diff options
Diffstat (limited to 'sx.el')
-rw-r--r-- | sx.el | 93 |
1 files changed, 74 insertions, 19 deletions
@@ -1,8 +1,12 @@ -;;; sx.el --- core functions -*- lexical-binding: t; -*- +;;; sx.el --- Core functions of the sx package. -*- lexical-binding: t; -*- ;; Copyright (C) 2014 Sean Allred ;; Author: Sean Allred <code@seanallred.com> +;; URL: https://github.com/vermiculus/stack-mode/ +;; Version: 0.1 +;; Keywords: help, hypermedia, tools +;; Package-Requires: ((emacs "24.1") (cl-lib "0.5") (json "1.3") (markdown-mode "2.0")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -24,11 +28,41 @@ ;;; Code: +(defconst sx-version "0.1" "Version of the `sx' package.") + + +;;; User commands +(defun sx-version () + "Print and return the version of the `sx' package." + (interactive) + (message "%s: %s" 'sx-version sx-version) + sx-version) + +;;;###autoload +(defun sx-bug-report () + "File a bug report about the `sx' package." + (interactive) + (browse-url "https://github.com/vermiculus/stack-mode/issues/new")) + ;;; Utility Functions +(defmacro sx-sorted-insert-skip-first (newelt list &optional predicate) + "Inserted NEWELT into LIST sorted by PREDICATE. +This is designed for the (site id id ...) lists. So the first car +is intentionally skipped." + `(let ((tail ,list) + (x ,newelt)) + (while (and ;; We're not at the end. + (cdr-safe tail) + ;; We're not at the right place. + (,(or predicate #'<) x (cadr tail))) + (setq tail (cdr tail))) + (setcdr tail (cons x (cdr tail))))) + (defun sx-message (format-string &rest args) - "Display a message" + "Display FORMAT-STRING as a message with ARGS. +See `format'." (message "[stack] %s" (apply #'format format-string args))) (defun sx-message-help-echo () @@ -37,8 +71,11 @@ (when echo (message "%s" echo)))) (defun sx--thing-as-string (thing &optional sequence-sep) - "Return a string representation of THING. If THING is already -a string, just return it." + "Return a string representation of THING. +If THING is already a string, just return it. + +Optional argument SEQUENCE-SEP is the separator applied between +elements of a sequence." (cond ((stringp thing) thing) ((symbolp thing) (symbol-name thing)) @@ -48,7 +85,24 @@ a string, just return it." thing (if sequence-sep sequence-sep ";"))))) (defun sx--filter-data (data desired-tree) - "Filters DATA and returns the DESIRED-TREE" + "Filter DATA and return the DESIRED-TREE. + +For example: + + (sx--filter-data + '((prop1 . value1) + (prop2 . value2) + (prop3 + (test1 . 1) + (test2 . 2)) + (prop4 . t)) + '(prop1 (prop3 test2))) + +would yield + + ((prop1 . value1) + (prop3 + (test2 . 2)))" (if (vectorp data) (apply #'vector (mapcar (lambda (entry) @@ -58,7 +112,7 @@ a string, just return it." (delq nil (mapcar (lambda (cons-cell) - ;; TODO the resolution of `f' is O(2n) in the worst + ;; @TODO the resolution of `f' is O(2n) in the worst ;; case. It may be faster to implement the same ;; functionality as a `while' loop to stop looking the ;; list once it has found a match. Do speed tests. @@ -78,7 +132,7 @@ a string, just return it." ;;; Interpreting request data (defun sx--deep-dot-search (data) "Find symbols somewhere inside DATA which start with a `.'. -Returns a list where each element is a cons cell. The car is the +Returns a list where each element is a cons cell. The car is the symbol, the cdr is the symbol without the `.'." (cond ((symbolp data) @@ -93,13 +147,13 @@ symbol, the cdr is the symbol without the `.'." (remove nil (mapcar #'sx--deep-dot-search data)))))) (defmacro sx-assoc-let (alist &rest body) - "Execute BODY while let-binding dotted symbols to their values in ALIST. -Dotted symbol is any symbol starting with a `.'. Only those + "Use dotted symbols let-bound to their values in ALIST and execute BODY. +Dotted symbol is any symbol starting with a `.'. Only those present in BODY are letbound, which leads to optimal performance. -For instance the following code +For instance, the following code - (stack-core-with-data alist + (sx-assoc-let alist (list .title .body)) is equivalent to @@ -116,19 +170,19 @@ is equivalent to (defcustom sx-init-hook nil "Hook run when stack-mode initializes. - -Run after `sx-init--internal-hook'.") +Run after `sx-init--internal-hook'." + :group 'sx + :type 'hook) (defvar sx-init--internal-hook nil "Hook run when stack-mode initializes. - This is used internally to set initial values for variables such as filters.") -(defun sx--< (property x y &optional pred) - "Non-nil if PROPERTY attribute of question X is less than that of Y. -With optional argument predicate, use it instead of `<'." - (funcall (or pred #'<) +(defun sx--< (property x y &optional predicate) + "Non-nil if PROPERTY attribute of alist X is less than that of Y. +With optional argument PREDICATE, use it instead of `<'." + (funcall (or predicate #'<) (cdr (assoc property x)) (cdr (assoc property y)))) @@ -143,13 +197,14 @@ SETTER should be a function of two arguments. If SETTER is nil, (,(or setter #'setq) ,variable ,value)))) nil) -(defvar sx-initialized nil +(defvar sx-initialized nil "Nil if sx hasn't been initialized yet. If it has, holds the time at which initialization happened.") (defun sx-initialize (&optional force) "Run initialization hooks if they haven't been run yet. These are `sx-init--internal-hook' and `sx-init-hook'. + If FORCE is non-nil, run them even if they've already been run." (when (or force (not sx-initialized)) (prog1 |