diff --git a/.gitignore b/.gitignore index 86953b8..7de9718 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,11 @@ !/elpa/diminish-20* !/elpa/bind-key-20* !/elpa/use-package-20* +!/elpa/dash-20* +!/elpa/hydra-20* +!/elpa/page-break-lines-20* +!/elpa/multiple-cursors-20* +!/elpa/exec-path-from-shell-20* /emms/ /eshell/history /eshell/lastdir diff --git a/elpa/dash-20170810.137/dash-autoloads.el b/elpa/dash-20170810.137/dash-autoloads.el new file mode 100644 index 0000000..6ffe377 --- /dev/null +++ b/elpa/dash-20170810.137/dash-autoloads.el @@ -0,0 +1,15 @@ +;;; dash-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil nil ("dash.el") (22942 51308 152174 503000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; dash-autoloads.el ends here diff --git a/elpa/dash-20170810.137/dash-pkg.el b/elpa/dash-20170810.137/dash-pkg.el new file mode 100644 index 0000000..a25f7a5 --- /dev/null +++ b/elpa/dash-20170810.137/dash-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "dash" "20170810.137" "A modern list library for Emacs" 'nil :commit "0df0ff1a65d54377381e50c08d88b247db44c3dd" :keywords '("lists")) diff --git a/elpa/dash-20170810.137/dash.el b/elpa/dash-20170810.137/dash.el new file mode 100644 index 0000000..02b04b7 --- /dev/null +++ b/elpa/dash-20170810.137/dash.el @@ -0,0 +1,2664 @@ +;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2016 Free Software Foundation, Inc. + +;; Author: Magnar Sveen +;; Version: 2.13.0 +;; Package-Version: 20170810.137 +;; Keywords: lists + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; A modern list api for Emacs. +;; +;; See documentation on https://github.com/magnars/dash.el#functions +;; +;; **Please note** The lexical binding in this file is not utilised at the +;; moment. We will take full advantage of lexical binding in an upcoming 3.0 +;; release of Dash. In the meantime, we've added the pragma to avoid a bug that +;; you can read more about in https://github.com/magnars/dash.el/issues/130. +;; + +;;; Code: + +(defgroup dash () + "Customize group for dash.el" + :group 'lisp + :prefix "dash-") + +(defun dash--enable-fontlock (symbol value) + (when value + (dash-enable-font-lock)) + (set-default symbol value)) + +(defcustom dash-enable-fontlock nil + "If non-nil, enable fontification of dash functions, macros and +special values." + :type 'boolean + :set 'dash--enable-fontlock + :group 'dash) + +(defmacro !cons (car cdr) + "Destructive: Set CDR to the cons of CAR and CDR." + `(setq ,cdr (cons ,car ,cdr))) + +(defmacro !cdr (list) + "Destructive: Set LIST to the cdr of LIST." + `(setq ,list (cdr ,list))) + +(defmacro --each (list &rest body) + "Anaphoric form of `-each'." + (declare (debug (form body)) + (indent 1)) + (let ((l (make-symbol "list"))) + `(let ((,l ,list) + (it-index 0)) + (while ,l + (let ((it (car ,l))) + ,@body) + (setq it-index (1+ it-index)) + (!cdr ,l))))) + +(defmacro -doto (eval-initial-value &rest forms) + "Eval a form, then insert that form as the 2nd argument to other forms. +The EVAL-INITIAL-VALUE form is evaluated once. Its result is +passed to FORMS, which are then evaluated sequentially. Returns +the target form." + (declare (indent 1)) + (let ((retval (make-symbol "value"))) + `(let ((,retval ,eval-initial-value)) + ,@(mapcar (lambda (form) + (if (sequencep form) + `(,(-first-item form) ,retval ,@(cdr form)) + `(funcall form ,retval))) + forms) + ,retval))) + +(defun -each (list fn) + "Call FN with every item in LIST. Return nil, used for side-effects only." + (--each list (funcall fn it))) + +(put '-each 'lisp-indent-function 1) + +(defalias '--each-indexed '--each) + +(defun -each-indexed (list fn) + "Call (FN index item) for each item in LIST. + +In the anaphoric form `--each-indexed', the index is exposed as symbol `it-index'. + +See also: `-map-indexed'." + (--each list (funcall fn it-index it))) +(put '-each-indexed 'lisp-indent-function 1) + +(defmacro --each-while (list pred &rest body) + "Anaphoric form of `-each-while'." + (declare (debug (form form body)) + (indent 2)) + (let ((l (make-symbol "list")) + (c (make-symbol "continue"))) + `(let ((,l ,list) + (,c t) + (it-index 0)) + (while (and ,l ,c) + (let ((it (car ,l))) + (if (not ,pred) (setq ,c nil) ,@body)) + (setq it-index (1+ it-index)) + (!cdr ,l))))) + +(defun -each-while (list pred fn) + "Call FN with every item in LIST while (PRED item) is non-nil. +Return nil, used for side-effects only." + (--each-while list (funcall pred it) (funcall fn it))) + +(put '-each-while 'lisp-indent-function 2) + +(defmacro --dotimes (num &rest body) + "Repeatedly executes BODY (presumably for side-effects) with symbol `it' bound to integers from 0 through NUM-1." + (declare (debug (form body)) + (indent 1)) + (let ((n (make-symbol "num"))) + `(let ((,n ,num) + (it 0)) + (while (< it ,n) + ,@body + (setq it (1+ it)))))) + +(defun -dotimes (num fn) + "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through NUM-1." + (--dotimes num (funcall fn it))) + +(put '-dotimes 'lisp-indent-function 1) + +(defun -map (fn list) + "Return a new list consisting of the result of applying FN to the items in LIST." + (mapcar fn list)) + +(defmacro --map (form list) + "Anaphoric form of `-map'." + (declare (debug (form form))) + `(mapcar (lambda (it) ,form) ,list)) + +(defmacro --reduce-from (form initial-value list) + "Anaphoric form of `-reduce-from'." + (declare (debug (form form form))) + `(let ((acc ,initial-value)) + (--each ,list (setq acc ,form)) + acc)) + +(defun -reduce-from (fn initial-value list) + "Return the result of applying FN to INITIAL-VALUE and the +first item in LIST, then applying FN to that result and the 2nd +item, etc. If LIST contains no items, return INITIAL-VALUE and +FN is not called. + +In the anaphoric form `--reduce-from', the accumulated value is +exposed as symbol `acc'. + +See also: `-reduce', `-reduce-r'" + (--reduce-from (funcall fn acc it) initial-value list)) + +(defmacro --reduce (form list) + "Anaphoric form of `-reduce'." + (declare (debug (form form))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv ,list)) + (if ,lv + (--reduce-from ,form (car ,lv) (cdr ,lv)) + (let (acc it) ,form))))) + +(defun -reduce (fn list) + "Return the result of applying FN to the first 2 items in LIST, +then applying FN to that result and the 3rd item, etc. If LIST +contains no items, FN must accept no arguments as well, and +reduce return the result of calling FN with no arguments. If +LIST has only 1 item, it is returned and FN is not called. + +In the anaphoric form `--reduce', the accumulated value is +exposed as symbol `acc'. + +See also: `-reduce-from', `-reduce-r'" + (if list + (-reduce-from fn (car list) (cdr list)) + (funcall fn))) + +(defun -reduce-r-from (fn initial-value list) + "Replace conses with FN, nil with INITIAL-VALUE and evaluate +the resulting expression. If LIST is empty, INITIAL-VALUE is +returned and FN is not called. + +Note: this function works the same as `-reduce-from' but the +operation associates from right instead of from left. + +See also: `-reduce-r', `-reduce'" + (if (not list) initial-value + (funcall fn (car list) (-reduce-r-from fn initial-value (cdr list))))) + +(defmacro --reduce-r-from (form initial-value list) + "Anaphoric version of `-reduce-r-from'." + (declare (debug (form form form))) + `(-reduce-r-from (lambda (&optional it acc) ,form) ,initial-value ,list)) + +(defun -reduce-r (fn list) + "Replace conses with FN and evaluate the resulting expression. +The final nil is ignored. If LIST contains no items, FN must +accept no arguments as well, and reduce return the result of +calling FN with no arguments. If LIST has only 1 item, it is +returned and FN is not called. + +The first argument of FN is the new item, the second is the +accumulated value. + +Note: this function works the same as `-reduce' but the operation +associates from right instead of from left. + +See also: `-reduce-r-from', `-reduce'" + (cond + ((not list) (funcall fn)) + ((not (cdr list)) (car list)) + (t (funcall fn (car list) (-reduce-r fn (cdr list)))))) + +(defmacro --reduce-r (form list) + "Anaphoric version of `-reduce-r'." + (declare (debug (form form))) + `(-reduce-r (lambda (&optional it acc) ,form) ,list)) + +(defmacro --filter (form list) + "Anaphoric form of `-filter'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list (when ,form (!cons it ,r))) + (nreverse ,r)))) + +(defun -filter (pred list) + "Return a new list of the items in LIST for which PRED returns a non-nil value. + +Alias: `-select' + +See also: `-keep'" + (--filter (funcall pred it) list)) + +(defalias '-select '-filter) +(defalias '--select '--filter) + +(defmacro --remove (form list) + "Anaphoric form of `-remove'." + (declare (debug (form form))) + `(--filter (not ,form) ,list)) + +(defun -remove (pred list) + "Return a new list of the items in LIST for which PRED returns nil. + +Alias: `-reject'" + (--remove (funcall pred it) list)) + +(defalias '-reject '-remove) +(defalias '--reject '--remove) + +(defun -remove-first (pred list) + "Return a new list with the first item matching PRED removed. + +Alias: `-reject-first' + +See also: `-remove', `-map-first'" + (let (front) + (while (and list (not (funcall pred (car list)))) + (push (car list) front) + (!cdr list)) + (if list + (-concat (nreverse front) (cdr list)) + (nreverse front)))) + +(defmacro --remove-first (form list) + "Anaphoric form of `-remove-first'." + (declare (debug (form form))) + `(-remove-first (lambda (it) ,form) ,list)) + +(defalias '-reject-first '-remove-first) +(defalias '--reject-first '--remove-first) + +(defun -remove-last (pred list) + "Return a new list with the last item matching PRED removed. + +Alias: `-reject-last' + +See also: `-remove', `-map-last'" + (nreverse (-remove-first pred (reverse list)))) + +(defmacro --remove-last (form list) + "Anaphoric form of `-remove-last'." + (declare (debug (form form))) + `(-remove-last (lambda (it) ,form) ,list)) + +(defalias '-reject-last '-remove-last) +(defalias '--reject-last '--remove-last) + +(defun -remove-item (item list) + "Remove all occurences of ITEM from LIST. + +Comparison is done with `equal'." + (declare (pure t) (side-effect-free t)) + (--remove (equal it item) list)) + +(defmacro --keep (form list) + "Anaphoric form of `-keep'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (m (make-symbol "mapped"))) + `(let (,r) + (--each ,list (let ((,m ,form)) (when ,m (!cons ,m ,r)))) + (nreverse ,r)))) + +(defun -keep (fn list) + "Return a new list of the non-nil results of applying FN to the items in LIST. + +If you want to select the original items satisfying a predicate use `-filter'." + (--keep (funcall fn it) list)) + +(defun -non-nil (list) + "Return all non-nil elements of LIST." + (declare (pure t) (side-effect-free t)) + (-remove 'null list)) + +(defmacro --map-indexed (form list) + "Anaphoric form of `-map-indexed'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list + (!cons ,form ,r)) + (nreverse ,r)))) + +(defun -map-indexed (fn list) + "Return a new list consisting of the result of (FN index item) for each item in LIST. + +In the anaphoric form `--map-indexed', the index is exposed as symbol `it-index'. + +See also: `-each-indexed'." + (--map-indexed (funcall fn it-index it) list)) + +(defmacro --map-when (pred rep list) + "Anaphoric form of `-map-when'." + (declare (debug (form form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list (!cons (if ,pred ,rep it) ,r)) + (nreverse ,r)))) + +(defun -map-when (pred rep list) + "Return a new list where the elements in LIST that do not match the PRED function +are unchanged, and where the elements in LIST that do match the PRED function are mapped +through the REP function. + +Alias: `-replace-where' + +See also: `-update-at'" + (--map-when (funcall pred it) (funcall rep it) list)) + +(defalias '-replace-where '-map-when) +(defalias '--replace-where '--map-when) + +(defun -map-first (pred rep list) + "Replace first item in LIST satisfying PRED with result of REP called on this item. + +See also: `-map-when', `-replace-first'" + (let (front) + (while (and list (not (funcall pred (car list)))) + (push (car list) front) + (!cdr list)) + (if list + (-concat (nreverse front) (cons (funcall rep (car list)) (cdr list))) + (nreverse front)))) + +(defmacro --map-first (pred rep list) + "Anaphoric form of `-map-first'." + `(-map-first (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list)) + +(defun -map-last (pred rep list) + "Replace last item in LIST satisfying PRED with result of REP called on this item. + +See also: `-map-when', `-replace-last'" + (nreverse (-map-first pred rep (reverse list)))) + +(defmacro --map-last (pred rep list) + "Anaphoric form of `-map-last'." + `(-map-last (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list)) + +(defun -replace (old new list) + "Replace all OLD items in LIST with NEW. + +Elements are compared using `equal'. + +See also: `-replace-at'" + (declare (pure t) (side-effect-free t)) + (--map-when (equal it old) new list)) + +(defun -replace-first (old new list) + "Replace the first occurence of OLD with NEW in LIST. + +Elements are compared using `equal'. + +See also: `-map-first'" + (declare (pure t) (side-effect-free t)) + (--map-first (equal old it) new list)) + +(defun -replace-last (old new list) + "Replace the last occurence of OLD with NEW in LIST. + +Elements are compared using `equal'. + +See also: `-map-last'" + (declare (pure t) (side-effect-free t)) + (--map-last (equal old it) new list)) + +(defmacro --mapcat (form list) + "Anaphoric form of `-mapcat'." + (declare (debug (form form))) + `(apply 'append (--map ,form ,list))) + +(defun -mapcat (fn list) + "Return the concatenation of the result of mapping FN over LIST. +Thus function FN should return a list." + (--mapcat (funcall fn it) list)) + +(defun -flatten (l) + "Take a nested list L and return its contents as a single, flat list. + +Note that because `nil' represents a list of zero elements (an +empty list), any mention of nil in L will disappear after +flattening. If you need to preserve nils, consider `-flatten-n' +or map them to some unique symbol and then map them back. + +Conses of two atoms are considered \"terminals\", that is, they +aren't flattened further. + +See also: `-flatten-n'" + (declare (pure t) (side-effect-free t)) + (if (and (listp l) (listp (cdr l))) + (-mapcat '-flatten l) + (list l))) + +(defmacro --iterate (form init n) + "Anaphoric version of `-iterate'." + (declare (debug (form form form))) + `(-iterate (lambda (it) ,form) ,init ,n)) + +(defun -flatten-n (num list) + "Flatten NUM levels of a nested LIST. + +See also: `-flatten'" + (declare (pure t) (side-effect-free t)) + (-last-item (--iterate (--mapcat (-list it) it) list (1+ num)))) + +(defun -concat (&rest lists) + "Return a new list with the concatenation of the elements in the supplied LISTS." + (declare (pure t) (side-effect-free t)) + (apply 'append lists)) + +(defalias '-copy 'copy-sequence + "Create a shallow copy of LIST. + +\(fn LIST)") + +(defun -splice (pred fun list) + "Splice lists generated by FUN in place of elements matching PRED in LIST. + +FUN takes the element matching PRED as input. + +This function can be used as replacement for `,@' in case you +need to splice several lists at marked positions (for example +with keywords). + +See also: `-splice-list', `-insert-at'" + (let (r) + (--each list + (if (funcall pred it) + (let ((new (funcall fun it))) + (--each new (!cons it r))) + (!cons it r))) + (nreverse r))) + +(defmacro --splice (pred form list) + "Anaphoric form of `-splice'." + `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list)) + +(defun -splice-list (pred new-list list) + "Splice NEW-LIST in place of elements matching PRED in LIST. + +See also: `-splice', `-insert-at'" + (-splice pred (lambda (_) new-list) list)) + +(defmacro --splice-list (pred new-list list) + "Anaphoric form of `-splice-list'." + `(-splice-list (lambda (it) ,pred) ,new-list ,list)) + +(defun -cons* (&rest args) + "Make a new list from the elements of ARGS. + +The last 2 members of ARGS are used as the final cons of the +result so if the final member of ARGS is not a list the result is +a dotted list." + (declare (pure t) (side-effect-free t)) + (-reduce-r 'cons args)) + +(defun -snoc (list elem &rest elements) + "Append ELEM to the end of the list. + +This is like `cons', but operates on the end of list. + +If ELEMENTS is non nil, append these to the list as well." + (-concat list (list elem) elements)) + +(defmacro --first (form list) + "Anaphoric form of `-first'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (not ,n) + (when ,form (setq ,n it))) + ,n))) + +(defun -first (pred list) + "Return the first x in LIST where (PRED x) is non-nil, else nil. + +To get the first item in the list no questions asked, use `car'. + +Alias: `-find'" + (--first (funcall pred it) list)) + +(defalias '-find '-first) +(defalias '--find '--first) + +(defmacro --some (form list) + "Anaphoric form of `-some'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (not ,n) + (setq ,n ,form)) + ,n))) + +(defun -some (pred list) + "Return (PRED x) for the first LIST item where (PRED x) is non-nil, else nil. + +Alias: `-any'" + (--some (funcall pred it) list)) + +(defalias '-any '-some) +(defalias '--any '--some) + +(defmacro --last (form list) + "Anaphoric form of `-last'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each ,list + (when ,form (setq ,n it))) + ,n))) + +(defun -last (pred list) + "Return the last x in LIST where (PRED x) is non-nil, else nil." + (--last (funcall pred it) list)) + +(defalias '-first-item 'car + "Return the first item of LIST, or nil on an empty list. + +\(fn LIST)") + +;; Ensure that calls to `-first-item' are compiled to a single opcode, +;; just like `car'. +(put '-first-item 'byte-opcode 'byte-car) +(put '-first-item 'byte-compile 'byte-compile-one-arg) + +;; TODO: emacs23 support, when dropped remove the condition +(eval-when-compile + (require 'cl) + (if (fboundp 'gv-define-simple-setter) + (gv-define-simple-setter -first-item setcar) + (require 'cl) + (with-no-warnings + (defsetf -first-item (x) (val) `(setcar ,x ,val))))) + +(defun -last-item (list) + "Return the last item of LIST, or nil on an empty list." + (declare (pure t) (side-effect-free t)) + (car (last list))) + +;; TODO: emacs23 support, when dropped remove the condition +(eval-when-compile + (if (fboundp 'gv-define-setter) + (gv-define-setter -last-item (val x) `(setcar (last ,x) ,val)) + (with-no-warnings + (defsetf -last-item (x) (val) `(setcar (last ,x) ,val))))) + +(defun -butlast (list) + "Return a list of all items in list except for the last." + ;; no alias as we don't want magic optional argument + (declare (pure t) (side-effect-free t)) + (butlast list)) + +(defmacro --count (pred list) + "Anaphoric form of `-count'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let ((,r 0)) + (--each ,list (when ,pred (setq ,r (1+ ,r)))) + ,r))) + +(defun -count (pred list) + "Counts the number of items in LIST where (PRED item) is non-nil." + (--count (funcall pred it) list)) + +(defun ---truthy? (val) + (declare (pure t) (side-effect-free t)) + (not (null val))) + +(defmacro --any? (form list) + "Anaphoric form of `-any?'." + (declare (debug (form form))) + `(---truthy? (--first ,form ,list))) + +(defun -any? (pred list) + "Return t if (PRED x) is non-nil for any x in LIST, else nil. + +Alias: `-any-p', `-some?', `-some-p'" + (--any? (funcall pred it) list)) + +(defalias '-some? '-any?) +(defalias '--some? '--any?) +(defalias '-any-p '-any?) +(defalias '--any-p '--any?) +(defalias '-some-p '-any?) +(defalias '--some-p '--any?) + +(defmacro --all? (form list) + "Anaphoric form of `-all?'." + (declare (debug (form form))) + (let ((a (make-symbol "all"))) + `(let ((,a t)) + (--each-while ,list ,a (setq ,a ,form)) + (---truthy? ,a)))) + +(defun -all? (pred list) + "Return t if (PRED x) is non-nil for all x in LIST, else nil. + +Alias: `-all-p', `-every?', `-every-p'" + (--all? (funcall pred it) list)) + +(defalias '-every? '-all?) +(defalias '--every? '--all?) +(defalias '-all-p '-all?) +(defalias '--all-p '--all?) +(defalias '-every-p '-all?) +(defalias '--every-p '--all?) + +(defmacro --none? (form list) + "Anaphoric form of `-none?'." + (declare (debug (form form))) + `(--all? (not ,form) ,list)) + +(defun -none? (pred list) + "Return t if (PRED x) is nil for all x in LIST, else nil. + +Alias: `-none-p'" + (--none? (funcall pred it) list)) + +(defalias '-none-p '-none?) +(defalias '--none-p '--none?) + +(defmacro --only-some? (form list) + "Anaphoric form of `-only-some?'." + (declare (debug (form form))) + (let ((y (make-symbol "yes")) + (n (make-symbol "no"))) + `(let (,y ,n) + (--each-while ,list (not (and ,y ,n)) + (if ,form (setq ,y t) (setq ,n t))) + (---truthy? (and ,y ,n))))) + +(defun -only-some? (pred list) + "Return `t` if at least one item of LIST matches PRED and at least one item of LIST does not match PRED. +Return `nil` both if all items match the predicate or if none of the items match the predicate. + +Alias: `-only-some-p'" + (--only-some? (funcall pred it) list)) + +(defalias '-only-some-p '-only-some?) +(defalias '--only-some-p '--only-some?) + +(defun -slice (list from &optional to step) + "Return copy of LIST, starting from index FROM to index TO. + +FROM or TO may be negative. These values are then interpreted +modulo the length of the list. + +If STEP is a number, only each STEPth item in the resulting +section is returned. Defaults to 1." + (declare (pure t) (side-effect-free t)) + (let ((length (length list)) + (new-list nil)) + ;; to defaults to the end of the list + (setq to (or to length)) + (setq step (or step 1)) + ;; handle negative indices + (when (< from 0) + (setq from (mod from length))) + (when (< to 0) + (setq to (mod to length))) + + ;; iterate through the list, keeping the elements we want + (--each-while list (< it-index to) + (when (and (>= it-index from) + (= (mod (- from it-index) step) 0)) + (push it new-list))) + (nreverse new-list))) + +(defun -take (n list) + "Return a new list of the first N items in LIST, or all items if there are fewer than N. + +See also: `-take-last'" + (declare (pure t) (side-effect-free t)) + (let (result) + (--dotimes n + (when list + (!cons (car list) result) + (!cdr list))) + (nreverse result))) + +(defun -take-last (n list) + "Return the last N items of LIST in order. + +See also: `-take'" + (declare (pure t) (side-effect-free t)) + (copy-sequence (last list n))) + +(defalias '-drop 'nthcdr + "Return the tail of LIST without the first N items. + +See also: `-drop-last' + +\(fn N LIST)") + +(defun -drop-last (n list) + "Remove the last N items of LIST and return a copy. + +See also: `-drop'" + ;; No alias because we don't want magic optional argument + (declare (pure t) (side-effect-free t)) + (butlast list n)) + +(defmacro --take-while (form list) + "Anaphoric form of `-take-while'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each-while ,list ,form (!cons it ,r)) + (nreverse ,r)))) + +(defun -take-while (pred list) + "Return a new list of successive items from LIST while (PRED item) returns a non-nil value." + (--take-while (funcall pred it) list)) + +(defmacro --drop-while (form list) + "Anaphoric form of `-drop-while'." + (declare (debug (form form))) + (let ((l (make-symbol "list"))) + `(let ((,l ,list)) + (while (and ,l (let ((it (car ,l))) ,form)) + (!cdr ,l)) + ,l))) + +(defun -drop-while (pred list) + "Return the tail of LIST starting from the first item for which (PRED item) returns nil." + (--drop-while (funcall pred it) list)) + +(defun -split-at (n list) + "Return a list of ((-take N LIST) (-drop N LIST)), in no more than one pass through the list." + (declare (pure t) (side-effect-free t)) + (let (result) + (--dotimes n + (when list + (!cons (car list) result) + (!cdr list))) + (list (nreverse result) list))) + +(defun -rotate (n list) + "Rotate LIST N places to the right. With N negative, rotate to the left. +The time complexity is O(n)." + (declare (pure t) (side-effect-free t)) + (if (> n 0) + (append (last list n) (butlast list n)) + (append (-drop (- n) list) (-take (- n) list)))) + +(defun -insert-at (n x list) + "Return a list with X inserted into LIST at position N. + +See also: `-splice', `-splice-list'" + (declare (pure t) (side-effect-free t)) + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons x (cadr split-list))))) + +(defun -replace-at (n x list) + "Return a list with element at Nth position in LIST replaced with X. + +See also: `-replace'" + (declare (pure t) (side-effect-free t)) + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons x (cdr (cadr split-list)))))) + +(defun -update-at (n func list) + "Return a list with element at Nth position in LIST replaced with `(func (nth n list))`. + +See also: `-map-when'" + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons (funcall func (car (cadr split-list))) (cdr (cadr split-list)))))) + +(defmacro --update-at (n form list) + "Anaphoric version of `-update-at'." + (declare (debug (form form form))) + `(-update-at ,n (lambda (it) ,form) ,list)) + +(defun -remove-at (n list) + "Return a list with element at Nth position in LIST removed. + +See also: `-remove-at-indices', `-remove'" + (declare (pure t) (side-effect-free t)) + (-remove-at-indices (list n) list)) + +(defun -remove-at-indices (indices list) + "Return a list whose elements are elements from LIST without +elements selected as `(nth i list)` for all i +from INDICES. + +See also: `-remove-at', `-remove'" + (declare (pure t) (side-effect-free t)) + (let* ((indices (-sort '< indices)) + (diffs (cons (car indices) (-map '1- (-zip-with '- (cdr indices) indices)))) + r) + (--each diffs + (let ((split (-split-at it list))) + (!cons (car split) r) + (setq list (cdr (cadr split))))) + (!cons list r) + (apply '-concat (nreverse r)))) + +(defmacro --split-with (pred list) + "Anaphoric form of `-split-with'." + (declare (debug (form form))) + (let ((l (make-symbol "list")) + (r (make-symbol "result")) + (c (make-symbol "continue"))) + `(let ((,l ,list) + (,r nil) + (,c t)) + (while (and ,l ,c) + (let ((it (car ,l))) + (if (not ,pred) + (setq ,c nil) + (!cons it ,r) + (!cdr ,l)))) + (list (nreverse ,r) ,l)))) + +(defun -split-with (pred list) + "Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list." + (--split-with (funcall pred it) list)) + +(defmacro -split-on (item list) + "Split the LIST each time ITEM is found. + +Unlike `-partition-by', the ITEM is discarded from the results. +Empty lists are also removed from the result. + +Comparison is done by `equal'. + +See also `-split-when'" + (declare (debug (form form))) + `(-split-when (lambda (it) (equal it ,item)) ,list)) + +(defmacro --split-when (form list) + "Anaphoric version of `-split-when'." + (declare (debug (form form))) + `(-split-when (lambda (it) ,form) ,list)) + +(defun -split-when (fn list) + "Split the LIST on each element where FN returns non-nil. + +Unlike `-partition-by', the \"matched\" element is discarded from +the results. Empty lists are also removed from the result. + +This function can be thought of as a generalization of +`split-string'." + (let (r s) + (while list + (if (not (funcall fn (car list))) + (push (car list) s) + (when s (push (nreverse s) r)) + (setq s nil)) + (!cdr list)) + (when s (push (nreverse s) r)) + (nreverse r))) + +(defmacro --separate (form list) + "Anaphoric form of `-separate'." + (declare (debug (form form))) + (let ((y (make-symbol "yes")) + (n (make-symbol "no"))) + `(let (,y ,n) + (--each ,list (if ,form (!cons it ,y) (!cons it ,n))) + (list (nreverse ,y) (nreverse ,n))))) + +(defun -separate (pred list) + "Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list." + (--separate (funcall pred it) list)) + +(defun ---partition-all-in-steps-reversed (n step list) + "Private: Used by -partition-all-in-steps and -partition-in-steps." + (when (< step 1) + (error "Step must be a positive number, or you're looking at some juicy infinite loops.")) + (let ((result nil)) + (while list + (!cons (-take n list) result) + (setq list (-drop step list))) + result)) + +(defun -partition-all-in-steps (n step list) + "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart. +The last groups may contain less than N items." + (declare (pure t) (side-effect-free t)) + (nreverse (---partition-all-in-steps-reversed n step list))) + +(defun -partition-in-steps (n step list) + "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart. +If there are not enough items to make the last group N-sized, +those items are discarded." + (declare (pure t) (side-effect-free t)) + (let ((result (---partition-all-in-steps-reversed n step list))) + (while (and result (< (length (car result)) n)) + (!cdr result)) + (nreverse result))) + +(defun -partition-all (n list) + "Return a new list with the items in LIST grouped into N-sized sublists. +The last group may contain less than N items." + (declare (pure t) (side-effect-free t)) + (-partition-all-in-steps n n list)) + +(defun -partition (n list) + "Return a new list with the items in LIST grouped into N-sized sublists. +If there are not enough items to make the last group N-sized, +those items are discarded." + (declare (pure t) (side-effect-free t)) + (-partition-in-steps n n list)) + +(defmacro --partition-by (form list) + "Anaphoric form of `-partition-by'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (s (make-symbol "sublist")) + (v (make-symbol "value")) + (n (make-symbol "new-value")) + (l (make-symbol "list"))) + `(let ((,l ,list)) + (when ,l + (let* ((,r nil) + (it (car ,l)) + (,s (list it)) + (,v ,form) + (,l (cdr ,l))) + (while ,l + (let* ((it (car ,l)) + (,n ,form)) + (unless (equal ,v ,n) + (!cons (nreverse ,s) ,r) + (setq ,s nil) + (setq ,v ,n)) + (!cons it ,s) + (!cdr ,l))) + (!cons (nreverse ,s) ,r) + (nreverse ,r)))))) + +(defun -partition-by (fn list) + "Apply FN to each item in LIST, splitting it each time FN returns a new value." + (--partition-by (funcall fn it) list)) + +(defmacro --partition-by-header (form list) + "Anaphoric form of `-partition-by-header'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (s (make-symbol "sublist")) + (h (make-symbol "header-value")) + (b (make-symbol "seen-body?")) + (n (make-symbol "new-value")) + (l (make-symbol "list"))) + `(let ((,l ,list)) + (when ,l + (let* ((,r nil) + (it (car ,l)) + (,s (list it)) + (,h ,form) + (,b nil) + (,l (cdr ,l))) + (while ,l + (let* ((it (car ,l)) + (,n ,form)) + (if (equal ,h ,n) + (when ,b + (!cons (nreverse ,s) ,r) + (setq ,s nil) + (setq ,b nil)) + (setq ,b t)) + (!cons it ,s) + (!cdr ,l))) + (!cons (nreverse ,s) ,r) + (nreverse ,r)))))) + +(defun -partition-by-header (fn list) + "Apply FN to the first item in LIST. That is the header +value. Apply FN to each item in LIST, splitting it each time FN +returns the header value, but only after seeing at least one +other value (the body)." + (--partition-by-header (funcall fn it) list)) + +(defun -partition-after-pred (pred list) + "Partition directly after each time PRED is true on an element of LIST." + (when list + (let ((rest (-partition-after-pred pred + (cdr list)))) + (if (funcall pred (car list)) + ;;split after (car list) + (cons (list (car list)) + rest) + + ;;don't split after (car list) + (cons (cons (car list) + (car rest)) + (cdr rest)))))) + +(defun -partition-before-pred (pred list) + "Partition directly before each time PRED is true on an element of LIST." + (nreverse (-map #'reverse + (-partition-after-pred pred (reverse list))))) + +(defun -partition-after-item (item list) + "Partition directly after each time ITEM appears in LIST." + (-partition-after-pred (lambda (ele) (equal ele item)) + list)) + +(defun -partition-before-item (item list) + "Partition directly before each time ITEM appears in LIST." + (-partition-before-pred (lambda (ele) (equal ele item)) + list)) + +(defmacro --group-by (form list) + "Anaphoric form of `-group-by'." + (declare (debug t)) + (let ((n (make-symbol "n")) + (k (make-symbol "k")) + (grp (make-symbol "grp"))) + `(nreverse + (-map + (lambda (,n) + (cons (car ,n) + (nreverse (cdr ,n)))) + (--reduce-from + (let* ((,k (,@form)) + (,grp (assoc ,k acc))) + (if ,grp + (setcdr ,grp (cons it (cdr ,grp))) + (push + (list ,k it) + acc)) + acc) + nil ,list))))) + +(defun -group-by (fn list) + "Separate LIST into an alist whose keys are FN applied to the +elements of LIST. Keys are compared by `equal'." + (--group-by (funcall fn it) list)) + +(defun -interpose (sep list) + "Return a new list of all elements in LIST separated by SEP." + (declare (pure t) (side-effect-free t)) + (let (result) + (when list + (!cons (car list) result) + (!cdr list)) + (while list + (setq result (cons (car list) (cons sep result))) + (!cdr list)) + (nreverse result))) + +(defun -interleave (&rest lists) + "Return a new list of the first item in each list, then the second etc." + (declare (pure t) (side-effect-free t)) + (let (result) + (while (-none? 'null lists) + (--each lists (!cons (car it) result)) + (setq lists (-map 'cdr lists))) + (nreverse result))) + +(defmacro --zip-with (form list1 list2) + "Anaphoric form of `-zip-with'. + +The elements in list1 are bound as symbol `it', the elements in list2 as symbol `other'." + (declare (debug (form form form))) + (let ((r (make-symbol "result")) + (l1 (make-symbol "list1")) + (l2 (make-symbol "list2"))) + `(let ((,r nil) + (,l1 ,list1) + (,l2 ,list2)) + (while (and ,l1 ,l2) + (let ((it (car ,l1)) + (other (car ,l2))) + (!cons ,form ,r) + (!cdr ,l1) + (!cdr ,l2))) + (nreverse ,r)))) + +(defun -zip-with (fn list1 list2) + "Zip the two lists LIST1 and LIST2 using a function FN. This +function is applied pairwise taking as first argument element of +LIST1 and as second argument element of LIST2 at corresponding +position. + +The anaphoric form `--zip-with' binds the elements from LIST1 as symbol `it', +and the elements from LIST2 as symbol `other'." + (--zip-with (funcall fn it other) list1 list2)) + +(defun -zip (&rest lists) + "Zip LISTS together. Group the head of each list, followed by the +second elements of each list, and so on. The lengths of the returned +groupings are equal to the length of the shortest input list. + +If two lists are provided as arguments, return the groupings as a list +of cons cells. Otherwise, return the groupings as a list of lists. + +Please note! This distinction is being removed in an upcoming 3.0 +release of Dash. If you rely on this behavior, use -zip-pair instead." + (declare (pure t) (side-effect-free t)) + (let (results) + (while (-none? 'null lists) + (setq results (cons (mapcar 'car lists) results)) + (setq lists (mapcar 'cdr lists))) + (setq results (nreverse results)) + (if (= (length lists) 2) + ;; to support backward compatability, return + ;; a cons cell if two lists were provided + (--map (cons (car it) (cadr it)) results) + results))) + +(defalias '-zip-pair '-zip) + +(defun -zip-fill (fill-value &rest lists) + "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The +lengths of the returned groupings are equal to the length of the +longest input list." + (declare (pure t) (side-effect-free t)) + (apply '-zip (apply '-pad (cons fill-value lists)))) + +(defun -unzip (lists) + "Unzip LISTS. + +This works just like `-zip' but takes a list of lists instead of +a variable number of arguments, such that + + (-unzip (-zip L1 L2 L3 ...)) + +is identity (given that the lists are the same length). + +See also: `-zip'" + (apply '-zip lists)) + +(defun -cycle (list) + "Return an infinite copy of LIST that will cycle through the +elements and repeat from the beginning." + (declare (pure t) (side-effect-free t)) + (let ((newlist (-map 'identity list))) + (nconc newlist newlist))) + +(defun -pad (fill-value &rest lists) + "Appends FILL-VALUE to the end of each list in LISTS such that they +will all have the same length." + (let* ((annotations (-annotate 'length lists)) + (n (-max (-map 'car annotations)))) + (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations))) + +(defun -annotate (fn list) + "Return a list of cons cells where each cell is FN applied to each +element of LIST paired with the unmodified element of LIST." + (-zip (-map fn list) list)) + +(defmacro --annotate (form list) + "Anaphoric version of `-annotate'." + (declare (debug (form form))) + `(-annotate (lambda (it) ,form) ,list)) + +(defun dash--table-carry (lists restore-lists &optional re) + "Helper for `-table' and `-table-flat'. + +If a list overflows, carry to the right and reset the list." + (while (not (or (car lists) + (equal lists '(nil)))) + (setcar lists (car restore-lists)) + (pop (cadr lists)) + (!cdr lists) + (!cdr restore-lists) + (when re + (push (nreverse (car re)) (cadr re)) + (setcar re nil) + (!cdr re)))) + +(defun -table (fn &rest lists) + "Compute outer product of LISTS using function FN. + +The function FN should have the same arity as the number of +supplied lists. + +The outer product is computed by applying fn to all possible +combinations created by taking one element from each list in +order. The dimension of the result is (length lists). + +See also: `-table-flat'" + (let ((restore-lists (copy-sequence lists)) + (last-list (last lists)) + (re (make-list (length lists) nil))) + (while (car last-list) + (let ((item (apply fn (-map 'car lists)))) + (push item (car re)) + (setcar lists (cdar lists)) ;; silence byte compiler + (dash--table-carry lists restore-lists re))) + (nreverse (car (last re))))) + +(defun -table-flat (fn &rest lists) + "Compute flat outer product of LISTS using function FN. + +The function FN should have the same arity as the number of +supplied lists. + +The outer product is computed by applying fn to all possible +combinations created by taking one element from each list in +order. The results are flattened, ignoring the tensor structure +of the result. This is equivalent to calling: + + (-flatten-n (1- (length lists)) (apply '-table fn lists)) + +but the implementation here is much more efficient. + +See also: `-flatten-n', `-table'" + (let ((restore-lists (copy-sequence lists)) + (last-list (last lists)) + re) + (while (car last-list) + (let ((item (apply fn (-map 'car lists)))) + (push item re) + (setcar lists (cdar lists)) ;; silence byte compiler + (dash--table-carry lists restore-lists))) + (nreverse re))) + +(defun -partial (fn &rest args) + "Take a function FN and fewer than the normal arguments to FN, +and return a fn that takes a variable number of additional ARGS. +When called, the returned function calls FN with ARGS first and +then additional args." + (apply 'apply-partially fn args)) + +(defun -elem-index (elem list) + "Return the index of the first element in the given LIST which +is equal to the query element ELEM, or nil if there is no +such element." + (declare (pure t) (side-effect-free t)) + (car (-elem-indices elem list))) + +(defun -elem-indices (elem list) + "Return the indices of all elements in LIST equal to the query +element ELEM, in ascending order." + (declare (pure t) (side-effect-free t)) + (-find-indices (-partial 'equal elem) list)) + +(defun -find-indices (pred list) + "Return the indices of all elements in LIST satisfying the +predicate PRED, in ascending order." + (apply 'append (--map-indexed (when (funcall pred it) (list it-index)) list))) + +(defmacro --find-indices (form list) + "Anaphoric version of `-find-indices'." + (declare (debug (form form))) + `(-find-indices (lambda (it) ,form) ,list)) + +(defun -find-index (pred list) + "Take a predicate PRED and a LIST and return the index of the +first element in the list satisfying the predicate, or nil if +there is no such element. + +See also `-first'." + (car (-find-indices pred list))) + +(defmacro --find-index (form list) + "Anaphoric version of `-find-index'." + (declare (debug (form form))) + `(-find-index (lambda (it) ,form) ,list)) + +(defun -find-last-index (pred list) + "Take a predicate PRED and a LIST and return the index of the +last element in the list satisfying the predicate, or nil if +there is no such element. + +See also `-last'." + (-last-item (-find-indices pred list))) + +(defmacro --find-last-index (form list) + "Anaphoric version of `-find-last-index'." + `(-find-last-index (lambda (it) ,form) ,list)) + +(defun -select-by-indices (indices list) + "Return a list whose elements are elements from LIST selected +as `(nth i list)` for all i from INDICES." + (declare (pure t) (side-effect-free t)) + (let (r) + (--each indices + (!cons (nth it list) r)) + (nreverse r))) + +(defun -select-columns (columns table) + "Select COLUMNS from TABLE. + +TABLE is a list of lists where each element represents one row. +It is assumed each row has the same length. + +Each row is transformed such that only the specified COLUMNS are +selected. + +See also: `-select-column', `-select-by-indices'" + (declare (pure t) (side-effect-free t)) + (--map (-select-by-indices columns it) table)) + +(defun -select-column (column table) + "Select COLUMN from TABLE. + +TABLE is a list of lists where each element represents one row. +It is assumed each row has the same length. + +The single selected column is returned as a list. + +See also: `-select-columns', `-select-by-indices'" + (declare (pure t) (side-effect-free t)) + (--mapcat (-select-by-indices (list column) it) table)) + +(defmacro -> (x &optional form &rest more) + "Thread the expr through the forms. Insert X as the second item +in the first form, making a list of it if it is not a list +already. If there are more forms, insert the first form as the +second item in second form, etc." + (declare (debug (form &rest [&or symbolp (sexp &rest form)]))) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,(car form) ,x ,@(cdr form)) + (list form x))) + (:else `(-> (-> ,x ,form) ,@more)))) + +(defmacro ->> (x &optional form &rest more) + "Thread the expr through the forms. Insert X as the last item +in the first form, making a list of it if it is not a list +already. If there are more forms, insert the first form as the +last item in second form, etc." + (declare (debug ->)) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,@form ,x) + (list form x))) + (:else `(->> (->> ,x ,form) ,@more)))) + +(defmacro --> (x &rest forms) + "Starting with the value of X, thread each expression through FORMS. + +Insert X at the position signified by the symbol `it' in the first +form. If there are more forms, insert the first form at the position +signified by `it' in in second form, etc." + (declare (debug (form body))) + `(-as-> ,x it ,@forms)) + +(defmacro -as-> (value variable &rest forms) + "Starting with VALUE, thread VARIABLE through FORMS. + +In the first form, bind VARIABLE to VALUE. In the second form, bind +VARIABLE to the result of the first form, and so forth." + (declare (debug (form symbolp body))) + (if (null forms) + `,value + `(let ((,variable ,value)) + (-as-> ,(if (symbolp (car forms)) + (list (car forms) variable) + (car forms)) + ,variable + ,@(cdr forms))))) + +(defmacro -some-> (x &optional form &rest more) + "When expr is non-nil, thread it through the first form (via `->'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some-> (-when-let (,result ,x) + (-> ,result ,form)) + ,@more)))) + +(defmacro -some->> (x &optional form &rest more) + "When expr is non-nil, thread it through the first form (via `->>'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some->> (-when-let (,result ,x) + (->> ,result ,form)) + ,@more)))) + +(defmacro -some--> (x &optional form &rest more) + "When expr in non-nil, thread it through the first form (via `-->'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some--> (-when-let (,result ,x) + (--> ,result ,form)) + ,@more)))) + +(defun -grade-up (comparator list) + "Grade elements of LIST using COMPARATOR relation, yielding a +permutation vector such that applying this permutation to LIST +sorts it in ascending order." + ;; ugly hack to "fix" lack of lexical scope + (let ((comp `(lambda (it other) (funcall ',comparator (car it) (car other))))) + (->> (--map-indexed (cons it it-index) list) + (-sort comp) + (-map 'cdr)))) + +(defun -grade-down (comparator list) + "Grade elements of LIST using COMPARATOR relation, yielding a +permutation vector such that applying this permutation to LIST +sorts it in descending order." + ;; ugly hack to "fix" lack of lexical scope + (let ((comp `(lambda (it other) (funcall ',comparator (car other) (car it))))) + (->> (--map-indexed (cons it it-index) list) + (-sort comp) + (-map 'cdr)))) + +(defvar dash--source-counter 0 + "Monotonic counter for generated symbols.") + +(defun dash--match-make-source-symbol () + "Generate a new dash-source symbol. + +All returned symbols are guaranteed to be unique." + (prog1 (make-symbol (format "--dash-source-%d--" dash--source-counter)) + (setq dash--source-counter (1+ dash--source-counter)))) + +(defun dash--match-ignore-place-p (symbol) + "Return non-nil if SYMBOL is a symbol and starts with _." + (and (symbolp symbol) + (eq (aref (symbol-name symbol) 0) ?_))) + +(defun dash--match-cons-skip-cdr (skip-cdr source) + "Helper function generating idiomatic shifting code." + (cond + ((= skip-cdr 0) + `(pop ,source)) + (t + `(prog1 ,(dash--match-cons-get-car skip-cdr source) + (setq ,source ,(dash--match-cons-get-cdr (1+ skip-cdr) source)))))) + +(defun dash--match-cons-get-car (skip-cdr source) + "Helper function generating idiomatic code to get nth car." + (cond + ((= skip-cdr 0) + `(car ,source)) + ((= skip-cdr 1) + `(cadr ,source)) + (t + `(nth ,skip-cdr ,source)))) + +(defun dash--match-cons-get-cdr (skip-cdr source) + "Helper function generating idiomatic code to get nth cdr." + (cond + ((= skip-cdr 0) + source) + ((= skip-cdr 1) + `(cdr ,source)) + (t + `(nthcdr ,skip-cdr ,source)))) + +(defun dash--match-cons (match-form source) + "Setup a cons matching environment and call the real matcher." + (let ((s (dash--match-make-source-symbol)) + (n 0) + (m match-form)) + (while (and (consp m) + (dash--match-ignore-place-p (car m))) + (setq n (1+ n)) (!cdr m)) + (cond + ;; when we only have one pattern in the list, we don't have to + ;; create a temporary binding (--dash-source--) for the source + ;; and just use the input directly + ((and (consp m) + (not (cdr m))) + (dash--match (car m) (dash--match-cons-get-car n source))) + ;; handle other special types + ((> n 0) + (dash--match m (dash--match-cons-get-cdr n source))) + ;; this is the only entry-point for dash--match-cons-1, that's + ;; why we can't simply use the above branch, it would produce + ;; infinite recursion + (t + (cons (list s source) (dash--match-cons-1 match-form s)))))) + +(defun dash--match-cons-1 (match-form source &optional props) + "Match MATCH-FORM against SOURCE. + +MATCH-FORM is a proper or improper list. Each element of +MATCH-FORM is either a symbol, which gets bound to the respective +value in source or another match form which gets destructured +recursively. + +If the cdr of last cons cell in the list is `nil', matching stops +there. + +SOURCE is a proper or improper list." + (let ((skip-cdr (or (plist-get props :skip-cdr) 0))) + (cond + ((consp match-form) + (cond + ((cdr match-form) + (cond + ((and (symbolp (car match-form)) + (memq (car match-form) '(&keys &plist &alist &hash))) + (dash--match-kv match-form (dash--match-cons-get-cdr skip-cdr source))) + ((dash--match-ignore-place-p (car match-form)) + (dash--match-cons-1 (cdr match-form) source + (plist-put props :skip-cdr (1+ skip-cdr)))) + (t + (-concat (dash--match (car match-form) (dash--match-cons-skip-cdr skip-cdr source)) + (dash--match-cons-1 (cdr match-form) source))))) + (t ;; Last matching place, no need for shift + (dash--match (car match-form) (dash--match-cons-get-car skip-cdr source))))) + ((eq match-form nil) + nil) + (t ;; Handle improper lists. Last matching place, no need for shift + (dash--match match-form (dash--match-cons-get-cdr skip-cdr source)))))) + +(defun dash--vector-tail (seq start) + "Return the tail of SEQ starting at START." + (cond + ((vectorp seq) + (let* ((re-length (- (length seq) start)) + (re (make-vector re-length 0))) + (--dotimes re-length (aset re it (aref seq (+ it start)))) + re)) + ((stringp seq) + (substring seq start)))) + +(defun dash--match-vector (match-form source) + "Setup a vector matching environment and call the real matcher." + (let ((s (dash--match-make-source-symbol))) + (cond + ;; don't bind `s' if we only have one sub-pattern + ((= (length match-form) 1) + (dash--match (aref match-form 0) `(aref ,source 0))) + ;; if the source is a symbol, we don't need to re-bind it + ((symbolp source) + (dash--match-vector-1 match-form source)) + ;; don't bind `s' if we only have one sub-pattern which is not ignored + ((let* ((ignored-places (mapcar 'dash--match-ignore-place-p match-form)) + (ignored-places-n (length (-remove 'null ignored-places)))) + (when (= ignored-places-n (1- (length match-form))) + (let ((n (-find-index 'null ignored-places))) + (dash--match (aref match-form n) `(aref ,source ,n)))))) + (t + (cons (list s source) (dash--match-vector-1 match-form s)))))) + +(defun dash--match-vector-1 (match-form source) + "Match MATCH-FORM against SOURCE. + +MATCH-FORM is a vector. Each element of MATCH-FORM is either a +symbol, which gets bound to the respective value in source or +another match form which gets destructured recursively. + +If second-from-last place in MATCH-FORM is the symbol &rest, the +next element of the MATCH-FORM is matched against the tail of +SOURCE, starting at index of the &rest symbol. This is +conceptually the same as the (head . tail) match for improper +lists, where dot plays the role of &rest. + +SOURCE is a vector. + +If the MATCH-FORM vector is shorter than SOURCE vector, only +the (length MATCH-FORM) places are bound, the rest of the SOURCE +is discarded." + (let ((i 0) + (l (length match-form)) + (re)) + (while (< i l) + (let ((m (aref match-form i))) + (push (cond + ((and (symbolp m) + (eq m '&rest)) + (prog1 (dash--match + (aref match-form (1+ i)) + `(dash--vector-tail ,source ,i)) + (setq i l))) + ((and (symbolp m) + ;; do not match symbols starting with _ + (not (eq (aref (symbol-name m) 0) ?_))) + (list (list m `(aref ,source ,i)))) + ((not (symbolp m)) + (dash--match m `(aref ,source ,i)))) + re) + (setq i (1+ i)))) + (-flatten-n 1 (nreverse re)))) + +(defun dash--match-kv (match-form source) + "Setup a kv matching environment and call the real matcher. + +kv can be any key-value store, such as plist, alist or hash-table." + (let ((s (dash--match-make-source-symbol))) + (cond + ;; don't bind `s' if we only have one sub-pattern (&type key val) + ((= (length match-form) 3) + (dash--match-kv-1 (cdr match-form) source (car match-form))) + ;; if the source is a symbol, we don't need to re-bind it + ((symbolp source) + (dash--match-kv-1 (cdr match-form) source (car match-form))) + (t + (cons (list s source) (dash--match-kv-1 (cdr match-form) s (car match-form))))))) + +(defun dash--match-kv-1 (match-form source type) + "Match MATCH-FORM against SOURCE of type TYPE. + +MATCH-FORM is a proper list of the form (key1 place1 ... keyN +placeN). Each placeK is either a symbol, which gets bound to the +value of keyK retrieved from the key-value store, or another +match form which gets destructured recursively. + +SOURCE is a key-value store of type TYPE, which can be a plist, +an alist or a hash table. + +TYPE is a token specifying the type of the key-value store. +Valid values are &plist, &alist and &hash." + (-flatten-n 1 (-map + (lambda (kv) + (let* ((k (car kv)) + (v (cadr kv)) + (getter (cond + ((or (eq type '&plist) (eq type '&keys)) + `(plist-get ,source ,k)) + ((eq type '&alist) + `(cdr (assoc ,k ,source))) + ((eq type '&hash) + `(gethash ,k ,source))))) + (cond + ((symbolp v) + (list (list v getter))) + (t (dash--match v getter))))) + (-partition 2 match-form)))) + +(defun dash--match-symbol (match-form source) + "Bind a symbol. + +This works just like `let', there is no destructuring." + (list (list match-form source))) + +(defun dash--match (match-form source) + "Match MATCH-FORM against SOURCE. + +This function tests the MATCH-FORM and dispatches to specific +matchers based on the type of the expression. + +Key-value stores are disambiguated by placing a token &plist, +&alist or &hash as a first item in the MATCH-FORM." + (cond + ((symbolp match-form) + (dash--match-symbol match-form source)) + ((consp match-form) + (cond + ;; Handle the "x &as" bindings first. + ((and (consp (cdr match-form)) + (symbolp (car match-form)) + (eq '&as (cadr match-form))) + (let ((s (car match-form))) + (cons (list s source) + (dash--match (cddr match-form) s)))) + ((memq (car match-form) '(&keys &plist &alist &hash)) + (dash--match-kv match-form source)) + (t (dash--match-cons match-form source)))) + ((vectorp match-form) + ;; We support the &as binding in vectors too + (cond + ((and (> (length match-form) 2) + (symbolp (aref match-form 0)) + (eq '&as (aref match-form 1))) + (let ((s (aref match-form 0))) + (cons (list s source) + (dash--match (dash--vector-tail match-form 2) s)))) + (t (dash--match-vector match-form source)))))) + +(defmacro -let* (varlist &rest body) + "Bind variables according to VARLIST then eval BODY. + +VARLIST is a list of lists of the form (PATTERN SOURCE). Each +PATTERN is matched against the SOURCE structurally. SOURCE is +only evaluated once for each PATTERN. + +Each SOURCE can refer to the symbols already bound by this +VARLIST. This is useful if you want to destructure SOURCE +recursively but also want to name the intermediate structures. + +See `-let' for the list of all possible patterns." + (declare (debug ((&rest (sexp form)) body)) + (indent 1)) + (let ((bindings (--mapcat (dash--match (car it) (cadr it)) varlist))) + `(let* ,bindings + ,@body))) + +(defmacro -let (varlist &rest body) + "Bind variables according to VARLIST then eval BODY. + +VARLIST is a list of lists of the form (PATTERN SOURCE). Each +PATTERN is matched against the SOURCE \"structurally\". SOURCE +is only evaluated once for each PATTERN. Each PATTERN is matched +recursively, and can therefore contain sub-patterns which are +matched against corresponding sub-expressions of SOURCE. + +All the SOURCEs are evalled before any symbols are +bound (i.e. \"in parallel\"). + +If VARLIST only contains one (PATTERN SOURCE) element, you can +optionally specify it using a vector and discarding the +outer-most parens. Thus + + (-let ((PATTERN SOURCE)) ..) + +becomes + + (-let [PATTERN SOURCE] ..). + +`-let' uses a convention of not binding places (symbols) starting +with _ whenever it's possible. You can use this to skip over +entries you don't care about. However, this is not *always* +possible (as a result of implementation) and these symbols might +get bound to undefined values. + +Following is the overview of supported patterns. Remember that +patterns can be matched recursively, so every a, b, aK in the +following can be a matching construct and not necessarily a +symbol/variable. + +Symbol: + + a - bind the SOURCE to A. This is just like regular `let'. + +Conses and lists: + + (a) - bind `car' of cons/list to A + + (a . b) - bind car of cons to A and `cdr' to B + + (a b) - bind car of list to A and `cadr' to B + + (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3 ... + + (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST. + +Vectors: + + [a] - bind 0th element of a non-list sequence to A (works with + vectors, strings, bit arrays...) + + [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st to + A1, 2nd to A2, ... + If the PATTERN is shorter than SOURCE, the values at + places not in PATTERN are ignored. + If the PATTERN is longer than SOURCE, an `error' is + thrown. + + [a1 a2 a3 ... &rest rest] - as above, but bind the rest of + the sequence to REST. This is + conceptually the same as improper list + matching (a1 a2 ... aN . rest) + +Key/value stores: + + (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE plist to aK. If the + value is not found, aK is nil. + + (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE alist to aK. If the + value is not found, aK is nil. + + (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE hash table to aK. If the + value is not found, aK is nil. + +Further, special keyword &keys supports \"inline\" matching of +plist-like key-value pairs, similarly to &keys keyword of +`cl-defun'. + + (a1 a2 ... aN &keys key1 b1 ... keyN bK) + +This binds N values from the list to a1 ... aN, then interprets +the cdr as a plist (see key/value matching above). + +You can name the source using the syntax SYMBOL &as PATTERN. +This syntax works with lists (proper or improper), vectors and +all types of maps. + + (list &as a b c) (list 1 2 3) + +binds A to 1, B to 2, C to 3 and LIST to (1 2 3). + +Similarly: + + (bounds &as beg . end) (cons 1 2) + +binds BEG to 1, END to 2 and BOUNDS to (1 . 2). + + (items &as first . rest) (list 1 2 3) + +binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3) + + [vect &as _ b c] [1 2 3] + +binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as usual). + + (plist &as &plist :b b) (list :a 1 :b 2 :c 3) + +binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and &hash. + +This is especially useful when we want to capture the result of a +computation and destructure at the same time. Consider the +form (function-returning-complex-structure) returning a list of +two vectors with two items each. We want to capture this entire +result and pass it to another computation, but at the same time +we want to get the second item from each vector. We can achieve +it with pattern + + (result &as [_ a] [_ b]) (function-returning-complex-structure) + +Note: Clojure programmers may know this feature as the \":as +binding\". The difference is that we put the &as at the front +because we need to support improper list binding." + (declare (debug ([&or (&rest (sexp form)) + (vector [&rest [sexp form]])] + body)) + (indent 1)) + (if (vectorp varlist) + `(let* ,(dash--match (aref varlist 0) (aref varlist 1)) + ,@body) + (let* ((inputs (--map-indexed (list (make-symbol (format "input%d" it-index)) (cadr it)) varlist)) + (new-varlist (--map (list (caar it) (cadr it)) (-zip varlist inputs)))) + `(let ,inputs + (-let* ,new-varlist ,@body))))) + +(defmacro -lambda (match-form &rest body) + "Return a lambda which destructures its input as MATCH-FORM and executes BODY. + +Note that you have to enclose the MATCH-FORM in a pair of parens, +such that: + + (-lambda (x) body) + (-lambda (x y ...) body) + +has the usual semantics of `lambda'. Furthermore, these get +translated into normal lambda, so there is no performance +penalty. + +See `-let' for the description of destructuring mechanism." + (declare (doc-string 2) (indent defun) + (debug (&define sexp + [&optional stringp] + [&optional ("interactive" interactive)] + def-body))) + (cond + ((not (consp match-form)) + (signal 'wrong-type-argument "match-form must be a list")) + ;; no destructuring, so just return regular lambda to make things faster + ((-all? 'symbolp match-form) + `(lambda ,match-form ,@body)) + (t + (let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form))) + ;; TODO: because inputs to the lambda are evaluated only once, + ;; -let* need not to create the extra bindings to ensure that. + ;; We should find a way to optimize that. Not critical however. + `(lambda ,(--map (cadr it) inputs) + (-let* ,inputs ,@body)))))) + +(defmacro -if-let* (vars-vals then &rest else) + "If all VALS evaluate to true, bind them to their corresponding +VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list +of (VAR VAL) pairs. + +Note: binding is done according to `-let*'. VALS are evaluated +sequentially, and evaluation stops after the first nil VAL is +encountered." + (declare (debug ((&rest (sexp form)) form body)) + (indent 2)) + (->> vars-vals + (--mapcat (dash--match (car it) (cadr it))) + (--reduce-r-from + (let ((var (car it)) + (val (cadr it))) + `(let ((,var ,val)) + (if ,var ,acc ,@else))) + then))) + +(defmacro -if-let (var-val then &rest else) + "If VAL evaluates to non-nil, bind it to VAR and do THEN, +otherwise do ELSE. + +Note: binding is done according to `-let'. + +\(fn (VAR VAL) THEN &rest ELSE)" + (declare (debug ((sexp form) form body)) + (indent 2)) + `(-if-let* (,var-val) ,then ,@else)) + +(defmacro --if-let (val then &rest else) + "If VAL evaluates to non-nil, bind it to symbol `it' and do THEN, +otherwise do ELSE." + (declare (debug (form form body)) + (indent 2)) + `(-if-let (it ,val) ,then ,@else)) + +(defmacro -when-let* (vars-vals &rest body) + "If all VALS evaluate to true, bind them to their corresponding +VARS and execute body. VARS-VALS should be a list of (VAR VAL) +pairs. + +Note: binding is done according to `-let*'. VALS are evaluated +sequentially, and evaluation stops after the first nil VAL is +encountered." + (declare (debug ((&rest (sexp form)) body)) + (indent 1)) + `(-if-let* ,vars-vals (progn ,@body))) + +(defmacro -when-let (var-val &rest body) + "If VAL evaluates to non-nil, bind it to VAR and execute body. + +Note: binding is done according to `-let'. + +\(fn (VAR VAL) &rest BODY)" + (declare (debug ((sexp form) body)) + (indent 1)) + `(-if-let ,var-val (progn ,@body))) + +(defmacro --when-let (val &rest body) + "If VAL evaluates to non-nil, bind it to symbol `it' and +execute body." + (declare (debug (form body)) + (indent 1)) + `(--if-let ,val (progn ,@body))) + +(defvar -compare-fn nil + "Tests for equality use this function or `equal' if this is nil. +It should only be set using dynamic scope with a let, like: + + (let ((-compare-fn #'=)) (-union numbers1 numbers2 numbers3)") + +(defun -distinct (list) + "Return a new list with all duplicates removed. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil. + +Alias: `-uniq'" + (let (result) + (--each list (unless (-contains? result it) (!cons it result))) + (nreverse result))) + +(defalias '-uniq '-distinct) + +(defun -union (list list2) + "Return a new list containing the elements of LIST and elements of LIST2 that are not in LIST. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + ;; We fall back to iteration implementation if the comparison + ;; function isn't one of `eq', `eql' or `equal'. + (let* ((result (reverse list)) + ;; TODO: get rid of this dynamic variable, pass it as an + ;; argument instead. + (-compare-fn (if (bound-and-true-p -compare-fn) + -compare-fn + 'equal))) + (if (memq -compare-fn '(eq eql equal)) + (let ((ht (make-hash-table :test -compare-fn))) + (--each list (puthash it t ht)) + (--each list2 (unless (gethash it ht) (!cons it result)))) + (--each list2 (unless (-contains? result it) (!cons it result)))) + (nreverse result))) + +(defun -intersection (list list2) + "Return a new list containing only the elements that are members of both LIST and LIST2. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + (--filter (-contains? list2 it) list)) + +(defun -difference (list list2) + "Return a new list with only the members of LIST that are not in LIST2. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + (--filter (not (-contains? list2 it)) list)) + +(defun -powerset (list) + "Return the power set of LIST." + (if (null list) '(()) + (let ((last (-powerset (cdr list)))) + (append (mapcar (lambda (x) (cons (car list) x)) last) + last)))) + +(defun -permutations (list) + "Return the permutations of LIST." + (if (null list) '(()) + (apply #'append + (mapcar (lambda (x) + (mapcar (lambda (perm) (cons x perm)) + (-permutations (remove x list)))) + list)))) + +(defun -contains? (list element) + "Return non-nil if LIST contains ELEMENT. + +The test for equality is done with `equal', or with `-compare-fn' +if that's non-nil. + +Alias: `-contains-p'" + (not + (null + (cond + ((null -compare-fn) (member element list)) + ((eq -compare-fn 'eq) (memq element list)) + ((eq -compare-fn 'eql) (memql element list)) + (t + (let ((lst list)) + (while (and lst + (not (funcall -compare-fn element (car lst)))) + (setq lst (cdr lst))) + lst)))))) + +(defalias '-contains-p '-contains?) + +(defun -same-items? (list list2) + "Return true if LIST and LIST2 has the same items. + +The order of the elements in the lists does not matter. + +Alias: `-same-items-p'" + (let ((length-a (length list)) + (length-b (length list2))) + (and + (= length-a length-b) + (= length-a (length (-intersection list list2)))))) + +(defalias '-same-items-p '-same-items?) + +(defun -is-prefix? (prefix list) + "Return non-nil if PREFIX is prefix of LIST. + +Alias: `-is-prefix-p'" + (declare (pure t) (side-effect-free t)) + (--each-while list (equal (car prefix) it) + (!cdr prefix)) + (not prefix)) + +(defun -is-suffix? (suffix list) + "Return non-nil if SUFFIX is suffix of LIST. + +Alias: `-is-suffix-p'" + (declare (pure t) (side-effect-free t)) + (-is-prefix? (reverse suffix) (reverse list))) + +(defun -is-infix? (infix list) + "Return non-nil if INFIX is infix of LIST. + +This operation runs in O(n^2) time + +Alias: `-is-infix-p'" + (declare (pure t) (side-effect-free t)) + (let (done) + (while (and (not done) list) + (setq done (-is-prefix? infix list)) + (!cdr list)) + done)) + +(defalias '-is-prefix-p '-is-prefix?) +(defalias '-is-suffix-p '-is-suffix?) +(defalias '-is-infix-p '-is-infix?) + +(defun -sort (comparator list) + "Sort LIST, stably, comparing elements using COMPARATOR. +Return the sorted list. LIST is NOT modified by side effects. +COMPARATOR is called with two elements of LIST, and should return non-nil +if the first element should sort before the second." + (sort (copy-sequence list) comparator)) + +(defmacro --sort (form list) + "Anaphoric form of `-sort'." + (declare (debug (form form))) + `(-sort (lambda (it other) ,form) ,list)) + +(defun -list (&rest args) + "Return a list with ARGS. + +If first item of ARGS is already a list, simply return ARGS. If +not, return a list with ARGS as elements." + (declare (pure t) (side-effect-free t)) + (let ((arg (car args))) + (if (listp arg) arg args))) + +(defun -repeat (n x) + "Return a list with X repeated N times. +Return nil if N is less than 1." + (declare (pure t) (side-effect-free t)) + (let (ret) + (--dotimes n (!cons x ret)) + ret)) + +(defun -sum (list) + "Return the sum of LIST." + (declare (pure t) (side-effect-free t)) + (apply '+ list)) + +(defun -product (list) + "Return the product of LIST." + (declare (pure t) (side-effect-free t)) + (apply '* list)) + +(defun -max (list) + "Return the largest value from LIST of numbers or markers." + (declare (pure t) (side-effect-free t)) + (apply 'max list)) + +(defun -min (list) + "Return the smallest value from LIST of numbers or markers." + (declare (pure t) (side-effect-free t)) + (apply 'min list)) + +(defun -max-by (comparator list) + "Take a comparison function COMPARATOR and a LIST and return +the greatest element of the list by the comparison function. + +See also combinator `-on' which can transform the values before +comparing them." + (--reduce (if (funcall comparator it acc) it acc) list)) + +(defun -min-by (comparator list) + "Take a comparison function COMPARATOR and a LIST and return +the least element of the list by the comparison function. + +See also combinator `-on' which can transform the values before +comparing them." + (--reduce (if (funcall comparator it acc) acc it) list)) + +(defmacro --max-by (form list) + "Anaphoric version of `-max-by'. + +The items for the comparator form are exposed as \"it\" and \"other\"." + (declare (debug (form form))) + `(-max-by (lambda (it other) ,form) ,list)) + +(defmacro --min-by (form list) + "Anaphoric version of `-min-by'. + +The items for the comparator form are exposed as \"it\" and \"other\"." + (declare (debug (form form))) + `(-min-by (lambda (it other) ,form) ,list)) + +(defun -iterate (fun init n) + "Return a list of iterated applications of FUN to INIT. + +This means a list of form: + + (init (fun init) (fun (fun init)) ...) + +N is the length of the returned list." + (if (= n 0) nil + (let ((r (list init))) + (--dotimes (1- n) + (push (funcall fun (car r)) r)) + (nreverse r)))) + +(defun -fix (fn list) + "Compute the (least) fixpoint of FN with initial input LIST. + +FN is called at least once, results are compared with `equal'." + (let ((re (funcall fn list))) + (while (not (equal list re)) + (setq list re) + (setq re (funcall fn re))) + re)) + +(defmacro --fix (form list) + "Anaphoric form of `-fix'." + `(-fix (lambda (it) ,form) ,list)) + +(defun -unfold (fun seed) + "Build a list from SEED using FUN. + +This is \"dual\" operation to `-reduce-r': while -reduce-r +consumes a list to produce a single value, `-unfold' takes a +seed value and builds a (potentially infinite!) list. + +FUN should return `nil' to stop the generating process, or a +cons (A . B), where A will be prepended to the result and B is +the new seed." + (let ((last (funcall fun seed)) r) + (while last + (push (car last) r) + (setq last (funcall fun (cdr last)))) + (nreverse r))) + +(defmacro --unfold (form seed) + "Anaphoric version of `-unfold'." + (declare (debug (form form))) + `(-unfold (lambda (it) ,form) ,seed)) + +(defun -cons-pair? (con) + "Return non-nil if CON is true cons pair. +That is (A . B) where B is not a list." + (declare (pure t) (side-effect-free t)) + (and (listp con) + (not (listp (cdr con))))) + +(defun -cons-to-list (con) + "Convert a cons pair to a list with `car' and `cdr' of the pair respectively." + (declare (pure t) (side-effect-free t)) + (list (car con) (cdr con))) + +(defun -value-to-list (val) + "Convert a value to a list. + +If the value is a cons pair, make a list with two elements, `car' +and `cdr' of the pair respectively. + +If the value is anything else, wrap it in a list." + (declare (pure t) (side-effect-free t)) + (cond + ((-cons-pair? val) (-cons-to-list val)) + (t (list val)))) + +(defun -tree-mapreduce-from (fn folder init-value tree) + "Apply FN to each element of TREE, and make a list of the results. +If elements of TREE are lists themselves, apply FN recursively to +elements of these nested lists. + +Then reduce the resulting lists using FOLDER and initial value +INIT-VALUE. See `-reduce-r-from'. + +This is the same as calling `-tree-reduce-from' after `-tree-map' +but is twice as fast as it only traverse the structure once." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (-reduce-r-from folder init-value (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree))) + (t (funcall fn tree)))) + +(defmacro --tree-mapreduce-from (form folder init-value tree) + "Anaphoric form of `-tree-mapreduce-from'." + (declare (debug (form form form form))) + `(-tree-mapreduce-from (lambda (it) ,form) (lambda (it acc) ,folder) ,init-value ,tree)) + +(defun -tree-mapreduce (fn folder tree) + "Apply FN to each element of TREE, and make a list of the results. +If elements of TREE are lists themselves, apply FN recursively to +elements of these nested lists. + +Then reduce the resulting lists using FOLDER and initial value +INIT-VALUE. See `-reduce-r-from'. + +This is the same as calling `-tree-reduce' after `-tree-map' +but is twice as fast as it only traverse the structure once." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree))) + (t (funcall fn tree)))) + +(defmacro --tree-mapreduce (form folder tree) + "Anaphoric form of `-tree-mapreduce'." + (declare (debug (form form form))) + `(-tree-mapreduce (lambda (it) ,form) (lambda (it acc) ,folder) ,tree)) + +(defun -tree-map (fn tree) + "Apply FN to each element of TREE while preserving the tree structure." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (mapcar (lambda (x) (-tree-map fn x)) tree)) + (t (funcall fn tree)))) + +(defmacro --tree-map (form tree) + "Anaphoric form of `-tree-map'." + (declare (debug (form form))) + `(-tree-map (lambda (it) ,form) ,tree)) + +(defun -tree-reduce-from (fn init-value tree) + "Use FN to reduce elements of list TREE. +If elements of TREE are lists themselves, apply the reduction recursively. + +FN is first applied to INIT-VALUE and first element of the list, +then on this result and second element from the list etc. + +The initial value is ignored on cons pairs as they always contain +two elements." + (cond + ((not tree) nil) + ((-cons-pair? tree) tree) + ((listp tree) + (-reduce-r-from fn init-value (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree))) + (t tree))) + +(defmacro --tree-reduce-from (form init-value tree) + "Anaphoric form of `-tree-reduce-from'." + (declare (debug (form form form))) + `(-tree-reduce-from (lambda (it acc) ,form) ,init-value ,tree)) + +(defun -tree-reduce (fn tree) + "Use FN to reduce elements of list TREE. +If elements of TREE are lists themselves, apply the reduction recursively. + +FN is first applied to first element of the list and second +element, then on this result and third element from the list etc. + +See `-reduce-r' for how exactly are lists of zero or one element handled." + (cond + ((not tree) nil) + ((-cons-pair? tree) tree) + ((listp tree) + (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree))) + (t tree))) + +(defmacro --tree-reduce (form tree) + "Anaphoric form of `-tree-reduce'." + (declare (debug (form form))) + `(-tree-reduce (lambda (it acc) ,form) ,tree)) + +(defun -tree-map-nodes (pred fun tree) + "Call FUN on each node of TREE that satisfies PRED. + +If PRED returns nil, continue descending down this node. If PRED +returns non-nil, apply FUN to this node and do not descend +further." + (if (funcall pred tree) + (funcall fun tree) + (if (and (listp tree) + (not (-cons-pair? tree))) + (-map (lambda (x) (-tree-map-nodes pred fun x)) tree) + tree))) + +(defmacro --tree-map-nodes (pred form tree) + "Anaphoric form of `-tree-map-nodes'." + `(-tree-map-nodes (lambda (it) ,pred) (lambda (it) ,form) ,tree)) + +(defun -tree-seq (branch children tree) + "Return a sequence of the nodes in TREE, in depth-first search order. + +BRANCH is a predicate of one argument that returns non-nil if the +passed argument is a branch, that is, a node that can have children. + +CHILDREN is a function of one argument that returns the children +of the passed branch node. + +Non-branch nodes are simply copied." + (cons tree + (when (funcall branch tree) + (-mapcat (lambda (x) (-tree-seq branch children x)) + (funcall children tree))))) + +(defmacro --tree-seq (branch children tree) + "Anaphoric form of `-tree-seq'." + `(-tree-seq (lambda (it) ,branch) (lambda (it) ,children) ,tree)) + +(defun -clone (list) + "Create a deep copy of LIST. +The new list has the same elements and structure but all cons are +replaced with new ones. This is useful when you need to clone a +structure such as plist or alist." + (declare (pure t) (side-effect-free t)) + (-tree-map 'identity list)) + +(defun dash-enable-font-lock () + "Add syntax highlighting to dash functions, macros and magic values." + (eval-after-load 'lisp-mode + '(progn + (let ((new-keywords '( + "-each" + "--each" + "-each-indexed" + "--each-indexed" + "-each-while" + "--each-while" + "-dotimes" + "--dotimes" + "-map" + "--map" + "-reduce-from" + "--reduce-from" + "-reduce" + "--reduce" + "-reduce-r-from" + "--reduce-r-from" + "-reduce-r" + "--reduce-r" + "-filter" + "--filter" + "-select" + "--select" + "-remove" + "--remove" + "-reject" + "--reject" + "-remove-first" + "--remove-first" + "-reject-first" + "--reject-first" + "-remove-last" + "--remove-last" + "-reject-last" + "--reject-last" + "-remove-item" + "-non-nil" + "-keep" + "--keep" + "-map-indexed" + "--map-indexed" + "-splice" + "--splice" + "-splice-list" + "--splice-list" + "-map-when" + "--map-when" + "-replace-where" + "--replace-where" + "-map-first" + "--map-first" + "-map-last" + "--map-last" + "-replace" + "-replace-first" + "-replace-last" + "-flatten" + "-flatten-n" + "-concat" + "-mapcat" + "--mapcat" + "-copy" + "-cons*" + "-snoc" + "-first" + "--first" + "-find" + "--find" + "-some" + "--some" + "-any" + "--any" + "-last" + "--last" + "-first-item" + "-last-item" + "-butlast" + "-count" + "--count" + "-any?" + "--any?" + "-some?" + "--some?" + "-any-p" + "--any-p" + "-some-p" + "--some-p" + "-all?" + "--all?" + "-every?" + "--every?" + "-all-p" + "--all-p" + "-every-p" + "--every-p" + "-none?" + "--none?" + "-none-p" + "--none-p" + "-only-some?" + "--only-some?" + "-only-some-p" + "--only-some-p" + "-slice" + "-take" + "-drop" + "-take-while" + "--take-while" + "-drop-while" + "--drop-while" + "-split-at" + "-rotate" + "-insert-at" + "-replace-at" + "-update-at" + "--update-at" + "-remove-at" + "-remove-at-indices" + "-split-with" + "--split-with" + "-split-on" + "-split-when" + "--split-when" + "-separate" + "--separate" + "-partition-all-in-steps" + "-partition-in-steps" + "-partition-all" + "-partition" + "-partition-by" + "--partition-by" + "-partition-by-header" + "--partition-by-header" + "-group-by" + "--group-by" + "-interpose" + "-interleave" + "-zip-with" + "--zip-with" + "-zip" + "-zip-fill" + "-cycle" + "-pad" + "-annotate" + "--annotate" + "-table" + "-table-flat" + "-partial" + "-elem-index" + "-elem-indices" + "-find-indices" + "--find-indices" + "-find-index" + "--find-index" + "-find-last-index" + "--find-last-index" + "-select-by-indices" + "-select-columns" + "-select-column" + "-grade-up" + "-grade-down" + "->" + "->>" + "-->" + "-when-let" + "-when-let*" + "--when-let" + "-if-let" + "-if-let*" + "--if-let" + "-let*" + "-let" + "-lambda" + "-distinct" + "-uniq" + "-union" + "-intersection" + "-difference" + "-contains?" + "-contains-p" + "-same-items?" + "-same-items-p" + "-is-prefix-p" + "-is-prefix?" + "-is-suffix-p" + "-is-suffix?" + "-is-infix-p" + "-is-infix?" + "-sort" + "--sort" + "-list" + "-repeat" + "-sum" + "-product" + "-max" + "-min" + "-max-by" + "--max-by" + "-min-by" + "--min-by" + "-iterate" + "--iterate" + "-fix" + "--fix" + "-unfold" + "--unfold" + "-cons-pair?" + "-cons-to-list" + "-value-to-list" + "-tree-mapreduce-from" + "--tree-mapreduce-from" + "-tree-mapreduce" + "--tree-mapreduce" + "-tree-map" + "--tree-map" + "-tree-reduce-from" + "--tree-reduce-from" + "-tree-reduce" + "--tree-reduce" + "-tree-seq" + "--tree-seq" + "-tree-map-nodes" + "--tree-map-nodes" + "-clone" + "-rpartial" + "-juxt" + "-applify" + "-on" + "-flip" + "-const" + "-cut" + "-orfn" + "-andfn" + "-iteratefn" + "-fixfn" + "-prodfn" + )) + (special-variables '( + "it" + "it-index" + "acc" + "other" + ))) + (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "\\_<" (regexp-opt special-variables 'paren) "\\_>") + 1 font-lock-variable-name-face)) 'append) + (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "(\\s-*" (regexp-opt new-keywords 'paren) "\\_>") + 1 font-lock-keyword-face)) 'append)) + (--each (buffer-list) + (with-current-buffer it + (when (and (eq major-mode 'emacs-lisp-mode) + (boundp 'font-lock-mode) + font-lock-mode) + (font-lock-refresh-defaults))))))) + +(provide 'dash) +;;; dash.el ends here diff --git a/elpa/exec-path-from-shell-20170508.4/exec-path-from-shell-autoloads.el b/elpa/exec-path-from-shell-20170508.4/exec-path-from-shell-autoloads.el new file mode 100644 index 0000000..4083900 --- /dev/null +++ b/elpa/exec-path-from-shell-20170508.4/exec-path-from-shell-autoloads.el @@ -0,0 +1,44 @@ +;;; exec-path-from-shell-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "exec-path-from-shell" "exec-path-from-shell.el" +;;;;;; (22911 3932 648589 906000)) +;;; Generated autoloads from exec-path-from-shell.el + +(autoload 'exec-path-from-shell-copy-envs "exec-path-from-shell" "\ +Set the environment variables with NAMES from the user's shell. + +As a special case, if the variable is $PATH, then `exec-path' and +`eshell-path-env' are also set appropriately. The result is an alist, +as described by `exec-path-from-shell-getenvs'. + +\(fn NAMES)" nil nil) + +(autoload 'exec-path-from-shell-copy-env "exec-path-from-shell" "\ +Set the environment variable $NAME from the user's shell. + +As a special case, if the variable is $PATH, then `exec-path' and +`eshell-path-env' are also set appropriately. Return the value +of the environment variable. + +\(fn NAME)" t nil) + +(autoload 'exec-path-from-shell-initialize "exec-path-from-shell" "\ +Initialize environment from the user's shell. + +The values of all the environment variables named in +`exec-path-from-shell-variables' are set from the corresponding +values used in the user's shell. + +\(fn)" t nil) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; exec-path-from-shell-autoloads.el ends here diff --git a/elpa/exec-path-from-shell-20170508.4/exec-path-from-shell-pkg.el b/elpa/exec-path-from-shell-20170508.4/exec-path-from-shell-pkg.el new file mode 100644 index 0000000..3703a14 --- /dev/null +++ b/elpa/exec-path-from-shell-20170508.4/exec-path-from-shell-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "exec-path-from-shell" "20170508.4" "Get environment variables such as $PATH from the shell" 'nil :commit "5e355fbc50913d1ffe48bf86df0bcecd8b369ffb" :url "https://github.com/purcell/exec-path-from-shell" :keywords '("environment")) diff --git a/elpa/exec-path-from-shell-20170508.4/exec-path-from-shell.el b/elpa/exec-path-from-shell-20170508.4/exec-path-from-shell.el new file mode 100644 index 0000000..2bec881 --- /dev/null +++ b/elpa/exec-path-from-shell-20170508.4/exec-path-from-shell.el @@ -0,0 +1,270 @@ +;;; exec-path-from-shell.el --- Get environment variables such as $PATH from the shell + +;; Copyright (C) 2012-2014 Steve Purcell + +;; Author: Steve Purcell +;; Keywords: environment +;; URL: https://github.com/purcell/exec-path-from-shell +;; Package-Version: 20170508.4 +;; Package-X-Original-Version: 0 + +;; This file is not part of GNU Emacs. + +;; This file is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this file. If not, see . + +;;; Commentary: + +;; On OS X (and perhaps elsewhere) the $PATH environment variable and +;; `exec-path' used by a windowed Emacs instance will usually be the +;; system-wide default path, rather than that seen in a terminal +;; window. + +;; This library allows the user to set Emacs' `exec-path' and $PATH +;; from the shell path, so that `shell-command', `compile' and the +;; like work as expected. + +;; It also allows other environment variables to be retrieved from the +;; shell, so that Emacs will see the same values you get in a terminal. + +;; If you use a non-POSIX-standard shell like "tcsh" or "fish", your +;; shell will be asked to execute "sh" as a subshell in order to print +;; out the variables in a format which can be reliably parsed. "sh" +;; must be a POSIX-compliant shell in this case. + +;; Note that shell variables which have not been exported as +;; environment variables (e.g. using the "export" keyword) may not be +;; visible to `exec-path-from-shell'. + +;; Installation: + +;; ELPA packages are available on Marmalade and MELPA. Alternatively, +;; place this file on a directory in your `load-path', and explicitly +;; require it. + +;; Usage: +;; +;; (require 'exec-path-from-shell) ;; if not using the ELPA package +;; (exec-path-from-shell-initialize) +;; +;; Customize `exec-path-from-shell-variables' to modify the list of +;; variables imported. +;; +;; If you use your Emacs config on other platforms, you can instead +;; make initialization conditional as follows: +;; +;; (when (memq window-system '(mac ns)) +;; (exec-path-from-shell-initialize)) +;; +;; Alternatively, you can use `exec-path-from-shell-copy-envs' or +;; `exec-path-from-shell-copy-env' directly, e.g. +;; +;; (exec-path-from-shell-copy-env "PYTHONPATH") + +;;; Code: + +(defgroup exec-path-from-shell nil + "Make Emacs use shell-defined values for $PATH etc." + :prefix "exec-path-from-shell-" + :group 'environment) + +(defcustom exec-path-from-shell-variables + '("PATH" "MANPATH") + "List of environment variables which are copied from the shell." + :type '(repeat (string :tag "Environment variable")) + :group 'exec-path-from-shell) + +(defcustom exec-path-from-shell-check-startup-files t + "If non-nil, warn if variables are being set in the wrong shell startup files. +Environment variables should be set in .profile or .zshenv rather than +.bashrc or .zshrc." + :type 'boolean + :group 'exec-path-from-shell) + +(defcustom exec-path-from-shell-shell-name nil + "If non-nil, use this shell executable. +Otherwise, use either `shell-file-name' (if set), or the value of +the SHELL environment variable." + :type '(choice + (file :tag "Shell executable") + (const :tag "Use `shell-file-name' or $SHELL" nil)) + :group 'exec-path-from-shell) + +(defvar exec-path-from-shell-debug nil + "Display debug info when non-nil.") + +(defun exec-path-from-shell--double-quote (s) + "Double-quote S, escaping any double-quotes already contained in it." + (concat "\"" (replace-regexp-in-string "\"" "\\\\\"" s) "\"")) + +(defun exec-path-from-shell--shell () + "Return the shell to use. +See documentation for `exec-path-from-shell-shell-name'." + (or + exec-path-from-shell-shell-name + shell-file-name + (getenv "SHELL") + (error "SHELL environment variable is unset"))) + +(defcustom exec-path-from-shell-arguments + (if (string-match-p "t?csh$" (exec-path-from-shell--shell)) + (list "-d") + (list "-l" "-i")) + "Additional arguments to pass to the shell. + +The default value denotes an interactive login shell." + :type '(repeat (string :tag "Shell argument")) + :group 'exec-path-from-shell) + +(defun exec-path-from-shell--debug (msg &rest args) + "Print MSG and ARGS like `message', but only if debug output is enabled." + (when exec-path-from-shell-debug + (apply 'message msg args))) + +(defun exec-path-from-shell--standard-shell-p (shell) + "Return non-nil iff the shell supports the standard ${VAR-default} syntax." + (not (string-match "\\(fish\\|t?csh\\)$" shell))) + +(defun exec-path-from-shell-printf (str &optional args) + "Return the result of printing STR in the user's shell. + +Executes the shell as interactive login shell. + +STR is inserted literally in a single-quoted argument to printf, +and may therefore contain backslashed escape sequences understood +by printf. + +ARGS is an optional list of args which will be inserted by printf +in place of any % placeholders in STR. ARGS are not automatically +shell-escaped, so they may contain $ etc." + (let* ((printf-bin (or (executable-find "printf") "printf")) + (printf-command + (concat printf-bin + " '__RESULT\\000" str "\\000__RESULT' " + (mapconcat #'exec-path-from-shell--double-quote args " "))) + (shell (exec-path-from-shell--shell)) + (shell-args (append exec-path-from-shell-arguments + (list "-c" + (if (exec-path-from-shell--standard-shell-p shell) + printf-command + (concat "sh -c " (shell-quote-argument printf-command))))))) + (with-temp-buffer + (exec-path-from-shell--debug "Invoking shell %s with args %S" shell shell-args) + (let ((exit-code (apply #'call-process shell nil t nil shell-args))) + (exec-path-from-shell--debug "Shell printed: %S" (buffer-string)) + (unless (zerop exit-code) + (error "Non-zero exit code from shell %s invoked with args %S. Output was:\n%S" + shell shell-args (buffer-string)))) + (goto-char (point-min)) + (if (re-search-forward "__RESULT\0\\(.*\\)\0__RESULT" nil t) + (match-string 1) + (error "Expected printf output from shell, but got: %S" (buffer-string)))))) + +(defun exec-path-from-shell-getenvs (names) + "Get the environment variables with NAMES from the user's shell. + +Execute the shell according to `exec-path-from-shell-arguments'. +The result is a list of (NAME . VALUE) pairs." + (let* ((random-default (md5 (format "%s%s%s" (emacs-pid) (random) (current-time)))) + (dollar-names (mapcar (lambda (n) (format "${%s-%s}" n random-default)) names)) + (values (split-string (exec-path-from-shell-printf + (mapconcat #'identity (make-list (length names) "%s") "\\000") + dollar-names) "\0"))) + (let (result) + (while names + (prog1 + (let ((value (car values))) + (push (cons (car names) + (unless (string-equal random-default value) + value)) + result)) + (setq values (cdr values) + names (cdr names)))) + result))) + +(defun exec-path-from-shell-getenv (name) + "Get the environment variable NAME from the user's shell. + +Execute the shell as interactive login shell, have it output the +variable of NAME and return this output as string." + (cdr (assoc name (exec-path-from-shell-getenvs (list name))))) + +(defun exec-path-from-shell-setenv (name value) + "Set the value of environment var NAME to VALUE. +Additionally, if NAME is \"PATH\" then also set corresponding +variables such as `exec-path'." + (setenv name value) + (when (string-equal "PATH" name) + (setq eshell-path-env value + exec-path (append (parse-colon-path value) (list exec-directory))))) + +;;;###autoload +(defun exec-path-from-shell-copy-envs (names) + "Set the environment variables with NAMES from the user's shell. + +As a special case, if the variable is $PATH, then `exec-path' and +`eshell-path-env' are also set appropriately. The result is an alist, +as described by `exec-path-from-shell-getenvs'." + (let ((pairs (exec-path-from-shell-getenvs names))) + (when exec-path-from-shell-check-startup-files + (exec-path-from-shell--maybe-warn-about-startup-files pairs)) + (mapc (lambda (pair) + (exec-path-from-shell-setenv (car pair) (cdr pair))) + pairs))) + +(defun exec-path-from-shell--maybe-warn-about-startup-files (pairs) + "Warn the user if the value of PAIRS seems to depend on interactive shell startup files." + (let ((without-minus-i (remove "-i" exec-path-from-shell-arguments))) + ;; If the user is using "-i", we warn them if it is necessary. + (unless (eq exec-path-from-shell-arguments without-minus-i) + (let* ((exec-path-from-shell-arguments without-minus-i) + (alt-pairs (exec-path-from-shell-getenvs (mapcar 'car pairs))) + different) + (dolist (pair pairs) + (unless (equal pair (assoc (car pair) alt-pairs)) + (push (car pair) different))) + (when different + (message "You appear to be setting environment variables %S in your .bashrc or .zshrc: those files are only read by interactive shells, so you should instead set environment variables in startup files like .profile, .bash_profile or .zshenv. Refer to your shell's man page for more info. Customize `exec-path-from-shell-arguments' to remove \"-i\" when done, or disable `exec-path-from-shell-check-startup-files' to disable this message." different)))))) + +;;;###autoload +(defun exec-path-from-shell-copy-env (name) + "Set the environment variable $NAME from the user's shell. + +As a special case, if the variable is $PATH, then `exec-path' and +`eshell-path-env' are also set appropriately. Return the value +of the environment variable." + (interactive "sCopy value of which environment variable from shell? ") + (cdar (exec-path-from-shell-copy-envs (list name)))) + +;;;###autoload +(defun exec-path-from-shell-initialize () + "Initialize environment from the user's shell. + +The values of all the environment variables named in +`exec-path-from-shell-variables' are set from the corresponding +values used in the user's shell." + (interactive) + (exec-path-from-shell-copy-envs exec-path-from-shell-variables)) + + +(provide 'exec-path-from-shell) + +;; Local Variables: +;; coding: utf-8 +;; indent-tabs-mode: nil +;; mangle-whitespace: t +;; require-final-newline: t +;; checkdoc-minor-mode: t +;; End: + +;;; exec-path-from-shell.el ends here diff --git a/elpa/hydra-20170813.1058/hydra-autoloads.el b/elpa/hydra-20170813.1058/hydra-autoloads.el new file mode 100644 index 0000000..b7e07e3 --- /dev/null +++ b/elpa/hydra-20170813.1058/hydra-autoloads.el @@ -0,0 +1,77 @@ +;;; hydra-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "hydra" "hydra.el" (22942 51276 155994 337000)) +;;; Generated autoloads from hydra.el + +(autoload 'defhydra "hydra" "\ +Create a Hydra - a family of functions with prefix NAME. + +NAME should be a symbol, it will be the prefix of all functions +defined here. + +BODY has the format: + + (BODY-MAP BODY-KEY &rest BODY-PLIST) + +DOCSTRING will be displayed in the echo area to identify the +Hydra. When DOCSTRING starts with a newline, special Ruby-style +substitution will be performed by `hydra--format'. + +Functions are created on basis of HEADS, each of which has the +format: + + (KEY CMD &optional HINT &rest PLIST) + +BODY-MAP is a keymap; `global-map' is used quite often. Each +function generated from HEADS will be bound in BODY-MAP to +BODY-KEY + KEY (both are strings passed to `kbd'), and will set +the transient map so that all following heads can be called +though KEY only. BODY-KEY can be an empty string. + +CMD is a callable expression: either an interactive function +name, or an interactive lambda, or a single sexp (it will be +wrapped in an interactive lambda). + +HINT is a short string that identifies its head. It will be +printed beside KEY in the echo erea if `hydra-is-helpful' is not +nil. If you don't even want the KEY to be printed, set HINT +explicitly to nil. + +The heads inherit their PLIST from BODY-PLIST and are allowed to +override some keys. The keys recognized are :exit and :bind. +:exit can be: + +- nil (default): this head will continue the Hydra state. +- t: this head will stop the Hydra state. + +:bind can be: +- nil: this head will not be bound in BODY-MAP. +- a lambda taking KEY and CMD used to bind a head. + +It is possible to omit both BODY-MAP and BODY-KEY if you don't +want to bind anything. In that case, typically you will bind the +generated NAME/body command. This command is also the return +result of `defhydra'. + +\(fn NAME BODY &optional DOCSTRING &rest HEADS)" nil t) + +(function-put 'defhydra 'lisp-indent-function 'defun) + +(function-put 'defhydra 'doc-string-elt '3) + +;;;*** + +;;;### (autoloads nil nil ("hydra-examples.el" "hydra-ox.el" "hydra-pkg.el" +;;;;;; "lv.el") (22942 51276 167994 399000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; hydra-autoloads.el ends here diff --git a/elpa/hydra-20170813.1058/hydra-examples.el b/elpa/hydra-20170813.1058/hydra-examples.el new file mode 100644 index 0000000..70f75b0 --- /dev/null +++ b/elpa/hydra-20170813.1058/hydra-examples.el @@ -0,0 +1,386 @@ +;;; hydra-examples.el --- Some applications for Hydra + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Oleh Krehel + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: +;; +;; These are the sample Hydras. +;; +;; If you want to use them plainly, set `hydra-examples-verbatim' to t +;; before requiring this file. But it's probably better to only look +;; at them and use them as templates for building your own. + +;;; Code: + +(require 'hydra) + +;;* Examples +;;** Example 1: text scale +(when (bound-and-true-p hydra-examples-verbatim) + (defhydra hydra-zoom (global-map "") + "zoom" + ("g" text-scale-increase "in") + ("l" text-scale-decrease "out"))) + +;; This example generates three commands: +;; +;; `hydra-zoom/text-scale-increase' +;; `hydra-zoom/text-scale-decrease' +;; `hydra-zoom/body' +;; +;; In addition, two of them are bound like this: +;; +;; (global-set-key (kbd " g") 'hydra-zoom/text-scale-increase) +;; (global-set-key (kbd " l") 'hydra-zoom/text-scale-decrease) +;; +;; Note that you can substitute `global-map' with e.g. `emacs-lisp-mode-map' if you need. +;; The functions generated will be the same, except the binding code will change to: +;; +;; (define-key emacs-lisp-mode-map [f2 103] +;; (function hydra-zoom/text-scale-increase)) +;; (define-key emacs-lisp-mode-map [f2 108] +;; (function hydra-zoom/text-scale-decrease)) + +;;** Example 2: move window splitter +(when (bound-and-true-p hydra-examples-verbatim) + (defhydra hydra-splitter (global-map "C-M-s") + "splitter" + ("h" hydra-move-splitter-left) + ("j" hydra-move-splitter-down) + ("k" hydra-move-splitter-up) + ("l" hydra-move-splitter-right))) + +;;** Example 3: jump to error +(when (bound-and-true-p hydra-examples-verbatim) + (defhydra hydra-error (global-map "M-g") + "goto-error" + ("h" first-error "first") + ("j" next-error "next") + ("k" previous-error "prev") + ("v" recenter-top-bottom "recenter") + ("q" nil "quit"))) + +;; This example introduces only one new thing: since the command +;; passed to the "q" head is nil, it will quit the Hydra without doing +;; anything. Heads that quit the Hydra instead of continuing are +;; referred to as having blue :color. All the other heads have red +;; :color, unless other is specified. + +;;** Example 4: toggle rarely used modes +(when (bound-and-true-p hydra-examples-verbatim) + (defvar whitespace-mode nil) + (global-set-key + (kbd "C-c C-v") + (defhydra hydra-toggle-simple (:color blue) + "toggle" + ("a" abbrev-mode "abbrev") + ("d" toggle-debug-on-error "debug") + ("f" auto-fill-mode "fill") + ("t" toggle-truncate-lines "truncate") + ("w" whitespace-mode "whitespace") + ("q" nil "cancel")))) + +;; Note that in this case, `defhydra' returns the `hydra-toggle-simple/body' +;; symbol, which is then passed to `global-set-key'. +;; +;; Another new thing is that both the keymap and the body prefix are +;; skipped. This means that `defhydra' will bind nothing - that's why +;; `global-set-key' is necessary. +;; +;; One more new thing is that you can assign a :color to the body. All +;; heads will inherit this color. The code above is very much equivalent to: +;; +;; (global-set-key (kbd "C-c C-v a") 'abbrev-mode) +;; (global-set-key (kbd "C-c C-v d") 'toggle-debug-on-error) +;; +;; The differences are: +;; +;; * You get a hint immediately after "C-c C-v" +;; * You can cancel and call a command immediately, e.g. "C-c C-v C-n" +;; is equivalent to "C-n" with Hydra approach, while it will error +;; that "C-c C-v C-n" isn't bound with the usual approach. + +;;** Example 5: mini-vi +(defun hydra-vi/pre () + (set-cursor-color "#e52b50")) + +(defun hydra-vi/post () + (set-cursor-color "#ffffff")) + +(when (bound-and-true-p hydra-examples-verbatim) + (global-set-key + (kbd "C-z") + (defhydra hydra-vi (:pre hydra-vi/pre :post hydra-vi/post :color amaranth) + "vi" + ("l" forward-char) + ("h" backward-char) + ("j" next-line) + ("k" previous-line) + ("m" set-mark-command "mark") + ("a" move-beginning-of-line "beg") + ("e" move-end-of-line "end") + ("d" delete-region "del" :color blue) + ("y" kill-ring-save "yank" :color blue) + ("q" nil "quit"))) + (hydra-set-property 'hydra-vi :verbosity 1)) + +;; This example introduces :color amaranth. It's similar to red, +;; except while you can quit red with any binding which isn't a Hydra +;; head, you can quit amaranth only with a blue head. So you can quit +;; this mode only with "d", "y", "q" or "C-g". +;; +;; Another novelty are the :pre and :post handlers. :pre will be +;; called before each command, while :post will be called when the +;; Hydra quits. In this case, they're used to override the cursor +;; color while Hydra is active. + +;;** Example 6: selective global bind +(when (bound-and-true-p hydra-examples-verbatim) + (defhydra hydra-next-error (global-map "C-x") + "next-error" + ("`" next-error "next") + ("j" next-error "next" :bind nil) + ("k" previous-error "previous" :bind nil))) + +;; This example will bind "C-x `" in `global-map', but it will not +;; bind "C-x j" and "C-x k". +;; You can still "C-x `jjk" though. + +;;** Example 7: toggle with Ruby-style docstring +(defvar whitespace-mode nil) +(defhydra hydra-toggle (:color pink) + " +_a_ abbrev-mode: %`abbrev-mode +_d_ debug-on-error: %`debug-on-error +_f_ auto-fill-mode: %`auto-fill-function +_t_ truncate-lines: %`truncate-lines +_w_ whitespace-mode: %`whitespace-mode + +" + ("a" abbrev-mode nil) + ("d" toggle-debug-on-error nil) + ("f" auto-fill-mode nil) + ("t" toggle-truncate-lines nil) + ("w" whitespace-mode nil) + ("q" nil "quit")) +;; Recommended binding: +;; (global-set-key (kbd "C-c C-v") 'hydra-toggle/body) + +;; Here, using e.g. "_a_" translates to "a" with proper face. +;; More interestingly: +;; +;; "foobar %`abbrev-mode" means roughly (format "foobar %S" abbrev-mode) +;; +;; This means that you actually see the state of the mode that you're changing. + +;;** Example 8: the whole menu for `Buffer-menu-mode' +(defhydra hydra-buffer-menu (:color pink + :hint nil) + " +^Mark^ ^Unmark^ ^Actions^ ^Search +^^^^^^^^----------------------------------------------------------------- (__) +_m_: mark _u_: unmark _x_: execute _R_: re-isearch (oo) +_s_: save _U_: unmark up _b_: bury _I_: isearch /------\\/ +_d_: delete ^ ^ _g_: refresh _O_: multi-occur / | || +_D_: delete up ^ ^ _T_: files only: % -28`Buffer-menu-files-only^^ * /\\---/\\ +_~_: modified ^ ^ ^ ^ ^^ ~~ ~~ +" + ("m" Buffer-menu-mark) + ("u" Buffer-menu-unmark) + ("U" Buffer-menu-backup-unmark) + ("d" Buffer-menu-delete) + ("D" Buffer-menu-delete-backwards) + ("s" Buffer-menu-save) + ("~" Buffer-menu-not-modified) + ("x" Buffer-menu-execute) + ("b" Buffer-menu-bury) + ("g" revert-buffer) + ("T" Buffer-menu-toggle-files-only) + ("O" Buffer-menu-multi-occur :color blue) + ("I" Buffer-menu-isearch-buffers :color blue) + ("R" Buffer-menu-isearch-buffers-regexp :color blue) + ("c" nil "cancel") + ("v" Buffer-menu-select "select" :color blue) + ("o" Buffer-menu-other-window "other-window" :color blue) + ("q" quit-window "quit" :color blue)) +;; Recommended binding: +;; (define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body) + +;;** Example 9: s-expressions in the docstring +;; You can inline s-expresssions into the docstring like this: +(defvar dired-mode-map) +(declare-function dired-mark "dired") +(when (bound-and-true-p hydra-examples-verbatim) + (require 'dired) + (defhydra hydra-marked-items (dired-mode-map "") + " +Number of marked items: %(length (dired-get-marked-files)) +" + ("m" dired-mark "mark"))) + +;; This results in the following dynamic docstring: +;; +;; (format "Number of marked items: %S\n" +;; (length (dired-get-marked-files))) +;; +;; You can use `format'-style width specs, e.g. % 10(length nil). + +;;** Example 10: apropos family +(defhydra hydra-apropos (:color blue + :hint nil) + " +_a_propos _c_ommand +_d_ocumentation _l_ibrary +_v_ariable _u_ser-option +^ ^ valu_e_" + ("a" apropos) + ("d" apropos-documentation) + ("v" apropos-variable) + ("c" apropos-command) + ("l" apropos-library) + ("u" apropos-user-option) + ("e" apropos-value)) +;; Recommended binding: +;; (global-set-key (kbd "C-c h") 'hydra-apropos/body) + +;;** Example 11: rectangle-mark-mode +(require 'rect) +(defhydra hydra-rectangle (:body-pre (rectangle-mark-mode 1) + :color pink + :post (deactivate-mark)) + " + ^_k_^ _d_elete _s_tring +_h_ _l_ _o_k _y_ank + ^_j_^ _n_ew-copy _r_eset +^^^^ _e_xchange _u_ndo +^^^^ ^ ^ _p_aste +" + ("h" rectangle-backward-char nil) + ("l" rectangle-forward-char nil) + ("k" rectangle-previous-line nil) + ("j" rectangle-next-line nil) + ("e" hydra-ex-point-mark nil) + ("n" copy-rectangle-as-kill nil) + ("d" delete-rectangle nil) + ("r" (if (region-active-p) + (deactivate-mark) + (rectangle-mark-mode 1)) nil) + ("y" yank-rectangle nil) + ("u" undo nil) + ("s" string-rectangle nil) + ("p" kill-rectangle nil) + ("o" nil nil)) + +;; Recommended binding: +;; (global-set-key (kbd "C-x SPC") 'hydra-rectangle/body) + +;;** Example 12: org-agenda-view +(defun org-agenda-cts () + (and (eq major-mode 'org-agenda-mode) + (let ((args (get-text-property + (min (1- (point-max)) (point)) + 'org-last-args))) + (nth 2 args)))) + +(defhydra hydra-org-agenda-view (:hint none) + " +_d_: ?d? day _g_: time grid=?g? _a_: arch-trees +_w_: ?w? week _[_: inactive _A_: arch-files +_t_: ?t? fortnight _f_: follow=?f? _r_: clock report=?r? +_m_: ?m? month _e_: entry text=?e? _D_: include diary=?D? +_y_: ?y? year _q_: quit _L__l__c_: log = ?l?" + ("SPC" org-agenda-reset-view) + ("d" org-agenda-day-view (if (eq 'day (org-agenda-cts)) "[x]" "[ ]")) + ("w" org-agenda-week-view (if (eq 'week (org-agenda-cts)) "[x]" "[ ]")) + ("t" org-agenda-fortnight-view (if (eq 'fortnight (org-agenda-cts)) "[x]" "[ ]")) + ("m" org-agenda-month-view (if (eq 'month (org-agenda-cts)) "[x]" "[ ]")) + ("y" org-agenda-year-view (if (eq 'year (org-agenda-cts)) "[x]" "[ ]")) + ("l" org-agenda-log-mode (format "% -3S" org-agenda-show-log)) + ("L" (org-agenda-log-mode '(4))) + ("c" (org-agenda-log-mode 'clockcheck)) + ("f" org-agenda-follow-mode (format "% -3S" org-agenda-follow-mode)) + ("a" org-agenda-archives-mode) + ("A" (org-agenda-archives-mode 'files)) + ("r" org-agenda-clockreport-mode (format "% -3S" org-agenda-clockreport-mode)) + ("e" org-agenda-entry-text-mode (format "% -3S" org-agenda-entry-text-mode)) + ("g" org-agenda-toggle-time-grid (format "% -3S" org-agenda-use-time-grid)) + ("D" org-agenda-toggle-diary (format "% -3S" org-agenda-include-diary)) + ("!" org-agenda-toggle-deadlines) + ("[" (let ((org-agenda-include-inactive-timestamps t)) + (org-agenda-check-type t 'timeline 'agenda) + (org-agenda-redo) + (message "Display now includes inactive timestamps as well"))) + ("q" (message "Abort") :exit t) + ("v" nil)) + +;; Recommended binding: +;; (define-key org-agenda-mode-map "v" 'hydra-org-agenda-view/body) + +;;* Helpers +(require 'windmove) + +(defun hydra-move-splitter-left (arg) + "Move window splitter left." + (interactive "p") + (if (let ((windmove-wrap-around)) + (windmove-find-other-window 'right)) + (shrink-window-horizontally arg) + (enlarge-window-horizontally arg))) + +(defun hydra-move-splitter-right (arg) + "Move window splitter right." + (interactive "p") + (if (let ((windmove-wrap-around)) + (windmove-find-other-window 'right)) + (enlarge-window-horizontally arg) + (shrink-window-horizontally arg))) + +(defun hydra-move-splitter-up (arg) + "Move window splitter up." + (interactive "p") + (if (let ((windmove-wrap-around)) + (windmove-find-other-window 'up)) + (enlarge-window arg) + (shrink-window arg))) + +(defun hydra-move-splitter-down (arg) + "Move window splitter down." + (interactive "p") + (if (let ((windmove-wrap-around)) + (windmove-find-other-window 'up)) + (shrink-window arg) + (enlarge-window arg))) + +(defvar rectangle-mark-mode) +(defun hydra-ex-point-mark () + "Exchange point and mark." + (interactive) + (if rectangle-mark-mode + (rectangle-exchange-point-and-mark) + (let ((mk (mark))) + (rectangle-mark-mode 1) + (goto-char mk)))) + +(provide 'hydra-examples) + +;; Local Variables: +;; no-byte-compile: t +;; End: +;;; hydra-examples.el ends here diff --git a/elpa/hydra-20170813.1058/hydra-ox.el b/elpa/hydra-20170813.1058/hydra-ox.el new file mode 100644 index 0000000..a992efc --- /dev/null +++ b/elpa/hydra-20170813.1058/hydra-ox.el @@ -0,0 +1,127 @@ +;;; hydra-ox.el --- Org mode export widget implemented in Hydra + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Oleh Krehel + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: +;; +;; This shows how a complex dispatch menu can be built with Hydra. + +;;; Code: + +(require 'hydra) +(require 'org) +(declare-function org-html-export-as-html 'ox-html) +(declare-function org-html-export-to-html 'ox-html) +(declare-function org-latex-export-as-latex 'ox-latex) +(declare-function org-latex-export-to-latex 'ox-latex) +(declare-function org-latex-export-to-pdf 'ox-latex) +(declare-function org-ascii-export-as-ascii 'ox-ascii) +(declare-function org-ascii-export-to-ascii 'ox-ascii) + +(defhydradio hydra-ox () + (body-only "Export only the body.") + (export-scope "Export scope." [buffer subtree]) + (async-export "When non-nil, export async.") + (visible-only "When non-nil, export visible only") + (force-publishing "Toggle force publishing")) + +(defhydra hydra-ox-html (:color blue) + "ox-html" + ("H" (org-html-export-as-html + hydra-ox/async-export + (eq hydra-ox/export-scope 'subtree) + hydra-ox/visible-only + hydra-ox/body-only) + "As HTML buffer") + ("h" (org-html-export-to-html + hydra-ox/async-export + (eq hydra-ox/export-scope 'subtree) + hydra-ox/visible-only + hydra-ox/body-only) "As HTML file") + ("o" (org-open-file + (org-html-export-to-html + hydra-ox/async-export + (eq hydra-ox/export-scope 'subtree) + hydra-ox/visible-only + hydra-ox/body-only)) "As HTML file and open") + ("b" hydra-ox/body "back") + ("q" nil "quit")) + +(defhydra hydra-ox-latex (:color blue) + "ox-latex" + ("L" org-latex-export-as-latex "As LaTeX buffer") + ("l" org-latex-export-to-latex "As LaTeX file") + ("p" org-latex-export-to-pdf "As PDF file") + ("o" (org-open-file (org-latex-export-to-pdf)) "As PDF file and open") + ("b" hydra-ox/body "back") + ("q" nil "quit")) + +(defhydra hydra-ox-text (:color blue) + "ox-text" + ("A" (org-ascii-export-as-ascii + nil nil nil nil + '(:ascii-charset ascii)) + "As ASCII buffer") + + ("a" (org-ascii-export-to-ascii + nil nil nil nil + '(:ascii-charset ascii)) + "As ASCII file") + ("L" (org-ascii-export-as-ascii + nil nil nil nil + '(:ascii-charset latin1)) + "As Latin1 buffer") + ("l" (org-ascii-export-to-ascii + nil nil nil nil + '(:ascii-charset latin1)) + "As Latin1 file") + ("U" (org-ascii-export-as-ascii + nil nil nil nil + '(:ascii-charset utf-8)) + "As UTF-8 buffer") + ("u" (org-ascii-export-to-ascii + nil nil nil nil + '(:ascii-charset utf-8)) + "As UTF-8 file") + ("b" hydra-ox/body "back") + ("q" nil "quit")) + +(defhydra hydra-ox () + " +_C-b_ Body only: % -15`hydra-ox/body-only^^^ _C-v_ Visible only: %`hydra-ox/visible-only +_C-s_ Export scope: % -15`hydra-ox/export-scope _C-f_ Force publishing: %`hydra-ox/force-publishing +_C-a_ Async export: %`hydra-ox/async-export + +" + ("C-b" (hydra-ox/body-only) nil) + ("C-v" (hydra-ox/visible-only) nil) + ("C-s" (hydra-ox/export-scope) nil) + ("C-f" (hydra-ox/force-publishing) nil) + ("C-a" (hydra-ox/async-export) nil) + ("h" hydra-ox-html/body "Export to HTML" :exit t) + ("l" hydra-ox-latex/body "Export to LaTeX" :exit t) + ("t" hydra-ox-text/body "Export to Plain Text" :exit t) + ("q" nil "quit")) + +(define-key org-mode-map (kbd "C-c C-,") 'hydra-ox/body) + +(provide 'hydra-ox) + +;;; hydra-ox.el ends here diff --git a/elpa/hydra-20170813.1058/hydra-pkg.el b/elpa/hydra-20170813.1058/hydra-pkg.el new file mode 100644 index 0000000..8736d59 --- /dev/null +++ b/elpa/hydra-20170813.1058/hydra-pkg.el @@ -0,0 +1,7 @@ +(define-package "hydra" "20170813.1058" "Make bindings that stick around." + '((cl-lib "0.5")) + :url "https://github.com/abo-abo/hydra" :keywords + '("bindings")) +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/hydra-20170813.1058/hydra.el b/elpa/hydra-20170813.1058/hydra.el new file mode 100644 index 0000000..c8f9d92 --- /dev/null +++ b/elpa/hydra-20170813.1058/hydra.el @@ -0,0 +1,1403 @@ +;;; hydra.el --- Make bindings that stick around. -*- lexical-binding: t -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Oleh Krehel +;; Maintainer: Oleh Krehel +;; URL: https://github.com/abo-abo/hydra +;; Version: 0.14.0 +;; Keywords: bindings +;; Package-Requires: ((cl-lib "0.5")) + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: +;; +;; This package can be used to tie related commands into a family of +;; short bindings with a common prefix - a Hydra. +;; +;; Once you summon the Hydra (through the prefixed binding), all the +;; heads can be called in succession with only a short extension. +;; The Hydra is vanquished once Hercules, any binding that isn't the +;; Hydra's head, arrives. Note that Hercules, besides vanquishing the +;; Hydra, will still serve his orignal purpose, calling his proper +;; command. This makes the Hydra very seamless, it's like a minor +;; mode that disables itself automagically. +;; +;; Here's an example Hydra, bound in the global map (you can use any +;; keymap in place of `global-map'): +;; +;; (defhydra hydra-zoom (global-map "") +;; "zoom" +;; ("g" text-scale-increase "in") +;; ("l" text-scale-decrease "out")) +;; +;; It allows to start a command chain either like this: +;; " gg4ll5g", or " lgllg". +;; +;; Here's another approach, when you just want a "callable keymap": +;; +;; (defhydra hydra-toggle (:color blue) +;; "toggle" +;; ("a" abbrev-mode "abbrev") +;; ("d" toggle-debug-on-error "debug") +;; ("f" auto-fill-mode "fill") +;; ("t" toggle-truncate-lines "truncate") +;; ("w" whitespace-mode "whitespace") +;; ("q" nil "cancel")) +;; +;; This binds nothing so far, but if you follow up with: +;; +;; (global-set-key (kbd "C-c C-v") 'hydra-toggle/body) +;; +;; you will have bound "C-c C-v a", "C-c C-v d" etc. +;; +;; Knowing that `defhydra' defines e.g. `hydra-toggle/body' command, +;; you can nest Hydras if you wish, with `hydra-toggle/body' possibly +;; becoming a blue head of another Hydra. +;; +;; If you want to learn all intricacies of using `defhydra' without +;; having to figure it all out from this source code, check out the +;; wiki: https://github.com/abo-abo/hydra/wiki. There's a wealth of +;; information there. Everyone is welcome to bring the existing pages +;; up to date and add new ones. +;; +;; Additionally, the file hydra-examples.el serves to demo most of the +;; functionality. + +;;; Code: +;;* Requires +(require 'cl-lib) +(require 'lv) +(require 'ring) + +(defvar hydra-curr-map nil + "The keymap of the current Hydra called.") + +(defvar hydra-curr-on-exit nil + "The on-exit predicate for the current Hydra.") + +(defvar hydra-curr-foreign-keys nil + "The current :foreign-keys behavior.") + +(defvar hydra-curr-body-fn nil + "The current hydra-.../body function.") + +(defvar hydra-deactivate nil + "If a Hydra head sets this to t, exit the Hydra. +This will be done even if the head wasn't designated for exiting.") + +(defvar hydra-amaranth-warn-message "An amaranth Hydra can only exit through a blue head" + "Amaranth Warning message. Shown when the user tries to press an unbound/non-exit key while in an amaranth head.") + +(defun hydra-set-transient-map (keymap on-exit &optional foreign-keys) + "Set KEYMAP to the highest priority. + +Call ON-EXIT when the KEYMAP is deactivated. + +FOREIGN-KEYS determines the deactivation behavior, when a command +that isn't in KEYMAP is called: + +nil: deactivate KEYMAP and run the command. +run: keep KEYMAP and run the command. +warn: keep KEYMAP and issue a warning instead of running the command." + (if hydra-deactivate + (hydra-keyboard-quit) + (setq hydra-curr-map keymap) + (setq hydra-curr-on-exit on-exit) + (setq hydra-curr-foreign-keys foreign-keys) + (add-hook 'pre-command-hook 'hydra--clearfun) + (internal-push-keymap keymap 'overriding-terminal-local-map))) + +(defun hydra--clearfun () + "Disable the current Hydra unless `this-command' is a head." + (unless (eq this-command 'hydra-pause-resume) + (when (or + (memq this-command '(handle-switch-frame + keyboard-quit)) + (null overriding-terminal-local-map) + (not (or (eq this-command + (lookup-key hydra-curr-map (this-single-command-keys))) + (cl-case hydra-curr-foreign-keys + (warn + (setq this-command 'hydra-amaranth-warn)) + (run + t) + (t nil))))) + (hydra-disable)))) + +(defvar hydra--ignore nil + "When non-nil, don't call `hydra-curr-on-exit'.") + +(defvar hydra--input-method-function nil + "Store overridden `input-method-function' here.") + +(defun hydra-disable () + "Disable the current Hydra." + (setq hydra-deactivate nil) + (remove-hook 'pre-command-hook 'hydra--clearfun) + (unless hydra--ignore + (if (fboundp 'remove-function) + (remove-function input-method-function #'hydra--imf) + (when hydra--input-method-function + (setq input-method-function hydra--input-method-function) + (setq hydra--input-method-function nil)))) + (dolist (frame (frame-list)) + (with-selected-frame frame + (when overriding-terminal-local-map + (internal-pop-keymap hydra-curr-map 'overriding-terminal-local-map)))) + (unless hydra--ignore + (when hydra-curr-on-exit + (let ((on-exit hydra-curr-on-exit)) + (setq hydra-curr-on-exit nil) + (funcall on-exit))))) + +(unless (fboundp 'internal-push-keymap) + (defun internal-push-keymap (keymap symbol) + (let ((map (symbol-value symbol))) + (unless (memq keymap map) + (unless (memq 'add-keymap-witness (symbol-value symbol)) + (setq map (make-composed-keymap nil (symbol-value symbol))) + (push 'add-keymap-witness (cdr map)) + (set symbol map)) + (push keymap (cdr map)))))) + +(unless (fboundp 'internal-pop-keymap) + (defun internal-pop-keymap (keymap symbol) + (let ((map (symbol-value symbol))) + (when (memq keymap map) + (setf (cdr map) (delq keymap (cdr map)))) + (let ((tail (cddr map))) + (and (or (null tail) (keymapp tail)) + (eq 'add-keymap-witness (nth 1 map)) + (set symbol tail)))))) + +(defun hydra-amaranth-warn () + "Issue a warning that the current input was ignored." + (interactive) + (message hydra-amaranth-warn-message)) + +;;* Customize +(defgroup hydra nil + "Make bindings that stick around." + :group 'bindings + :prefix "hydra-") + +(defcustom hydra-is-helpful t + "When t, display a hint with possible bindings in the echo area." + :type 'boolean + :group 'hydra) + +(defcustom hydra-default-hint "" + "Default :hint property to use for heads when not specified in +the body or the head." + :type 'sexp + :group 'hydra) + +(defcustom hydra-lv t + "When non-nil, `lv-message' (not `message') will be used to display hints." + :type 'boolean) + +(defcustom hydra-verbose nil + "When non-nil, hydra will issue some non essential style warnings." + :type 'boolean) + +(defcustom hydra-key-format-spec "%s" + "Default `format'-style specifier for _a_ syntax in docstrings. +When nil, you can specify your own at each location like this: _ 5a_." + :type 'string) + +(defcustom hydra-doc-format-spec "%s" + "Default `format'-style specifier for ?a? syntax in docstrings." + :type 'string) + +(defcustom hydra-look-for-remap nil + "When non-nil, hydra binding behaves as keymap binding with [remap]. +When calling a head with a simple command, hydra will lookup for a potential +remap command according to the current active keymap and call it instead if +found" + :type 'boolean) + +(make-obsolete-variable + 'hydra-key-format-spec + "Since the docstrings are aligned by hand anyway, this isn't very useful." + "0.13.1") + +(defface hydra-face-red + '((t (:foreground "#FF0000" :bold t))) + "Red Hydra heads don't exit the Hydra. +Every other command exits the Hydra." + :group 'hydra) + +(defface hydra-face-blue + '((((class color) (background light)) + :foreground "#0000FF" :bold t) + (((class color) (background dark)) + :foreground "#8ac6f2" :bold t)) + "Blue Hydra heads exit the Hydra. +Every other command exits as well.") + +(defface hydra-face-amaranth + '((t (:foreground "#E52B50" :bold t))) + "Amaranth body has red heads and warns on intercepting non-heads. +Exitable only through a blue head.") + +(defface hydra-face-pink + '((t (:foreground "#FF6EB4" :bold t))) + "Pink body has red heads and runs intercepted non-heads. +Exitable only through a blue head.") + +(defface hydra-face-teal + '((t (:foreground "#367588" :bold t))) + "Teal body has blue heads and warns on intercepting non-heads. +Exitable only through a blue head.") + +;;* Fontification +(defun hydra-add-font-lock () + "Fontify `defhydra' statements." + (font-lock-add-keywords + 'emacs-lisp-mode + '(("(\\(defhydra\\)\\_> +\\(.*?\\)\\_>" + (1 font-lock-keyword-face) + (2 font-lock-type-face)) + ("(\\(defhydradio\\)\\_> +\\(.*?\\)\\_>" + (1 font-lock-keyword-face) + (2 font-lock-type-face))))) + +;;* Find Function +(eval-after-load 'find-func + '(defadvice find-function-search-for-symbol + (around hydra-around-find-function-search-for-symbol-advice + (symbol type library) activate) + "Navigate to hydras with `find-function-search-for-symbol'." + ad-do-it + ;; The orignial function returns (cons (current-buffer) (point)) + ;; if it found the point. + (unless (cdr ad-return-value) + (with-current-buffer (find-file-noselect library) + (let ((sn (symbol-name symbol))) + (when (and (null type) + (string-match "\\`\\(hydra-[a-z-A-Z0-9]+\\)/\\(.*\\)\\'" sn) + (re-search-forward (concat "(defhydra " (match-string 1 sn)) + nil t)) + (goto-char (match-beginning 0))) + (cons (current-buffer) (point))))))) + +;;* Universal Argument +(defvar hydra-base-map + (let ((map (make-sparse-keymap))) + (define-key map [?\C-u] 'hydra--universal-argument) + (define-key map [?-] 'hydra--negative-argument) + (define-key map [?0] 'hydra--digit-argument) + (define-key map [?1] 'hydra--digit-argument) + (define-key map [?2] 'hydra--digit-argument) + (define-key map [?3] 'hydra--digit-argument) + (define-key map [?4] 'hydra--digit-argument) + (define-key map [?5] 'hydra--digit-argument) + (define-key map [?6] 'hydra--digit-argument) + (define-key map [?7] 'hydra--digit-argument) + (define-key map [?8] 'hydra--digit-argument) + (define-key map [?9] 'hydra--digit-argument) + (define-key map [kp-0] 'hydra--digit-argument) + (define-key map [kp-1] 'hydra--digit-argument) + (define-key map [kp-2] 'hydra--digit-argument) + (define-key map [kp-3] 'hydra--digit-argument) + (define-key map [kp-4] 'hydra--digit-argument) + (define-key map [kp-5] 'hydra--digit-argument) + (define-key map [kp-6] 'hydra--digit-argument) + (define-key map [kp-7] 'hydra--digit-argument) + (define-key map [kp-8] 'hydra--digit-argument) + (define-key map [kp-9] 'hydra--digit-argument) + (define-key map [kp-subtract] 'hydra--negative-argument) + map) + "Keymap that all Hydras inherit. See `universal-argument-map'.") + +(defun hydra--universal-argument (arg) + "Forward to (`universal-argument' ARG)." + (interactive "P") + (setq prefix-arg (if (consp arg) + (list (* 4 (car arg))) + (if (eq arg '-) + (list -4) + '(4))))) + +(defun hydra--digit-argument (arg) + "Forward to (`digit-argument' ARG)." + (interactive "P") + (let* ((char (if (integerp last-command-event) + last-command-event + (get last-command-event 'ascii-character))) + (digit (- (logand char ?\177) ?0))) + (setq prefix-arg (cond ((integerp arg) + (+ (* arg 10) + (if (< arg 0) + (- digit) + digit))) + ((eq arg '-) + (if (zerop digit) + '- + (- digit))) + (t + digit))))) + +(defun hydra--negative-argument (arg) + "Forward to (`negative-argument' ARG)." + (interactive "P") + (setq prefix-arg (cond ((integerp arg) (- arg)) + ((eq arg '-) nil) + (t '-)))) + +;;* Repeat +(defvar hydra-repeat--prefix-arg nil + "Prefix arg to use with `hydra-repeat'.") + +(defvar hydra-repeat--command nil + "Command to use with `hydra-repeat'.") + +(defun hydra-repeat (&optional arg) + "Repeat last command with last prefix arg. +When ARG is non-nil, use that instead." + (interactive "p") + (if (eq arg 1) + (unless (string-match "hydra-repeat$" (symbol-name last-command)) + (setq hydra-repeat--command last-command) + (setq hydra-repeat--prefix-arg last-prefix-arg)) + (setq hydra-repeat--prefix-arg arg)) + (setq current-prefix-arg hydra-repeat--prefix-arg) + (funcall hydra-repeat--command)) + +;;* Misc internals +(defun hydra--callablep (x) + "Test if X is callable." + (or (functionp x) + (and (consp x) + (memq (car x) '(function quote))))) + +(defun hydra--make-callable (x) + "Generate a callable symbol from X. +If X is a function symbol or a lambda, return it. Otherwise, it +should be a single statement. Wrap it in an interactive lambda." + (cond ((or (symbolp x) (functionp x)) + x) + ((and (consp x) (eq (car x) 'function)) + (cadr x)) + (t + `(lambda () + (interactive) + ,x)))) + +(defun hydra-plist-get-default (plist prop default) + "Extract a value from a property list. +PLIST is a property list, which is a list of the form +\(PROP1 VALUE1 PROP2 VALUE2...). + +Return the value corresponding to PROP, or DEFAULT if PROP is not +one of the properties on the list." + (if (memq prop plist) + (plist-get plist prop) + default)) + +(defun hydra--head-property (h prop &optional default) + "Return for Hydra head H the value of property PROP. +Return DEFAULT if PROP is not in H." + (hydra-plist-get-default (cl-cdddr h) prop default)) + +(defun hydra--head-set-property (h prop value) + "In hydra Head H, set a property PROP to the value VALUE." + (cons (car h) (plist-put (cdr h) prop value))) + +(defun hydra--head-has-property (h prop) + "Return non nil if heads H has the property PROP." + (plist-member (cdr h) prop)) + +(defun hydra--body-foreign-keys (body) + "Return what BODY does with a non-head binding." + (or + (plist-get (cddr body) :foreign-keys) + (let ((color (plist-get (cddr body) :color))) + (cl-case color + ((amaranth teal) 'warn) + (pink 'run))))) + +(defun hydra--body-exit (body) + "Return the exit behavior of BODY." + (or + (plist-get (cddr body) :exit) + (let ((color (plist-get (cddr body) :color))) + (cl-case color + ((blue teal) t) + (t nil))))) + +(defalias 'hydra--imf #'list) + +(defun hydra-default-pre () + "Default setup that happens in each head before :pre." + (when (eq input-method-function 'key-chord-input-method) + (if (fboundp 'add-function) + (add-function :override input-method-function #'hydra--imf) + (unless hydra--input-method-function + (setq hydra--input-method-function input-method-function) + (setq input-method-function nil))))) + +(defvar hydra-timeout-timer (timer-create) + "Timer for `hydra-timeout'.") + +(defvar hydra-message-timer (timer-create) + "Timer for the hint.") + +(defvar hydra--work-around-dedicated t + "When non-nil, assume there's no bug in `pop-to-buffer'. +`pop-to-buffer' should not select a dedicated window.") + +(defun hydra-keyboard-quit () + "Quitting function similar to `keyboard-quit'." + (interactive) + (hydra-disable) + (cancel-timer hydra-timeout-timer) + (cancel-timer hydra-message-timer) + (setq hydra-curr-map nil) + (unless (and hydra--ignore + (null hydra--work-around-dedicated)) + (if hydra-lv + (lv-delete-window) + (message ""))) + nil) + +(defvar hydra-head-format "[%s]: " + "The formatter for each head of a plain docstring.") + +(defvar hydra-key-doc-function 'hydra-key-doc-function-default + "The function for formatting key-doc pairs.") + +(defun hydra-key-doc-function-default (key key-width doc doc-width) + "Doc" + (cond + ((equal key " ") (format (format "%%-%ds" (+ 3 key-width doc-width)) doc)) + (t (format (format "%%%ds: %%%ds" key-width (- -1 doc-width)) key doc)))) + +(defun hydra--to-string (x) + (if (stringp x) + x + (eval x))) + +(defun hydra--hint-heads-wocol (body heads) + "Generate a hint for the echo area. +BODY, and HEADS are parameters to `defhydra'. +Works for heads without a property :column." + (let (alist) + (dolist (h heads) + (let ((val (assoc (cadr h) alist)) + (pstr (hydra-fontify-head h body))) + (unless (not (stringp (cl-caddr h))) + (if val + (setf (cadr val) + (concat (cadr val) " " pstr)) + (push + (cons (cadr h) + (cons pstr (cl-caddr h))) + alist))))) + (let ((keys (nreverse (mapcar #'cdr alist))) + (n-cols (plist-get (cddr body) :columns)) + res) + (setq res + (if n-cols + (let ((n-rows (1+ (/ (length keys) n-cols))) + (max-key-len (apply #'max (mapcar (lambda (x) (length (car x))) keys))) + (max-doc-len (apply #'max (mapcar (lambda (x) + (length (hydra--to-string (cdr x)))) keys)))) + `(concat + "\n" + (mapconcat #'identity + (mapcar + (lambda (x) + (mapconcat + (lambda (y) + (and y + (funcall hydra-key-doc-function + (car y) + ,max-key-len + (hydra--to-string (cdr y)) + ,max-doc-len))) x "")) + ',(hydra--matrix keys n-cols n-rows)) + "\n"))) + + + `(concat + (mapconcat + (lambda (x) + (let ((str (hydra--to-string (cdr x)))) + (format + (if (> (length str) 0) + (concat hydra-head-format str) + "%s") + (car x)))) + ',keys + ", ") + ,(if keys "." "")))) + (if (cl-every #'stringp + (mapcar 'cddr alist)) + (eval res) + res)))) + +(defun hydra--hint (body heads) + "Generate a hint for the echo area. +BODY, and HEADS are parameters to `defhydra'." + (let* ((sorted-heads (hydra--sort-heads (hydra--normalize-heads heads))) + (heads-w-col (cl-remove-if-not (lambda (heads) (hydra--head-property (nth 0 heads) :column)) sorted-heads)) + (heads-wo-col (cl-remove-if (lambda (heads) (hydra--head-property (nth 0 heads) :column)) sorted-heads))) + (concat (when heads-w-col + (concat "\n" (hydra--hint-from-matrix body (hydra--generate-matrix heads-w-col)))) + (when heads-wo-col + (hydra--hint-heads-wocol body (car heads-wo-col)))))) + +(defvar hydra-fontify-head-function nil + "Possible replacement for `hydra-fontify-head-default'.") + +(defun hydra-fontify-head-default (head body) + "Produce a pretty string from HEAD and BODY. +HEAD's binding is returned as a string with a colored face." + (let* ((foreign-keys (hydra--body-foreign-keys body)) + (head-exit (hydra--head-property head :exit)) + (head-color + (if head-exit + (if (eq foreign-keys 'warn) + 'teal + 'blue) + (cl-case foreign-keys + (warn 'amaranth) + (run 'pink) + (t 'red))))) + (when (and (null (cadr head)) + (not head-exit)) + (hydra--complain "nil cmd can only be blue")) + (propertize + (replace-regexp-in-string "%" "%%" (car head)) + 'face + (or (hydra--head-property head :face) + (cl-case head-color + (blue 'hydra-face-blue) + (red 'hydra-face-red) + (amaranth 'hydra-face-amaranth) + (pink 'hydra-face-pink) + (teal 'hydra-face-teal) + (t (error "Unknown color for %S" head))))))) + +(defun hydra-fontify-head-greyscale (head _body) + "Produce a pretty string from HEAD and BODY. +HEAD's binding is returned as a string wrapped with [] or {}." + (format + (if (hydra--head-property head :exit) + "[%s]" + "{%s}") (car head))) + +(defun hydra-fontify-head (head body) + "Produce a pretty string from HEAD and BODY." + (funcall (or hydra-fontify-head-function 'hydra-fontify-head-default) + head body)) + +(defun hydra--strip-align-markers (str) + "Remove ^ from STR, unless they're escaped: \\^." + (let ((start 0)) + (while (setq start (string-match "\\\\?\\^" str start)) + (if (eq (- (match-end 0) (match-beginning 0)) 2) + (progn + (setq str (replace-match "^" nil nil str)) + (cl-incf start)) + (setq str (replace-match "" nil nil str)))) + str)) + +(defvar hydra-docstring-keys-translate-alist + '(("↑" . "") + ("↓" . "") + ("→" . "") + ("←" . "") + ("⌫" . "DEL") + ("⌦" . "") + ("⏎" . "RET"))) + +(defconst hydra-width-spec-regex " ?-?[0-9]*?" + "Regex for the width spec in keys and %` quoted sexps.") + +(defvar hydra-key-regex "\\[\\|]\\|[-[:alnum:] ~.,;:/|?<>={}*+#%@!&^↑↓←→⌫⌦⏎'`()\"$]+?" + "Regex for the key quoted in the docstring.") + +(defun hydra--format (_name body docstring heads) + "Generate a `format' statement from STR. +\"%`...\" expressions are extracted into \"%S\". +_NAME, BODY, DOCSTRING and HEADS are parameters of `defhydra'. +The expressions can be auto-expanded according to NAME." + (setq docstring (hydra--strip-align-markers docstring)) + (setq docstring (replace-regexp-in-string "___" "_β_" docstring)) + (let ((rest (if (eq (plist-get (cddr body) :hint) 'none) + "" + (hydra--hint body heads))) + (start 0) + varlist + offset) + (while (setq start + (string-match + (format + "\\(?:%%\\( ?-?[0-9]*s?\\)\\(`[a-z-A-Z/0-9]+\\|(\\)\\)\\|\\(?:[_?]\\(%s\\)\\(%s\\)[_?]\\)" + hydra-width-spec-regex + hydra-key-regex) + docstring start)) + (cond ((eq ?? (aref (match-string 0 docstring) 0)) + (let* ((key (match-string 4 docstring)) + (head (assoc key heads))) + (if head + (progn + (push (nth 2 head) varlist) + (setq docstring + (replace-match + (or + hydra-doc-format-spec + (concat "%" (match-string 3 docstring) "s")) + t nil docstring))) + (setq start (match-end 0)) + (warn "Unrecognized key: ?%s?" key)))) + ((eq ?_ (aref (match-string 0 docstring) 0)) + (let* ((key (match-string 4 docstring)) + (key (if (equal key "β") "_" key)) + normal-key + (head (or (assoc key heads) + (when (setq normal-key + (cdr (assoc + key hydra-docstring-keys-translate-alist))) + (assoc normal-key heads))))) + (if head + (progn + (push (hydra-fontify-head (if normal-key + (cons key (cdr head)) + head) + body) + varlist) + (let ((replacement + (or + hydra-key-format-spec + (concat "%" (match-string 3 docstring) "s")))) + (setq docstring + (replace-match replacement t nil docstring)) + (setq start (+ start (length replacement))))) + (setq start (match-end 0)) + (warn "Unrecognized key: _%s_" key)))) + + (t + (let* ((varp (if (eq ?` (aref (match-string 2 docstring) 0)) 1 0)) + (spec (match-string 1 docstring)) + (lspec (length spec))) + (setq offset + (with-temp-buffer + (insert (substring docstring (+ 1 start varp + (length spec)))) + (goto-char (point-min)) + (push (read (current-buffer)) varlist) + (- (point) (point-min)))) + (when (or (zerop lspec) + (/= (aref spec (1- (length spec))) ?s)) + (setq spec (concat spec "S"))) + (setq docstring + (concat + (substring docstring 0 start) + "%" spec + (substring docstring (+ start offset 1 lspec varp)))))))) + (if (eq ?\n (aref docstring 0)) + `(concat (format ,(substring docstring 1) ,@(nreverse varlist)) + ,rest) + (let ((r `(replace-regexp-in-string + " +$" "" + (concat ,docstring ": " + (replace-regexp-in-string + "\\(%\\)" "\\1\\1" ,rest))))) + (if (stringp rest) + `(format ,(eval r)) + `(format ,r)))))) + +(defun hydra--complain (format-string &rest args) + "Forward to (`message' FORMAT-STRING ARGS) unless `hydra-verbose' is nil." + (if hydra-verbose + (apply #'error format-string args) + (apply #'message format-string args))) + +(defun hydra--doc (body-key body-name heads) + "Generate a part of Hydra docstring. +BODY-KEY is the body key binding. +BODY-NAME is the symbol that identifies the Hydra. +HEADS is a list of heads." + (format + "Create a hydra with %s body and the heads:\n\n%s\n\n%s" + (if body-key + (format "a \"%s\"" body-key) + "no") + (mapconcat + (lambda (x) + (format "\"%s\": `%S'" (car x) (cadr x))) + heads ",\n") + (format "The body can be accessed via `%S'." body-name))) + +(defun hydra--call-interactively-remap-maybe (cmd) + "`call-interactively' the given CMD or its remapped equivalent. +Only when `hydra-look-for-remap' is non nil." + (let ((remapped-cmd (if hydra-look-for-remap + (command-remapping `,cmd) + nil))) + (if remapped-cmd + (call-interactively `,remapped-cmd) + (call-interactively `,cmd)))) + +(defun hydra--call-interactively (cmd name) + "Generate a `call-interactively' statement for CMD. +Set `this-command' to NAME." + (if (and (symbolp name) + (not (memq name '(nil body)))) + `(progn + (setq this-command ',name) + (hydra--call-interactively-remap-maybe #',cmd)) + `(hydra--call-interactively-remap-maybe #',cmd))) + +(defun hydra--make-defun (name body doc head + keymap body-pre body-before-exit + &optional body-after-exit) + "Make a defun wrapper, using NAME, BODY, DOC, HEAD, and KEYMAP. +NAME and BODY are the arguments to `defhydra'. +DOC was generated with `hydra--doc'. +HEAD is one of the HEADS passed to `defhydra'. +BODY-PRE is added to the start of the wrapper. +BODY-BEFORE-EXIT will be called before the hydra quits. +BODY-AFTER-EXIT is added to the end of the wrapper." + (let ((cmd-name (hydra--head-name head name)) + (cmd (when (car head) + (hydra--make-callable + (cadr head)))) + (doc (if (car head) + (format "%s\n\nCall the head: `%S'." doc (cadr head)) + doc)) + (hint (intern (format "%S/hint" name))) + (body-foreign-keys (hydra--body-foreign-keys body)) + (body-timeout (plist-get body :timeout)) + (body-idle (plist-get body :idle))) + `(defun ,cmd-name () + ,doc + (interactive) + (hydra-default-pre) + ,@(when body-pre (list body-pre)) + ,@(if (hydra--head-property head :exit) + `((hydra-keyboard-quit) + (setq hydra-curr-body-fn ',(intern (format "%S/body" name))) + ,@(if body-after-exit + `((unwind-protect + ,(when cmd + (hydra--call-interactively cmd (cadr head))) + ,body-after-exit)) + (when cmd + `(,(hydra--call-interactively cmd (cadr head)))))) + (delq + nil + `((let ((hydra--ignore ,(not (eq (cadr head) 'body)))) + (hydra-keyboard-quit) + (setq hydra-curr-body-fn ',(intern (format "%S/body" name)))) + ,(when cmd + `(condition-case err + ,(hydra--call-interactively cmd (cadr head)) + ((quit error) + (message (error-message-string err)) + (unless hydra-lv + (sit-for 0.8))))) + ,(if (and body-idle (eq (cadr head) 'body)) + `(hydra-idle-message ,body-idle ,hint ',name) + `(hydra-show-hint ,hint ',name)) + (hydra-set-transient-map + ,keymap + (lambda () (hydra-keyboard-quit) ,body-before-exit) + ,(when body-foreign-keys + (list 'quote body-foreign-keys))) + ,body-after-exit + ,(when body-timeout + `(hydra-timeout ,body-timeout)))))))) + +(defvar hydra-props-alist nil) + +(defun hydra-set-property (name key val) + "Set hydra property. +NAME is the symbolic name of the hydra. +KEY and VAL are forwarded to `plist-put'." + (let ((entry (assoc name hydra-props-alist)) + plist) + (when (null entry) + (add-to-list 'hydra-props-alist (list name)) + (setq entry (assoc name hydra-props-alist))) + (setq plist (cdr entry)) + (setcdr entry (plist-put plist key val)))) + +(defun hydra-get-property (name key) + "Get hydra property. +NAME is the symbolic name of the hydra. +KEY is forwarded to `plist-get'." + (let ((entry (assoc name hydra-props-alist))) + (when entry + (plist-get (cdr entry) key)))) + +(defun hydra-show-hint (hint caller) + (let ((verbosity (plist-get (cdr (assoc caller hydra-props-alist)) + :verbosity))) + (cond ((eq verbosity 0)) + ((eq verbosity 1) + (message (eval hint))) + (t + (when hydra-is-helpful + (if hydra-lv + (lv-message (eval hint)) + (message (eval hint)))))))) + +(defmacro hydra--make-funcall (sym) + "Transform SYM into a `funcall' to call it." + `(when (and ,sym (symbolp ,sym)) + (setq ,sym `(funcall #',,sym)))) + +(defun hydra--head-name (h name) + "Return the symbol for head H of hydra with NAME." + (let ((str (format "%S/%s" name + (cond ((symbolp (cadr h)) + (cadr h)) + ((and (consp (cadr h)) + (eq (cl-caadr h) 'function)) + (cadr (cadr h))) + (t + (concat "lambda-" (car h))))))) + (when (and (hydra--head-property h :exit) + (not (memq (cadr h) '(body nil)))) + (setq str (concat str "-and-exit"))) + (intern str))) + +(defun hydra--delete-duplicates (heads) + "Return HEADS without entries that have the same CMD part. +In duplicate HEADS, :cmd-name is modified to whatever they duplicate." + (let ((ali '(((hydra-repeat . nil) . hydra-repeat))) + res entry) + (dolist (h heads) + (if (setq entry (assoc (cons (cadr h) + (hydra--head-property h :exit)) + ali)) + (setf (cl-cdddr h) (plist-put (cl-cdddr h) :cmd-name (cdr entry))) + (push (cons (cons (cadr h) + (hydra--head-property h :exit)) + (plist-get (cl-cdddr h) :cmd-name)) + ali) + (push h res))) + (nreverse res))) + +(defun hydra--pad (lst n) + "Pad LST with nil until length N." + (let ((len (length lst))) + (if (= len n) + lst + (append lst (make-list (- n len) nil))))) + +(defmacro hydra-multipop (lst n) + "Return LST's first N elements while removing them." + `(if (<= (length ,lst) ,n) + (prog1 ,lst + (setq ,lst nil)) + (prog1 ,lst + (setcdr + (nthcdr (1- ,n) (prog1 ,lst (setq ,lst (nthcdr ,n ,lst)))) + nil)))) + +(defun hydra--matrix (lst rows cols) + "Create a matrix from elements of LST. +The matrix size is ROWS times COLS." + (let ((ls (copy-sequence lst)) + res) + (dotimes (_c cols) + (push (hydra--pad (hydra-multipop ls rows) rows) res)) + (nreverse res))) + +(defun hydra--cell (fstr names) + "Format a rectangular cell based on FSTR and NAMES. +FSTR is a format-style string with two string inputs: one for the +doc and one for the symbol name. +NAMES is a list of variables." + (let ((len (cl-reduce + (lambda (acc it) (max (length (symbol-name it)) acc)) + names + :initial-value 0))) + (mapconcat + (lambda (sym) + (if sym + (format fstr + (documentation-property sym 'variable-documentation) + (let ((name (symbol-name sym))) + (concat name (make-string (- len (length name)) ?^))) + sym) + "")) + names + "\n"))) + +(defun hydra--vconcat (strs &optional joiner) + "Glue STRS vertically. They must be the same height. +JOINER is a function similar to `concat'." + (setq joiner (or joiner #'concat)) + (mapconcat + (lambda (s) + (if (string-match " +$" s) + (replace-match "" nil nil s) + s)) + (apply #'cl-mapcar joiner + (mapcar + (lambda (s) (split-string s "\n")) + strs)) + "\n")) + +(defvar hydra-cell-format "% -20s %% -8`%s" + "The default format for docstring cells.") + +(defun hydra--table (names rows cols &optional cell-formats) + "Format a `format'-style table from variables in NAMES. +The size of the table is ROWS times COLS. +CELL-FORMATS are `format' strings for each column. +If CELL-FORMATS is a string, it's used for all columns. +If CELL-FORMATS is nil, `hydra-cell-format' is used for all columns." + (setq cell-formats + (cond ((null cell-formats) + (make-list cols hydra-cell-format)) + ((stringp cell-formats) + (make-list cols cell-formats)) + (t + cell-formats))) + (hydra--vconcat + (cl-mapcar + #'hydra--cell + cell-formats + (hydra--matrix names rows cols)) + (lambda (&rest x) + (mapconcat #'identity x " ")))) + +(defun hydra-reset-radios (names) + "Set varibles NAMES to their defaults. +NAMES should be defined by `defhydradio' or similar." + (dolist (n names) + (set n (aref (get n 'range) 0)))) + +;; Following functions deal with automatic docstring table generation from :column head property +(defun hydra--normalize-heads (heads) + "Ensure each head from HEADS have a property :column. +Set it to the same value as preceding head or nil if no previous value +was defined." + (let ((current-col nil)) + (mapcar (lambda (head) + (if (hydra--head-has-property head :column) + (setq current-col (hydra--head-property head :column))) + (hydra--head-set-property head :column current-col)) + heads))) + +(defun hydra--sort-heads (normalized-heads) + "Return a list of heads with non-nil doc grouped by column property. +Each head of NORMALIZED-HEADS must have a column property." + (let* ((heads-wo-nil-doc (cl-remove-if-not (lambda (head) (nth 2 head)) normalized-heads)) + (columns-list (delete-dups (mapcar (lambda (head) (hydra--head-property head :column)) + normalized-heads))) + (get-col-index-fun (lambda (head) (cl-position (hydra--head-property head :column) + columns-list + :test 'equal))) + (heads-sorted (cl-sort heads-wo-nil-doc (lambda (it other) + (< (funcall get-col-index-fun it) + (funcall get-col-index-fun other)))))) + ;; this operation partition the sorted head list into lists of heads with same column property + (cl-loop for head in heads-sorted + for column-name = (hydra--head-property head :column) + with prev-column-name = (hydra--head-property (nth 0 heads-sorted) :column) + unless (equal prev-column-name column-name) collect heads-one-column into heads-all-columns + and do (setq heads-one-column nil) + collect head into heads-one-column + do (setq prev-column-name column-name) + finally return (append heads-all-columns (list heads-one-column))))) + +(defun hydra--pad-heads (heads-groups padding-head) + "Return a copy of HEADS-GROUPS padded where applicable with PADDING-HEAD." + (cl-loop for heads-group in heads-groups + for this-head-group-length = (length heads-group) + with head-group-max-length = (apply #'max (mapcar (lambda (heads) (length heads)) heads-groups)) + if (<= this-head-group-length head-group-max-length) + collect (append heads-group (make-list (- head-group-max-length this-head-group-length) padding-head)) + into balanced-heads-groups + else collect heads-group into balanced-heads-groups + finally return balanced-heads-groups)) + +(defun hydra--generate-matrix (heads-groups) + "Return a copy of HEADS-GROUPS decorated with table formating information. +Details of modification: +2 virtual heads acting as table header were added to each heads-group. +Each head is decorated with 2 new properties max-doc-len and max-key-len +representing the maximum dimension of their owning group. + Every heads-group have equal length by adding padding heads where applicable." + (when heads-groups + (cl-loop for heads-group in (hydra--pad-heads heads-groups '(" " nil " " :exit t)) + for column-name = (hydra--head-property (nth 0 heads-group) :column) + for max-key-len = (apply #'max (mapcar (lambda (x) (length (car x))) heads-group)) + for max-doc-len = (apply #'max + (length column-name) + (mapcar (lambda (x) (length (hydra--to-string (nth 2 x)))) heads-group)) + for header-virtual-head = `(" " nil ,column-name :column ,column-name :exit t) + for separator-virtual-head = `(" " nil ,(make-string (+ 2 max-doc-len max-key-len) ?-) :column ,column-name :exit t) + for decorated-heads = (copy-tree (apply 'list header-virtual-head separator-virtual-head heads-group)) + collect (mapcar (lambda (it) + (hydra--head-set-property it :max-key-len max-key-len) + (hydra--head-set-property it :max-doc-len max-doc-len)) + decorated-heads) + into decorated-heads-matrix + finally return decorated-heads-matrix))) + +(defun hydra--hint-from-matrix (body heads-matrix) + "Generate a formated table-style docstring according to BODY and HEADS-MATRIX. +HEADS-MATRIX is expected to be a list of heads with following features: +Each heads must have the same length +Each head must have a property max-key-len and max-doc-len." + (when heads-matrix + (cl-loop with first-heads-col = (nth 0 heads-matrix) + with last-row-index = (- (length first-heads-col) 1) + for row-index from 0 to last-row-index + for heads-in-row = (mapcar (lambda (heads) (nth row-index heads)) heads-matrix) + concat (concat + (replace-regexp-in-string "\s+$" "" + (mapconcat (lambda (head) + (funcall hydra-key-doc-function + (hydra-fontify-head head body) ;; key + (hydra--head-property head :max-key-len) + (nth 2 head) ;; doc + (hydra--head-property head :max-doc-len))) + heads-in-row "| ")) "\n") + into matrix-image + finally return matrix-image))) +;; previous functions dealt with automatic docstring table generation from :column head property + +(defun hydra-idle-message (secs hint name) + "In SECS seconds display HINT." + (cancel-timer hydra-message-timer) + (setq hydra-message-timer (timer-create)) + (timer-set-time hydra-message-timer + (timer-relative-time (current-time) secs)) + (timer-set-function + hydra-message-timer + (lambda () + (hydra-show-hint hint name) + (cancel-timer hydra-message-timer))) + (timer-activate hydra-message-timer)) + +(defun hydra-timeout (secs &optional function) + "In SECS seconds call FUNCTION, then function `hydra-keyboard-quit'. +Cancel the previous `hydra-timeout'." + (cancel-timer hydra-timeout-timer) + (setq hydra-timeout-timer (timer-create)) + (timer-set-time hydra-timeout-timer + (timer-relative-time (current-time) secs)) + (timer-set-function + hydra-timeout-timer + `(lambda () + ,(when function + `(funcall ,function)) + (hydra-keyboard-quit))) + (timer-activate hydra-timeout-timer)) + +;;* Macros +;;;###autoload +(defmacro defhydra (name body &optional docstring &rest heads) + "Create a Hydra - a family of functions with prefix NAME. + +NAME should be a symbol, it will be the prefix of all functions +defined here. + +BODY has the format: + + (BODY-MAP BODY-KEY &rest BODY-PLIST) + +DOCSTRING will be displayed in the echo area to identify the +Hydra. When DOCSTRING starts with a newline, special Ruby-style +substitution will be performed by `hydra--format'. + +Functions are created on basis of HEADS, each of which has the +format: + + (KEY CMD &optional HINT &rest PLIST) + +BODY-MAP is a keymap; `global-map' is used quite often. Each +function generated from HEADS will be bound in BODY-MAP to +BODY-KEY + KEY (both are strings passed to `kbd'), and will set +the transient map so that all following heads can be called +though KEY only. BODY-KEY can be an empty string. + +CMD is a callable expression: either an interactive function +name, or an interactive lambda, or a single sexp (it will be +wrapped in an interactive lambda). + +HINT is a short string that identifies its head. It will be +printed beside KEY in the echo erea if `hydra-is-helpful' is not +nil. If you don't even want the KEY to be printed, set HINT +explicitly to nil. + +The heads inherit their PLIST from BODY-PLIST and are allowed to +override some keys. The keys recognized are :exit and :bind. +:exit can be: + +- nil (default): this head will continue the Hydra state. +- t: this head will stop the Hydra state. + +:bind can be: +- nil: this head will not be bound in BODY-MAP. +- a lambda taking KEY and CMD used to bind a head. + +It is possible to omit both BODY-MAP and BODY-KEY if you don't +want to bind anything. In that case, typically you will bind the +generated NAME/body command. This command is also the return +result of `defhydra'." + (declare (indent defun) (doc-string 3)) + (setq heads (copy-tree heads)) + (cond ((stringp docstring)) + ((and (consp docstring) + (memq (car docstring) '(hydra--table concat format))) + (setq docstring (concat "\n" (eval docstring)))) + (t + (setq heads (cons docstring heads)) + (setq docstring "hydra"))) + (when (keywordp (car body)) + (setq body (cons nil (cons nil body)))) + (condition-case-unless-debug err + (let* ((keymap (copy-keymap hydra-base-map)) + (keymap-name (intern (format "%S/keymap" name))) + (body-name (intern (format "%S/body" name))) + (body-key (cadr body)) + (body-plist (cddr body)) + (body-map (or (car body) + (plist-get body-plist :bind))) + (body-pre (plist-get body-plist :pre)) + (body-body-pre (plist-get body-plist :body-pre)) + (body-before-exit (or (plist-get body-plist :post) + (plist-get body-plist :before-exit))) + (body-after-exit (plist-get body-plist :after-exit)) + (body-inherit (plist-get body-plist :inherit)) + (body-foreign-keys (hydra--body-foreign-keys body)) + (body-exit (hydra--body-exit body))) + (dolist (base body-inherit) + (setq heads (append heads (copy-sequence (eval base))))) + (dolist (h heads) + (let ((len (length h))) + (cond ((< len 2) + (error "Each head should have at least two items: %S" h)) + ((= len 2) + (setcdr (cdr h) + (list + (hydra-plist-get-default + body-plist :hint hydra-default-hint))) + (setcdr (nthcdr 2 h) (list :exit body-exit))) + (t + (let ((hint (cl-caddr h))) + (unless (or (null hint) + (stringp hint) + (consp hint)) + (let ((inherited-hint + (hydra-plist-get-default + body-plist :hint hydra-default-hint))) + (setcdr (cdr h) (cons + (if (eq 'none inherited-hint) + nil + inherited-hint) + (cddr h)))))) + (let ((hint-and-plist (cddr h))) + (if (null (cdr hint-and-plist)) + (setcdr hint-and-plist (list :exit body-exit)) + (let* ((plist (cl-cdddr h)) + (h-color (plist-get plist :color))) + (if h-color + (progn + (plist-put plist :exit + (cl-case h-color + ((blue teal) t) + (t nil))) + (cl-remf (cl-cdddr h) :color)) + (let ((h-exit (hydra-plist-get-default plist :exit 'default))) + (plist-put plist :exit + (if (eq h-exit 'default) + body-exit + h-exit)))))))))) + (plist-put (cl-cdddr h) :cmd-name (hydra--head-name h name)) + (when (null (cadr h)) (plist-put (cl-cdddr h) :exit t))) + (let ((doc (hydra--doc body-key body-name heads)) + (heads-nodup (hydra--delete-duplicates heads))) + (mapc + (lambda (x) + (define-key keymap (kbd (car x)) + (plist-get (cl-cdddr x) :cmd-name))) + heads) + (hydra--make-funcall body-pre) + (hydra--make-funcall body-body-pre) + (hydra--make-funcall body-before-exit) + (hydra--make-funcall body-after-exit) + (when (memq body-foreign-keys '(run warn)) + (unless (cl-some + (lambda (h) + (hydra--head-property h :exit)) + heads) + (error + "An %S Hydra must have at least one blue head in order to exit" + body-foreign-keys))) + `(progn + ;; create keymap + (set (defvar ,keymap-name + nil + ,(format "Keymap for %S." name)) + ',keymap) + ;; declare heads + (set (defvar ,(intern (format "%S/heads" name)) + nil + ,(format "Heads for %S." name)) + ',(mapcar (lambda (h) + (let ((j (copy-sequence h))) + (cl-remf (cl-cdddr j) :cmd-name) + j)) + heads)) + (set + (defvar ,(intern (format "%S/hint" name)) nil + ,(format "Dynamic hint for %S." name)) + ',(hydra--format name body docstring heads)) + ;; create defuns + ,@(mapcar + (lambda (head) + (hydra--make-defun name body doc head keymap-name + body-pre + body-before-exit + body-after-exit)) + heads-nodup) + ;; free up keymap prefix + ,@(unless (or (null body-key) + (null body-map) + (hydra--callablep body-map)) + `((unless (keymapp (lookup-key ,body-map (kbd ,body-key))) + (define-key ,body-map (kbd ,body-key) nil)))) + ;; bind keys + ,@(delq nil + (mapcar + (lambda (head) + (let ((name (hydra--head-property head :cmd-name))) + (when (and (cadr head) + (or body-key body-map)) + (let ((bind (hydra--head-property head :bind body-map)) + (final-key + (if body-key + (vconcat (kbd body-key) (kbd (car head))) + (kbd (car head))))) + (cond ((null bind) nil) + ((hydra--callablep bind) + `(funcall ,bind ,final-key (function ,name))) + ((and (symbolp bind) + (if (boundp bind) + (keymapp (symbol-value bind)) + t)) + `(define-key ,bind ,final-key (quote ,name))) + (t + (error "Invalid :bind property `%S' for head %S" bind head))))))) + heads)) + ,(hydra--make-defun + name body doc '(nil body) + keymap-name + (or body-body-pre body-pre) body-before-exit + '(setq prefix-arg current-prefix-arg))))) + (error + (hydra--complain "Error in defhydra %S: %s" name (cdr err)) + nil))) + +(defmacro defhydradio (name _body &rest heads) + "Create radios with prefix NAME. +_BODY specifies the options; there are none currently. +HEADS have the format: + + (TOGGLE-NAME &optional VALUE DOC) + +TOGGLE-NAME will be used along with NAME to generate a variable +name and a function that cycles it with the same name. VALUE +should be an array. The first element of VALUE will be used to +inialize the variable. +VALUE defaults to [nil t]. +DOC defaults to TOGGLE-NAME split and capitalized." + (declare (indent defun)) + `(progn + ,@(apply #'append + (mapcar (lambda (h) + (hydra--radio name h)) + heads)) + (defvar ,(intern (format "%S/names" name)) + ',(mapcar (lambda (h) (intern (format "%S/%S" name (car h)))) + heads)))) + +(defun hydra--radio (parent head) + "Generate a hydradio with PARENT from HEAD." + (let* ((name (car head)) + (full-name (intern (format "%S/%S" parent name))) + (doc (cadr head)) + (val (or (cl-caddr head) [nil t]))) + `((defvar ,full-name ,(hydra--quote-maybe (aref val 0)) ,doc) + (put ',full-name 'range ,val) + (defun ,full-name () + (hydra--cycle-radio ',full-name))))) + +(defun hydra--quote-maybe (x) + "Quote X if it's a symbol." + (cond ((null x) + nil) + ((symbolp x) + (list 'quote x)) + (t + x))) + +(defun hydra--cycle-radio (sym) + "Set SYM to the next value in its range." + (let* ((val (symbol-value sym)) + (range (get sym 'range)) + (i 0) + (l (length range))) + (setq i (catch 'done + (while (< i l) + (if (equal (aref range i) val) + (throw 'done (1+ i)) + (cl-incf i))) + (error "Val not in range for %S" sym))) + (set sym + (aref range + (if (>= i l) + 0 + i))))) + +(defvar hydra-pause-ring (make-ring 10) + "Ring for paused hydras.") + +(defun hydra-pause-resume () + "Quit the current hydra and save it to the stack. +If there's no active hydra, pop one from the stack and call its body. +If the stack is empty, call the last hydra's body." + (interactive) + (cond (hydra-curr-map + (ring-insert hydra-pause-ring hydra-curr-body-fn) + (hydra-keyboard-quit)) + ((zerop (ring-length hydra-pause-ring)) + (funcall hydra-curr-body-fn)) + (t + (funcall (ring-remove hydra-pause-ring 0))))) + +;; Local Variables: +;; outline-regexp: ";;\\([;*]+ [^\s\t\n]\\|###autoload\\)\\|(" +;; indent-tabs-mode: nil +;; End: + +(provide 'hydra) + +;;; hydra.el ends here diff --git a/elpa/hydra-20170813.1058/lv.el b/elpa/hydra-20170813.1058/lv.el new file mode 100644 index 0000000..87f7e5e --- /dev/null +++ b/elpa/hydra-20170813.1058/lv.el @@ -0,0 +1,117 @@ +;;; lv.el --- Other echo area + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Oleh Krehel + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: +;; +;; This package provides `lv-message' intended to be used in place of +;; `message' when semi-permanent hints are needed, in order to not +;; interfere with Echo Area. +;; +;; "Я тихо-тихо пiдглядаю, +;; І тiшуся собi, як бачу то, +;; Шо страшить i не пiдпускає, +;; А iншi п’ють тебе, як воду пiсок." +;; -- Андрій Кузьменко, L.V. + +;;; Code: + +(defgroup lv nil + "The other echo area." + :group 'minibuffer + :group 'hydra) + +(defcustom lv-use-separator nil + "Whether to draw a line between the LV window and the Echo Area." + :group 'lv + :type 'boolean) + +(defface lv-separator + '((((class color) (background light)) :background "grey80") + (((class color) (background dark)) :background "grey30")) + "Face used to draw line between the lv window and the echo area. +This is only used if option `lv-use-separator' is non-nil. +Only the background color is significant." + :group 'lv) + +(defvar lv-wnd nil + "Holds the current LV window.") + +(defun lv-window () + "Ensure that LV window is live and return it." + (if (window-live-p lv-wnd) + lv-wnd + (let ((ori (selected-window)) + buf) + (prog1 (setq lv-wnd + (select-window + (let ((ignore-window-parameters t)) + (split-window + (frame-root-window) -1 'below)))) + (if (setq buf (get-buffer " *LV*")) + (switch-to-buffer buf) + (switch-to-buffer " *LV*") + (set-window-hscroll lv-wnd 0) + (setq window-size-fixed t) + (setq mode-line-format nil) + (setq cursor-type nil) + (set-window-dedicated-p lv-wnd t) + (set-window-parameter lv-wnd 'no-other-window t)) + (select-window ori))))) + +(defvar golden-ratio-mode) + +(defvar lv-force-update nil + "When non-nil, `lv-message' will refresh even for the same string.") + +(defun lv-message (format-string &rest args) + "Set LV window contents to (`format' FORMAT-STRING ARGS)." + (let* ((str (apply #'format format-string args)) + (n-lines (cl-count ?\n str)) + deactivate-mark + golden-ratio-mode) + (with-selected-window (lv-window) + (unless (and (string= (buffer-string) str) + (null lv-force-update)) + (delete-region (point-min) (point-max)) + (insert str) + (when (and (window-system) lv-use-separator) + (unless (looking-back "\n" nil) + (insert "\n")) + (insert + (propertize "__" 'face 'lv-separator 'display '(space :height (1))) + (propertize "\n" 'face 'lv-separator 'line-height t))) + (set (make-local-variable 'window-min-height) n-lines) + (setq truncate-lines (> n-lines 1)) + (let ((window-resize-pixelwise t) + (window-size-fixed nil)) + (fit-window-to-buffer nil nil 1))) + (goto-char (point-min))))) + +(defun lv-delete-window () + "Delete LV window and kill its buffer." + (when (window-live-p lv-wnd) + (let ((buf (window-buffer lv-wnd))) + (delete-window lv-wnd) + (kill-buffer buf)))) + +(provide 'lv) + +;;; lv.el ends here diff --git a/elpa/multiple-cursors-20170813.38/mc-cycle-cursors.el b/elpa/multiple-cursors-20170813.38/mc-cycle-cursors.el new file mode 100644 index 0000000..85af352 --- /dev/null +++ b/elpa/multiple-cursors-20170813.38/mc-cycle-cursors.el @@ -0,0 +1,119 @@ +;;; mc-cycle-cursors.el + +;; Copyright (C) 2012-2016 Magnar Sveen + +;; Author: Magnar Sveen +;; Keywords: editing cursors + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This scrolls the buffer to center each cursor in turn. +;; Scroll down with C-v, scroll up with M-v +;; This is nice when you have cursors that's outside of your view. + +;;; Code: + +(require 'multiple-cursors-core) + +(defun mc/next-fake-cursor-after-point () + (let ((pos (point)) + (next-pos (1+ (point-max))) + next) + (mc/for-each-fake-cursor + (let ((cursor-pos (overlay-get cursor 'point))) + (when (and (< pos cursor-pos) + (< cursor-pos next-pos)) + (setq next-pos cursor-pos) + (setq next cursor)))) + next)) + +(defun mc/prev-fake-cursor-before-point () + (let ((pos (point)) + (prev-pos (1- (point-min))) + prev) + (mc/for-each-fake-cursor + (let ((cursor-pos (overlay-get cursor 'point))) + (when (and (> pos cursor-pos) + (> cursor-pos prev-pos)) + (setq prev-pos cursor-pos) + (setq prev cursor)))) + prev)) + +(defcustom mc/cycle-looping-behaviour 'continue + "What to do if asked to cycle beyond the last cursor or before the first cursor." + :type '(radio (const :tag "Loop around to beginning/end of document." continue) + (const :tag "Warn and then loop around." warn) + (const :tag "Signal an error." error) + (const :tag "Don't loop." stop)) + :group 'multiple-cursors) + +(defun mc/handle-loop-condition (error-message) + (cl-ecase mc/cycle-looping-behaviour + (error (error error-message)) + (warn (message error-message)) + (continue 'continue) + (stop 'stop))) + +(defun mc/first-fake-cursor-after (point) + "Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)." + (let* ((cursors (mc/all-fake-cursors)) + (cursors-after-point (cl-remove-if (lambda (cursor) + (< (mc/cursor-beg cursor) point)) + cursors)) + (cursors-in-order (cl-sort cursors-after-point '< :key 'mc/cursor-beg))) + (car cursors-in-order))) + +(defun mc/last-fake-cursor-before (point) + "Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)." + (let* ((cursors (mc/all-fake-cursors)) + (cursors-before-point (cl-remove-if (lambda (cursor) + (> (mc/cursor-end cursor) point)) + cursors)) + (cursors-in-order (cl-sort cursors-before-point '> :key 'mc/cursor-end))) + (car cursors-in-order))) + +(cl-defun mc/cycle (next-cursor fallback-cursor loop-message) + (when (null next-cursor) + (when (eql 'stop (mc/handle-loop-condition loop-message)) + (return-from mc/cycle nil)) + (setf next-cursor fallback-cursor)) + (mc/create-fake-cursor-at-point) + (mc/pop-state-from-overlay next-cursor) + (recenter)) + +(defun mc/cycle-forward () + (interactive) + (mc/cycle (mc/next-fake-cursor-after-point) + (mc/first-fake-cursor-after (point-min)) + "We're already at the last cursor.")) + +(defun mc/cycle-backward () + (interactive) + (mc/cycle (mc/prev-fake-cursor-before-point) + (mc/last-fake-cursor-before (point-max)) + "We're already at the last cursor")) + +(define-key mc/keymap (kbd "C-v") 'mc/cycle-forward) +(define-key mc/keymap (kbd "M-v") 'mc/cycle-backward) + +(provide 'mc-cycle-cursors) + + +;; Local Variables: +;; coding: utf-8 +;; End: + +;;; mc-cycle-cursors.el ends here diff --git a/elpa/multiple-cursors-20170813.38/mc-edit-lines.el b/elpa/multiple-cursors-20170813.38/mc-edit-lines.el new file mode 100644 index 0000000..e38d1c1 --- /dev/null +++ b/elpa/multiple-cursors-20170813.38/mc-edit-lines.el @@ -0,0 +1,110 @@ +;;; mc-edit-lines.el + +;; Copyright (C) 2012-2016 Magnar Sveen + +;; Author: Magnar Sveen +;; Keywords: editing cursors + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This file contains functions to add multiple cursors to consecutive lines +;; given an active region. + +;; Please see multiple-cursors.el for more commentary. + +;;; Code: + +(require 'multiple-cursors-core) + +(defcustom mc/edit-lines-empty-lines nil + "What should be done by `mc/edit-lines' when a line is not long enough." + :type '(radio (const :tag "Pad the line with spaces." pad) + (const :tag "Ignore the line." ignore) + (const :tag "Signal an error." error) + (const :tag "Nothing. Cursor is at end of line." nil)) + :group 'multiple-cursors) + +;;;###autoload +(defun mc/edit-lines (&optional arg) + "Add one cursor to each line of the active region. +Starts from mark and moves in straight down or up towards the +line point is on. + +What is done with lines which are not long enough is governed by +`mc/edit-lines-empty-lines'. The prefix argument ARG can be used +to override this. If ARG is a symbol (when called from Lisp), +that symbol is used instead of `mc/edit-lines-empty-lines'. +Otherwise, if ARG negative, short lines will be ignored. Any +other non-nil value will cause short lines to be padded." + (interactive "P") + (when (not (and mark-active (/= (point) (mark)))) + (error "Mark a set of lines first")) + (mc/remove-fake-cursors) + (let* ((col (current-column)) + (point-line (line-number-at-pos)) + (mark-line (progn (exchange-point-and-mark) (line-number-at-pos))) + (direction (if (< point-line mark-line) :up :down)) + (style (cond + ;; called from lisp + ((and arg (symbolp arg)) + arg) + ;; negative argument + ((< (prefix-numeric-value arg) 0) + 'ignore) + (arg 'pad) + (t mc/edit-lines-empty-lines)))) + (deactivate-mark) + (when (and (eq direction :up) (bolp)) + (previous-logical-line 1 nil) + (move-to-column col)) + ;; Add the cursors + (while (not (eq (line-number-at-pos) point-line)) + ;; Pad the line + (when (eq style 'pad) + (while (< (current-column) col) + (insert " "))) + ;; Error + (when (and (eq style 'error) + (not (equal col (current-column)))) + (error "Short line encountered in `mc/edit-lines'")) + ;; create the cursor + (unless (and (eq style 'ignore) + (not (equal col (current-column)))) + (mc/create-fake-cursor-at-point)) + ;; proceed to next + (if (eq direction :up) + (previous-logical-line 1 nil) + (next-logical-line 1 nil)) + (move-to-column col)) + (multiple-cursors-mode))) + +;;;###autoload +(defun mc/edit-ends-of-lines () + "Add one cursor to the end of each line in the active region." + (interactive) + (mc/edit-lines) + (mc/execute-command-for-all-cursors 'end-of-line)) + +;;;###autoload +(defun mc/edit-beginnings-of-lines () + "Add one cursor to the beginning of each line in the active region." + (interactive) + (mc/edit-lines) + (mc/execute-command-for-all-cursors 'beginning-of-line)) + +(provide 'mc-edit-lines) + +;;; mc-edit-lines.el ends here diff --git a/elpa/multiple-cursors-20170813.38/mc-hide-unmatched-lines-mode.el b/elpa/multiple-cursors-20170813.38/mc-hide-unmatched-lines-mode.el new file mode 100644 index 0000000..18e1688 --- /dev/null +++ b/elpa/multiple-cursors-20170813.38/mc-hide-unmatched-lines-mode.el @@ -0,0 +1,107 @@ +;;; mc-hide-unmatched-lines.el + +;; Copyright (C) 2014 Aleksey Fedotov + +;; Author: Aleksey Fedotov +;; Keywords: editing cursors + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This minor mode when enabled hides all lines where no cursors (and +;; also hum/lines-to-expand below and above) To make use of this mode +;; press "C-'" while multiple-cursor-mode is active. You can still +;; edit lines while you are in mc-hide-unmatched-lines mode. To leave +;; this mode press "" or "C-g" +;; + +;;; Code: + +(require 'multiple-cursors-core) +(require 'mc-mark-more) + +(defvar hum/hide-unmatched-lines-mode-map (make-sparse-keymap) + "Keymap for hide unmatched lines is mainly for rebinding C-g") + +(define-key hum/hide-unmatched-lines-mode-map (kbd "C-g") 'hum/keyboard-quit) +(define-key hum/hide-unmatched-lines-mode-map (kbd "") 'hum/keyboard-quit) + +(defun hum/keyboard-quit () + "Leave hide-unmatched-lines mode" + (interactive) + (mc-hide-unmatched-lines-mode 0)) + +;; used only in in multiple-cursors-mode-disabled-hook +(defun hum/disable-hum-mode () + (mc-hide-unmatched-lines-mode 0)) + +;;;###autoload +(define-minor-mode mc-hide-unmatched-lines-mode + "Minor mode when enabled hides all lines where no cursors (and +also hum/lines-to-expand below and above) To make use of this +mode press \"C-'\" while multiple-cursor-mode is active. You can +still edit lines while you are in mc-hide-unmatched-lines +mode. To leave this mode press or \"C-g\"" + nil " hu" + hum/hide-unmatched-lines-mode-map + (if mc-hide-unmatched-lines-mode + ;;just in case if mc mode will be disabled while hide-unmatched-lines is active + (progn + (hum/hide-unmatched-lines) + (add-hook 'multiple-cursors-mode-disabled-hook 'hum/disable-hum-mode t t)) + (progn + (hum/unhide-unmatched-lines) + (remove-hook 'multiple-cursors-mode-disabled-hook 'hum/disable-hum-mode)))) + +(defconst hum/invisible-overlay-name 'hum/invisible-overlay-name) + +(defcustom hum/lines-to-expand 2 + "How many lines below and above cursor to show" + :type '(integer) + :group 'multiple-cursors) + +(defcustom hum/placeholder "..." + "Placeholder which will be placed insted of hiden text" + :type '(string) + :group 'multiple-cursors) + +(defun hum/add-invisible-overlay (begin end) + (let ((overlay (make-overlay begin + end + (current-buffer) + t + nil + ))) + (overlay-put overlay hum/invisible-overlay-name t) + (overlay-put overlay 'invisible t) + (overlay-put overlay 'intangible t) + (overlay-put overlay 'evaporate t) + (overlay-put overlay 'after-string hum/placeholder))) + +(defun hum/hide-unmatched-lines () + (let ((begin (point-min))) + (mc/for-each-cursor-ordered + (save-excursion + (goto-char (mc/cursor-beg cursor)) + (if (< begin (line-beginning-position (- hum/lines-to-expand))) + (hum/add-invisible-overlay begin (line-end-position (- hum/lines-to-expand)))) + (setq begin (line-beginning-position (+ 2 hum/lines-to-expand))))) + (hum/add-invisible-overlay begin (point-max)))) + +(defun hum/unhide-unmatched-lines () + (remove-overlays nil nil hum/invisible-overlay-name t)) + +(provide 'mc-hide-unmatched-lines-mode) +(define-key mc/keymap (kbd "C-'") 'mc-hide-unmatched-lines-mode) diff --git a/elpa/multiple-cursors-20170813.38/mc-mark-more.el b/elpa/multiple-cursors-20170813.38/mc-mark-more.el new file mode 100644 index 0000000..2ab7ec7 --- /dev/null +++ b/elpa/multiple-cursors-20170813.38/mc-mark-more.el @@ -0,0 +1,709 @@ +;;; mc-mark-more.el + +;; Copyright (C) 2012-2016 Magnar Sveen + +;; Author: Magnar Sveen +;; Keywords: editing cursors + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This file contains functions to mark more parts of the buffer. +;; See ./features/mark-more.feature for examples. + +;; Please see multiple-cursors.el for more commentary. + +;;; Code: + +(require 'multiple-cursors-core) +(require 'thingatpt) + +(defun mc/cursor-end (cursor) + (if (overlay-get cursor 'mark-active) + (max (overlay-get cursor 'point) + (overlay-get cursor 'mark)) + (overlay-get cursor 'point))) + +(defun mc/cursor-beg (cursor) + (if (overlay-get cursor 'mark-active) + (min (overlay-get cursor 'point) + (overlay-get cursor 'mark)) + (overlay-get cursor 'point))) + +(defun mc/furthest-region-end () + (let ((end (max (mark) (point)))) + (mc/for-each-fake-cursor + (setq end (max end (mc/cursor-end cursor)))) + end)) + +(defun mc/first-region-start () + (let ((beg (min (mark) (point)))) + (mc/for-each-fake-cursor + (setq beg (min beg (mc/cursor-beg cursor)))) + beg)) + +(defun mc/furthest-cursor-before-point () + (let ((beg (if mark-active (min (mark) (point)) (point))) + furthest) + (mc/for-each-fake-cursor + (when (< (mc/cursor-beg cursor) beg) + (setq beg (mc/cursor-beg cursor)) + (setq furthest cursor))) + furthest)) + +(defun mc/furthest-cursor-after-point () + (let ((end (if mark-active (max (mark) (point)) (point))) + furthest) + (mc/for-each-fake-cursor + (when (> (mc/cursor-end cursor) end) + (setq end (mc/cursor-end cursor)) + (setq furthest cursor))) + furthest)) + +(defun mc/fake-cursor-at-point (&optional point) + "Return the fake cursor with its point right at POINT (defaults +to (point)), or nil." + (setq point (or point (point))) + (let ((cursors (mc/all-fake-cursors)) + (c nil)) + (catch 'found + (while (setq c (pop cursors)) + (when (eq (marker-position (overlay-get c 'point)) + point) + (throw 'found c)))))) + +(defun mc/region-strings () + (let ((strings (list (buffer-substring-no-properties (point) (mark))))) + (mc/for-each-fake-cursor + (add-to-list 'strings (buffer-substring-no-properties + (mc/cursor-beg cursor) + (mc/cursor-end cursor)))) + strings)) + +(defvar mc/enclose-search-term nil + "How should mc/mark-more-* search for more matches? + +Match everything: nil +Match only whole words: 'words +Match only whole symbols: 'symbols + +Use like case-fold-search, don't recommend setting it globally.") + +(defun mc/mark-more-like-this (skip-last direction) + (let ((case-fold-search nil) + (re (regexp-opt (mc/region-strings) mc/enclose-search-term)) + (point-out-of-order (cl-ecase direction + (forwards (< (point) (mark))) + (backwards (not (< (point) (mark)))))) + (furthest-cursor (cl-ecase direction + (forwards (mc/furthest-cursor-after-point)) + (backwards (mc/furthest-cursor-before-point)))) + (start-char (cl-ecase direction + (forwards (mc/furthest-region-end)) + (backwards (mc/first-region-start)))) + (search-function (cl-ecase direction + (forwards 'search-forward-regexp) + (backwards 'search-backward-regexp))) + (match-point-getter (cl-ecase direction + (forwards 'match-beginning) + (backwards 'match-end)))) + (if (and skip-last (not furthest-cursor)) + (error "No cursors to be skipped") + (mc/save-excursion + (goto-char start-char) + (when skip-last + (mc/remove-fake-cursor furthest-cursor)) + (if (funcall search-function re nil t) + (progn + (push-mark (funcall match-point-getter 0)) + (when point-out-of-order + (exchange-point-and-mark)) + (mc/create-fake-cursor-at-point)) + (error "no more matches found.")))))) + +;;;###autoload +(defun mc/mark-next-like-this (arg) + "Find and mark the next part of the buffer matching the currently active region +If no region is active add a cursor on the next line +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next." + (interactive "p") + (if (< arg 0) + (let ((cursor (mc/furthest-cursor-after-point))) + (if cursor + (mc/remove-fake-cursor cursor) + (error "No cursors to be unmarked"))) + (if (region-active-p) + (mc/mark-more-like-this (= arg 0) 'forwards) + (mc/mark-lines arg 'forwards))) + (mc/maybe-multiple-cursors-mode)) + +;;;###autoload +(defun mc/mark-next-like-this-word (arg) + "Find and mark the next part of the buffer matching the currently active region +If no region is active, mark the word at the point and find the next match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next." + (interactive "p") + (if (< arg 0) + (let ((cursor (mc/furthest-cursor-after-point))) + (if cursor + (mc/remove-fake-cursor cursor) + (error "No cursors to be unmarked"))) + (if (region-active-p) + (mc/mark-more-like-this (= arg 0) 'forwards) + (mc--select-thing-at-point 'word) + (mc/mark-more-like-this (= arg 0) 'forwards))) + (mc/maybe-multiple-cursors-mode)) + +(defun mc/mark-next-like-this-symbol (arg) + "Find and mark the next part of the buffer matching the currently active region +If no region is active, mark the symbol at the point and find the next match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next." + (interactive "p") + (if (< arg 0) + (let ((cursor (mc/furthest-cursor-after-point))) + (if cursor + (mc/remove-fake-cursor cursor) + (error "No cursors to be unmarked"))) + (if (region-active-p) + (mc/mark-more-like-this (= arg 0) 'forwards) + (mc--select-thing-at-point 'symbol) + (mc/mark-more-like-this (= arg 0) 'forwards))) + (mc/maybe-multiple-cursors-mode)) + + +;;;###autoload +(defun mc/mark-next-word-like-this (arg) + "Find and mark the next word of the buffer matching the currently active region +The matching region must be a whole word to be a match +If no region is active, mark the symbol at the point and find the next match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next." + (interactive "p") + (let ((mc/enclose-search-term 'words)) + (mc/mark-next-like-this arg))) + +;;;###autoload +(defun mc/mark-next-symbol-like-this (arg) + "Find and mark the next symbol of the buffer matching the currently active region +The matching region must be a whole symbol to be a match +If no region is active, mark the symbol at the point and find the next match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next." + (interactive "p") + (let ((mc/enclose-search-term 'symbols)) + (mc/mark-next-like-this arg))) + +;;;###autoload +(defun mc/mark-previous-like-this (arg) + "Find and mark the previous part of the buffer matching the currently active region +If no region is active add a cursor on the previous line +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next." + (interactive "p") + (if (< arg 0) + (let ((cursor (mc/furthest-cursor-before-point))) + (if cursor + (mc/remove-fake-cursor cursor) + (error "No cursors to be unmarked"))) + (if (region-active-p) + (mc/mark-more-like-this (= arg 0) 'backwards) + (mc/mark-lines arg 'backwards))) + (mc/maybe-multiple-cursors-mode)) + +;;;###autoload +(defun mc/mark-previous-like-this-word (arg) + "Find and mark the previous part of the buffer matching the currently active region +If no region is active, mark the word at the point and find the previous match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark previous." + (interactive "p") + (if (< arg 0) + (let ((cursor (mc/furthest-cursor-after-point))) + (if cursor + (mc/remove-fake-cursor cursor) + (error "No cursors to be unmarked"))) + (if (region-active-p) + (mc/mark-more-like-this (= arg 0) 'backwards) + (mc--select-thing-at-point 'word) + (mc/mark-more-like-this (= arg 0) 'backwards))) + (mc/maybe-multiple-cursors-mode)) + +(defun mc/mark-previous-like-this-symbol (arg) + "Find and mark the previous part of the buffer matching the currently active region +If no region is active, mark the symbol at the point and find the previous match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark previous." + (interactive "p") + (if (< arg 0) + (let ((cursor (mc/furthest-cursor-after-point))) + (if cursor + (mc/remove-fake-cursor cursor) + (error "No cursors to be unmarked"))) + (if (region-active-p) + (mc/mark-more-like-this (= arg 0) 'backwards) + (mc--select-thing-at-point 'symbol) + (mc/mark-more-like-this (= arg 0) 'backwards))) + (mc/maybe-multiple-cursors-mode)) + + +;;;###autoload +(defun mc/mark-previous-word-like-this (arg) + "Find and mark the previous part of the buffer matching the currently active region +The matching region must be a whole word to be a match +If no region is active add a cursor on the previous line +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next." + (interactive "p") + (let ((mc/enclose-search-term 'words)) + (mc/mark-previous-like-this arg))) + +;;;###autoload +(defun mc/mark-previous-symbol-like-this (arg) + "Find and mark the previous part of the buffer matching the currently active region +The matching region must be a whole symbol to be a match +If no region is active add a cursor on the previous line +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next." + (interactive "p") + (let ((mc/enclose-search-term 'symbols)) + (mc/mark-previous-like-this arg))) + +(defun mc/mark-lines (num-lines direction) + (dotimes (i (if (= num-lines 0) 1 num-lines)) + (mc/save-excursion + (let ((furthest-cursor (cl-ecase direction + (forwards (mc/furthest-cursor-after-point)) + (backwards (mc/furthest-cursor-before-point))))) + (when (overlayp furthest-cursor) + (goto-char (overlay-get furthest-cursor 'point)) + (when (= num-lines 0) + (mc/remove-fake-cursor furthest-cursor)))) + (cl-ecase direction + (forwards (next-logical-line 1 nil)) + (backwards (previous-logical-line 1 nil))) + (mc/create-fake-cursor-at-point)))) + +;;;###autoload +(defun mc/mark-next-lines (arg) + (interactive "p") + (mc/mark-lines arg 'forwards) + (mc/maybe-multiple-cursors-mode)) + +;;;###autoload +(defun mc/mark-previous-lines (arg) + (interactive "p") + (mc/mark-lines arg 'backwards) + (mc/maybe-multiple-cursors-mode)) + +;;;###autoload +(defun mc/unmark-next-like-this () + "Deselect next part of the buffer matching the currently active region." + (interactive) + (mc/mark-next-like-this -1)) + +;;;###autoload +(defun mc/unmark-previous-like-this () + "Deselect prev part of the buffer matching the currently active region." + (interactive) + (mc/mark-previous-like-this -1)) + +;;;###autoload +(defun mc/skip-to-next-like-this () + "Skip the current one and select the next part of the buffer matching the currently active region." + (interactive) + (mc/mark-next-like-this 0)) + +;;;###autoload +(defun mc/skip-to-previous-like-this () + "Skip the current one and select the prev part of the buffer matching the currently active region." + (interactive) + (mc/mark-previous-like-this 0)) + +;;;###autoload +(defun mc/mark-all-like-this () + "Find and mark all the parts of the buffer matching the currently active region" + (interactive) + (unless (region-active-p) + (error "Mark a region to match first.")) + (mc/remove-fake-cursors) + (let ((master (point)) + (case-fold-search nil) + (point-first (< (point) (mark))) + (re (regexp-opt (mc/region-strings) mc/enclose-search-term))) + (mc/save-excursion + (goto-char 0) + (while (search-forward-regexp re nil t) + (push-mark (match-beginning 0)) + (when point-first (exchange-point-and-mark)) + (unless (= master (point)) + (mc/create-fake-cursor-at-point)) + (when point-first (exchange-point-and-mark))))) + (if (> (mc/num-cursors) 1) + (multiple-cursors-mode 1) + (multiple-cursors-mode 0))) + +(defun mc--select-thing-at-point (thing) + (let ((bound (bounds-of-thing-at-point thing))) + (when bound + (set-mark (car bound)) + (goto-char (cdr bound)) + bound))) + +(defun mc--select-thing-at-point-or-bark (thing) + (unless (or (region-active-p) (mc--select-thing-at-point thing)) + (error "Mark a region or set cursor on a %s." thing))) + +;;;###autoload +(defun mc/mark-all-words-like-this () + (interactive) + (mc--select-thing-at-point-or-bark 'word) + (let ((mc/enclose-search-term 'words)) + (mc/mark-all-like-this))) + +;;;###autoload +(defun mc/mark-all-symbols-like-this () + (interactive) + (mc--select-thing-at-point-or-bark 'symbol) + (let ((mc/enclose-search-term 'symbols)) + (mc/mark-all-like-this))) + +;;;###autoload +(defun mc/mark-all-in-region (beg end &optional search) + "Find and mark all the parts in the region matching the given search" + (interactive "r") + (let ((search (or search (read-from-minibuffer "Mark all in region: "))) + (case-fold-search nil)) + (if (string= search "") + (message "Mark aborted") + (progn + (mc/remove-fake-cursors) + (goto-char beg) + (while (search-forward search end t) + (push-mark (match-beginning 0)) + (mc/create-fake-cursor-at-point)) + (let ((first (mc/furthest-cursor-before-point))) + (if (not first) + (error "Search failed for %S" search) + (mc/pop-state-from-overlay first))) + (if (> (mc/num-cursors) 1) + (multiple-cursors-mode 1) + (multiple-cursors-mode 0)))))) + +;;;###autoload +(defun mc/mark-all-in-region-regexp (beg end) + "Find and mark all the parts in the region matching the given regexp." + (interactive "r") + (let ((search (read-regexp "Mark regexp in region: ")) + (case-fold-search nil)) + (if (string= search "") + (message "Mark aborted") + (progn + (mc/remove-fake-cursors) + (goto-char beg) + (let ((lastmatch)) + (while (and (< (point) end) ; can happen because of (forward-char) + (search-forward-regexp search end t)) + (push-mark (match-beginning 0)) + (mc/create-fake-cursor-at-point) + (setq lastmatch (point)) + (when (= (point) (match-beginning 0)) + (forward-char))) + (unless lastmatch + (error "Search failed for %S" search))) + (goto-char (match-end 0)) + (if (< (mc/num-cursors) 3) + (multiple-cursors-mode 0) + (mc/pop-state-from-overlay (mc/furthest-cursor-before-point)) + (multiple-cursors-mode 1)))))) + +(when (not (fboundp 'set-temporary-overlay-map)) + ;; Backport this function from newer emacs versions + (defun set-temporary-overlay-map (map &optional keep-pred) + "Set a new keymap that will only exist for a short period of time. +The new keymap to use must be given in the MAP variable. When to +remove the keymap depends on user input and KEEP-PRED: + +- if KEEP-PRED is nil (the default), the keymap disappears as + soon as any key is pressed, whether or not the key is in MAP; + +- if KEEP-PRED is t, the keymap disappears as soon as a key *not* + in MAP is pressed; + +- otherwise, KEEP-PRED must be a 0-arguments predicate that will + decide if the keymap should be removed (if predicate returns + nil) or kept (otherwise). The predicate will be called after + each key sequence." + + (let* ((clearfunsym (make-symbol "clear-temporary-overlay-map")) + (overlaysym (make-symbol "t")) + (alist (list (cons overlaysym map))) + (clearfun + `(lambda () + (unless ,(cond ((null keep-pred) nil) + ((eq t keep-pred) + `(eq this-command + (lookup-key ',map + (this-command-keys-vector)))) + (t `(funcall ',keep-pred))) + (remove-hook 'pre-command-hook ',clearfunsym) + (setq emulation-mode-map-alists + (delq ',alist emulation-mode-map-alists)))))) + (set overlaysym overlaysym) + (fset clearfunsym clearfun) + (add-hook 'pre-command-hook clearfunsym) + + (push alist emulation-mode-map-alists)))) + +;;;###autoload +(defun mc/mark-more-like-this-extended () + "Like mark-more-like-this, but then lets you adjust with arrows key. +The adjustments work like this: + + Mark previous like this and set direction to 'up + Mark next like this and set direction to 'down + +If direction is 'up: + + Skip past the cursor furthest up + Remove the cursor furthest up + +If direction is 'down: + + Remove the cursor furthest down + Skip past the cursor furthest down + +The bindings for these commands can be changed. See `mc/mark-more-like-this-extended-keymap'." + (interactive) + (mc/mmlte--down) + (set-temporary-overlay-map mc/mark-more-like-this-extended-keymap t)) + +(defvar mc/mark-more-like-this-extended-direction nil + "When using mc/mark-more-like-this-extended are we working on the next or previous cursors?") + +(make-variable-buffer-local 'mc/mark-more-like-this-extended) + +(defun mc/mmlte--message () + (if (eq mc/mark-more-like-this-extended-direction 'up) + (message " to mark previous, to skip, to remove, to mark next") + (message " to mark next, to skip, to remove, to mark previous"))) + +(defun mc/mmlte--up () + (interactive) + (mc/mark-previous-like-this 1) + (setq mc/mark-more-like-this-extended-direction 'up) + (mc/mmlte--message)) + +(defun mc/mmlte--down () + (interactive) + (mc/mark-next-like-this 1) + (setq mc/mark-more-like-this-extended-direction 'down) + (mc/mmlte--message)) + +(defun mc/mmlte--left () + (interactive) + (if (eq mc/mark-more-like-this-extended-direction 'down) + (mc/unmark-next-like-this) + (mc/skip-to-previous-like-this)) + (mc/mmlte--message)) + +(defun mc/mmlte--right () + (interactive) + (if (eq mc/mark-more-like-this-extended-direction 'up) + (mc/unmark-previous-like-this) + (mc/skip-to-next-like-this)) + (mc/mmlte--message)) + +(defvar mc/mark-more-like-this-extended-keymap (make-sparse-keymap)) + +(define-key mc/mark-more-like-this-extended-keymap (kbd "") 'mc/mmlte--up) +(define-key mc/mark-more-like-this-extended-keymap (kbd "") 'mc/mmlte--down) +(define-key mc/mark-more-like-this-extended-keymap (kbd "") 'mc/mmlte--left) +(define-key mc/mark-more-like-this-extended-keymap (kbd "") 'mc/mmlte--right) + +(defvar mc--restrict-mark-all-to-symbols nil) + +;;;###autoload +(defun mc/mark-all-like-this-dwim (arg) + "Tries to guess what you want to mark all of. +Can be pressed multiple times to increase selection. + +With prefix, it behaves the same as original `mc/mark-all-like-this'" + (interactive "P") + (if arg + (mc/mark-all-like-this) + (if (and (not (use-region-p)) + (derived-mode-p 'sgml-mode) + (mc--on-tag-name-p)) + (mc/mark-sgml-tag-pair) + (let ((before (mc/num-cursors))) + (unless (eq last-command 'mc/mark-all-like-this-dwim) + (setq mc--restrict-mark-all-to-symbols nil)) + (unless (use-region-p) + (mc--mark-symbol-at-point) + (setq mc--restrict-mark-all-to-symbols t)) + (if mc--restrict-mark-all-to-symbols + (mc/mark-all-symbols-like-this-in-defun) + (mc/mark-all-like-this-in-defun)) + (when (<= (mc/num-cursors) before) + (if mc--restrict-mark-all-to-symbols + (mc/mark-all-symbols-like-this) + (mc/mark-all-like-this))) + (when (<= (mc/num-cursors) before) + (mc/mark-all-like-this)))))) + +;;;###autoload +(defun mc/mark-all-dwim (arg) + "Tries even harder to guess what you want to mark all of. + +If the region is active and spans multiple lines, it will behave +as if `mc/mark-all-in-region'. With the prefix ARG, it will call +`mc/edit-lines' instead. + +If the region is inactive or on a single line, it will behave like +`mc/mark-all-like-this-dwim'." + (interactive "P") + (if (and (use-region-p) + (not (> (mc/num-cursors) 1)) + (not (= (line-number-at-pos (region-beginning)) + (line-number-at-pos (region-end))))) + (if arg + (call-interactively 'mc/edit-lines) + (call-interactively 'mc/mark-all-in-region)) + (progn + (setq this-command 'mc/mark-all-like-this-dwim) + (mc/mark-all-like-this-dwim arg)))) + +(defun mc--in-defun () + (bounds-of-thing-at-point 'defun)) + +;;;###autoload +(defun mc/mark-all-like-this-in-defun () + "Mark all like this in defun." + (interactive) + (if (mc--in-defun) + (save-restriction + (widen) + (narrow-to-defun) + (mc/mark-all-like-this)) + (mc/mark-all-like-this))) + +;;;###autoload +(defun mc/mark-all-words-like-this-in-defun () + "Mark all words like this in defun." + (interactive) + (mc--select-thing-at-point-or-bark 'word) + (if (mc--in-defun) + (save-restriction + (widen) + (narrow-to-defun) + (mc/mark-all-words-like-this)) + (mc/mark-all-words-like-this))) + +;;;###autoload +(defun mc/mark-all-symbols-like-this-in-defun () + "Mark all symbols like this in defun." + (interactive) + (mc--select-thing-at-point-or-bark 'symbol) + (if (mc--in-defun) + (save-restriction + (widen) + (narrow-to-defun) + (mc/mark-all-symbols-like-this)) + (mc/mark-all-symbols-like-this))) + +(defun mc--mark-symbol-at-point () + "Select the symbol under cursor" + (interactive) + (when (not (use-region-p)) + (let ((b (bounds-of-thing-at-point 'symbol))) + (goto-char (car b)) + (set-mark (cdr b))))) + +(defun mc--get-nice-sgml-context () + (car + (last + (progn + (when (looking-at "<") (forward-char 1)) + (when (looking-back ">") (forward-char -1)) + (sgml-get-context))))) + +(defun mc--on-tag-name-p () + (let* ((context (save-excursion (mc--get-nice-sgml-context))) + (tag-name-len (length (aref context 4))) + (beg (aref context 2)) + (end (+ beg tag-name-len (if (eq 'open (aref context 1)) 1 3)))) + (and context + (>= (point) beg) + (<= (point) end)))) + +;;;###autoload +(defun mc/toggle-cursor-on-click (event) + "Add a cursor where you click, or remove a fake cursor that is +already there." + (interactive "e") + (mouse-minibuffer-check event) + ;; Use event-end in case called from mouse-drag-region. + ;; If EVENT is a click, event-end and event-start give same value. + (let ((position (event-end event))) + (if (not (windowp (posn-window position))) + (error "Position not in text area of window")) + (select-window (posn-window position)) + (let ((pt (posn-point position))) + (if (numberp pt) + ;; is there a fake cursor with the actual *point* right where we are? + (let ((existing (mc/fake-cursor-at-point pt))) + (if existing + (mc/remove-fake-cursor existing) + (save-excursion + (goto-char pt) + (mc/create-fake-cursor-at-point)))))) + (mc/maybe-multiple-cursors-mode))) + +;;;###autoload +(defalias 'mc/add-cursor-on-click 'mc/toggle-cursor-on-click) + +;;;###autoload +(defun mc/mark-sgml-tag-pair () + "Mark the tag we're in and its pair for renaming." + (interactive) + (when (not (mc--inside-tag-p)) + (error "Place point inside tag to rename.")) + (let ((context (mc--get-nice-sgml-context))) + (if (looking-at " +;; Keywords: editing cursors + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This file contains functions that work differently on each cursor, +;; instead of treating all of them the same. + +;; Please see multiple-cursors.el for more commentary. + +;;; Code: + +(require 'multiple-cursors-core) + +;;;###autoload +(defun mc/insert-numbers (arg) + "Insert increasing numbers for each cursor, starting at +`mc/insert-numbers-default' or ARG." + (interactive "P") + (setq mc--insert-numbers-number (or (and arg (prefix-numeric-value arg)) + mc/insert-numbers-default)) + (mc/for-each-cursor-ordered + (mc/execute-command-for-fake-cursor 'mc--insert-number-and-increase cursor))) + +(defcustom mc/insert-numbers-default 0 + "The default number at which to start counting for +`mc/insert-numbers'" + :type 'integer + :group 'multiple-cursors) + +(defvar mc--insert-numbers-number 0) + +(defun mc--insert-number-and-increase () + (interactive) + (insert (number-to-string mc--insert-numbers-number)) + (setq mc--insert-numbers-number (1+ mc--insert-numbers-number))) + +(defun mc--ordered-region-strings () + (let (strings) + (save-excursion + (mc/for-each-cursor-ordered + (setq strings (cons (buffer-substring-no-properties + (mc/cursor-beg cursor) + (mc/cursor-end cursor)) strings)))) + (nreverse strings))) + +;;;###autoload +(defun mc/insert-letters (arg) + "Insert increasing letters for each cursor, starting at 0 or ARG. + Where letter[0]=a letter[2]=c letter[26]=aa" + (interactive "P") + (setq mc--insert-letters-number (or (and arg (prefix-numeric-value arg)) + 0)) + (mc/for-each-cursor-ordered + (mc/execute-command-for-fake-cursor 'mc--insert-letter-and-increase cursor))) + +(defun mc--number-to-letters (number) + (let ((letter + (char-to-string + (+ (mod number 26) ?a))) + (number2 (/ number 26))) + (if (> number2 0) + (concat (mc--number-to-letters (- number2 1)) letter) + letter))) + +(defvar mc--insert-letters-number 0) + +(defun mc--insert-letter-and-increase () + (interactive) + (insert (mc--number-to-letters mc--insert-letters-number)) + (setq mc--insert-letters-number (1+ mc--insert-letters-number))) + +(defvar mc--strings-to-replace nil) + +(defun mc--replace-region-strings-1 () + (interactive) + (delete-region (region-beginning) (region-end)) + (save-excursion (insert (car mc--strings-to-replace))) + (setq mc--strings-to-replace (cdr mc--strings-to-replace))) + +(defun mc--replace-region-strings () + (mc/for-each-cursor-ordered + (mc/execute-command-for-fake-cursor 'mc--replace-region-strings-1 cursor))) + +;;;###autoload +(defun mc/reverse-regions () + (interactive) + (if (not multiple-cursors-mode) + (progn + (mc/mark-next-lines 1) + (mc/reverse-regions) + (multiple-cursors-mode 0)) + (unless (use-region-p) + (mc/execute-command-for-all-cursors 'mark-sexp)) + (setq mc--strings-to-replace (nreverse (mc--ordered-region-strings))) + (mc--replace-region-strings))) + +;;;###autoload +(defun mc/sort-regions () + (interactive) + (unless (use-region-p) + (mc/execute-command-for-all-cursors 'mark-sexp)) + (setq mc--strings-to-replace (sort (mc--ordered-region-strings) 'string<)) + (mc--replace-region-strings)) + + +;;;###autoload +(defun mc/vertical-align (character) + "Aligns all cursors vertically with a given CHARACTER to the one with the +highest colum number (the rightest). +Might not behave as intended if more than one cursors are on the same line." + (interactive "c") + (let ((rightest-column (current-column))) + (mc/execute-command-for-all-cursors + (lambda () "get the rightest cursor" + (interactive) + (setq rightest-column (max (current-column) rightest-column)) + )) + (mc/execute-command-for-all-cursors + (lambda () + (interactive) + (let ((missing-spaces (- rightest-column (current-column)))) + (save-excursion (insert (make-string missing-spaces character))) + (forward-char missing-spaces) + ) + )) + ) + ) + +;;;###autoload +(defun mc/vertical-align-with-space () + "Aligns all cursors with whitespace like `mc/vertical-align' does" + (interactive) + (mc/vertical-align 32) + ) + +(provide 'mc-separate-operations) +;;; mc-separate-operations.el ends here diff --git a/elpa/multiple-cursors-20170813.38/multiple-cursors-autoloads.el b/elpa/multiple-cursors-20170813.38/multiple-cursors-autoloads.el new file mode 100644 index 0000000..8e752e7 --- /dev/null +++ b/elpa/multiple-cursors-20170813.38/multiple-cursors-autoloads.el @@ -0,0 +1,341 @@ +;;; multiple-cursors-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "mc-edit-lines" "mc-edit-lines.el" (22942 51258 +;;;;;; 659903 701000)) +;;; Generated autoloads from mc-edit-lines.el + +(autoload 'mc/edit-lines "mc-edit-lines" "\ +Add one cursor to each line of the active region. +Starts from mark and moves in straight down or up towards the +line point is on. + +What is done with lines which are not long enough is governed by +`mc/edit-lines-empty-lines'. The prefix argument ARG can be used +to override this. If ARG is a symbol (when called from Lisp), +that symbol is used instead of `mc/edit-lines-empty-lines'. +Otherwise, if ARG negative, short lines will be ignored. Any +other non-nil value will cause short lines to be padded. + +\(fn &optional ARG)" t nil) + +(autoload 'mc/edit-ends-of-lines "mc-edit-lines" "\ +Add one cursor to the end of each line in the active region. + +\(fn)" t nil) + +(autoload 'mc/edit-beginnings-of-lines "mc-edit-lines" "\ +Add one cursor to the beginning of each line in the active region. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "mc-hide-unmatched-lines-mode" "mc-hide-unmatched-lines-mode.el" +;;;;;; (22942 51258 691903 867000)) +;;; Generated autoloads from mc-hide-unmatched-lines-mode.el + +(autoload 'mc-hide-unmatched-lines-mode "mc-hide-unmatched-lines-mode" "\ +Minor mode when enabled hides all lines where no cursors (and +also hum/lines-to-expand below and above) To make use of this +mode press \"C-'\" while multiple-cursor-mode is active. You can +still edit lines while you are in mc-hide-unmatched-lines +mode. To leave this mode press or \"C-g\" + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads nil "mc-mark-more" "mc-mark-more.el" (22942 51258 +;;;;;; 711903 971000)) +;;; Generated autoloads from mc-mark-more.el + +(autoload 'mc/mark-next-like-this "mc-mark-more" "\ +Find and mark the next part of the buffer matching the currently active region +If no region is active add a cursor on the next line +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next. + +\(fn ARG)" t nil) + +(autoload 'mc/mark-next-like-this-word "mc-mark-more" "\ +Find and mark the next part of the buffer matching the currently active region +If no region is active, mark the word at the point and find the next match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next. + +\(fn ARG)" t nil) + +(autoload 'mc/mark-next-word-like-this "mc-mark-more" "\ +Find and mark the next word of the buffer matching the currently active region +The matching region must be a whole word to be a match +If no region is active, mark the symbol at the point and find the next match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next. + +\(fn ARG)" t nil) + +(autoload 'mc/mark-next-symbol-like-this "mc-mark-more" "\ +Find and mark the next symbol of the buffer matching the currently active region +The matching region must be a whole symbol to be a match +If no region is active, mark the symbol at the point and find the next match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next. + +\(fn ARG)" t nil) + +(autoload 'mc/mark-previous-like-this "mc-mark-more" "\ +Find and mark the previous part of the buffer matching the currently active region +If no region is active add a cursor on the previous line +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next. + +\(fn ARG)" t nil) + +(autoload 'mc/mark-previous-like-this-word "mc-mark-more" "\ +Find and mark the previous part of the buffer matching the currently active region +If no region is active, mark the word at the point and find the previous match +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark previous. + +\(fn ARG)" t nil) + +(autoload 'mc/mark-previous-word-like-this "mc-mark-more" "\ +Find and mark the previous part of the buffer matching the currently active region +The matching region must be a whole word to be a match +If no region is active add a cursor on the previous line +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next. + +\(fn ARG)" t nil) + +(autoload 'mc/mark-previous-symbol-like-this "mc-mark-more" "\ +Find and mark the previous part of the buffer matching the currently active region +The matching region must be a whole symbol to be a match +If no region is active add a cursor on the previous line +With negative ARG, delete the last one instead. +With zero ARG, skip the last one and mark next. + +\(fn ARG)" t nil) + +(autoload 'mc/mark-next-lines "mc-mark-more" "\ + + +\(fn ARG)" t nil) + +(autoload 'mc/mark-previous-lines "mc-mark-more" "\ + + +\(fn ARG)" t nil) + +(autoload 'mc/unmark-next-like-this "mc-mark-more" "\ +Deselect next part of the buffer matching the currently active region. + +\(fn)" t nil) + +(autoload 'mc/unmark-previous-like-this "mc-mark-more" "\ +Deselect prev part of the buffer matching the currently active region. + +\(fn)" t nil) + +(autoload 'mc/skip-to-next-like-this "mc-mark-more" "\ +Skip the current one and select the next part of the buffer matching the currently active region. + +\(fn)" t nil) + +(autoload 'mc/skip-to-previous-like-this "mc-mark-more" "\ +Skip the current one and select the prev part of the buffer matching the currently active region. + +\(fn)" t nil) + +(autoload 'mc/mark-all-like-this "mc-mark-more" "\ +Find and mark all the parts of the buffer matching the currently active region + +\(fn)" t nil) + +(autoload 'mc/mark-all-words-like-this "mc-mark-more" "\ + + +\(fn)" t nil) + +(autoload 'mc/mark-all-symbols-like-this "mc-mark-more" "\ + + +\(fn)" t nil) + +(autoload 'mc/mark-all-in-region "mc-mark-more" "\ +Find and mark all the parts in the region matching the given search + +\(fn BEG END &optional SEARCH)" t nil) + +(autoload 'mc/mark-all-in-region-regexp "mc-mark-more" "\ +Find and mark all the parts in the region matching the given regexp. + +\(fn BEG END)" t nil) + +(autoload 'mc/mark-more-like-this-extended "mc-mark-more" "\ +Like mark-more-like-this, but then lets you adjust with arrows key. +The adjustments work like this: + + Mark previous like this and set direction to 'up + Mark next like this and set direction to 'down + +If direction is 'up: + + Skip past the cursor furthest up + Remove the cursor furthest up + +If direction is 'down: + + Remove the cursor furthest down + Skip past the cursor furthest down + +The bindings for these commands can be changed. See `mc/mark-more-like-this-extended-keymap'. + +\(fn)" t nil) + +(autoload 'mc/mark-all-like-this-dwim "mc-mark-more" "\ +Tries to guess what you want to mark all of. +Can be pressed multiple times to increase selection. + +With prefix, it behaves the same as original `mc/mark-all-like-this' + +\(fn ARG)" t nil) + +(autoload 'mc/mark-all-dwim "mc-mark-more" "\ +Tries even harder to guess what you want to mark all of. + +If the region is active and spans multiple lines, it will behave +as if `mc/mark-all-in-region'. With the prefix ARG, it will call +`mc/edit-lines' instead. + +If the region is inactive or on a single line, it will behave like +`mc/mark-all-like-this-dwim'. + +\(fn ARG)" t nil) + +(autoload 'mc/mark-all-like-this-in-defun "mc-mark-more" "\ +Mark all like this in defun. + +\(fn)" t nil) + +(autoload 'mc/mark-all-words-like-this-in-defun "mc-mark-more" "\ +Mark all words like this in defun. + +\(fn)" t nil) + +(autoload 'mc/mark-all-symbols-like-this-in-defun "mc-mark-more" "\ +Mark all symbols like this in defun. + +\(fn)" t nil) + +(autoload 'mc/toggle-cursor-on-click "mc-mark-more" "\ +Add a cursor where you click, or remove a fake cursor that is +already there. + +\(fn EVENT)" t nil) + +(defalias 'mc/add-cursor-on-click 'mc/toggle-cursor-on-click) + +(autoload 'mc/mark-sgml-tag-pair "mc-mark-more" "\ +Mark the tag we're in and its pair for renaming. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "mc-mark-pop" "mc-mark-pop.el" (22942 51258 +;;;;;; 679903 805000)) +;;; Generated autoloads from mc-mark-pop.el + +(autoload 'mc/mark-pop "mc-mark-pop" "\ +Add a cursor at the current point, pop off mark ring and jump +to the popped mark. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "mc-separate-operations" "mc-separate-operations.el" +;;;;;; (22942 51258 695903 888000)) +;;; Generated autoloads from mc-separate-operations.el + +(autoload 'mc/insert-numbers "mc-separate-operations" "\ +Insert increasing numbers for each cursor, starting at +`mc/insert-numbers-default' or ARG. + +\(fn ARG)" t nil) + +(autoload 'mc/insert-letters "mc-separate-operations" "\ +Insert increasing letters for each cursor, starting at 0 or ARG. + Where letter[0]=a letter[2]=c letter[26]=aa + +\(fn ARG)" t nil) + +(autoload 'mc/reverse-regions "mc-separate-operations" "\ + + +\(fn)" t nil) + +(autoload 'mc/sort-regions "mc-separate-operations" "\ + + +\(fn)" t nil) + +(autoload 'mc/vertical-align "mc-separate-operations" "\ +Aligns all cursors vertically with a given CHARACTER to the one with the +highest colum number (the rightest). +Might not behave as intended if more than one cursors are on the same line. + +\(fn CHARACTER)" t nil) + +(autoload 'mc/vertical-align-with-space "mc-separate-operations" "\ +Aligns all cursors with whitespace like `mc/vertical-align' does + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "multiple-cursors-core" "multiple-cursors-core.el" +;;;;;; (22942 51258 651903 661000)) +;;; Generated autoloads from multiple-cursors-core.el + +(autoload 'multiple-cursors-mode "multiple-cursors-core" "\ +Mode while multiple cursors are active. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads nil "rectangular-region-mode" "rectangular-region-mode.el" +;;;;;; (22942 51258 667903 743000)) +;;; Generated autoloads from rectangular-region-mode.el + +(autoload 'set-rectangular-region-anchor "rectangular-region-mode" "\ +Anchors the rectangular region at point. + +Think of this one as `set-mark' except you're marking a rectangular region. It is +an exceedingly quick way of adding multiple cursors to multiple lines. + +\(fn)" t nil) + +(autoload 'rectangular-region-mode "rectangular-region-mode" "\ +A mode for creating a rectangular region to edit + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads nil nil ("mc-cycle-cursors.el" "multiple-cursors-pkg.el" +;;;;;; "multiple-cursors.el") (22942 51258 715903 992000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; multiple-cursors-autoloads.el ends here diff --git a/elpa/multiple-cursors-20170813.38/multiple-cursors-core.el b/elpa/multiple-cursors-20170813.38/multiple-cursors-core.el new file mode 100644 index 0000000..96c4631 --- /dev/null +++ b/elpa/multiple-cursors-20170813.38/multiple-cursors-core.el @@ -0,0 +1,795 @@ +;;; multiple-cursors-core.el --- An experiment in multiple cursors for emacs. + +;; Copyright (C) 2012-2016 Magnar Sveen + +;; Author: Magnar Sveen +;; Keywords: editing cursors + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This file contains the core functionality of multiple-cursors. +;; Please see multiple-cursors.el for more commentary. + +;;; Code: + +(require 'cl-lib) +(require 'rect) + +(defvar mc--read-char) + +(defface mc/cursor-face + '((t (:inverse-video t))) + "The face used for fake cursors" + :group 'multiple-cursors) + +(defface mc/cursor-bar-face + `((t (:height 1 :background ,(face-attribute 'cursor :background)))) + "The face used for fake cursors if the cursor-type is bar" + :group 'multiple-cursors) + +(defface mc/region-face + '((t :inherit region)) + "The face used for fake regions" + :group 'multiple-cursors) + +(defmacro mc/add-fake-cursor-to-undo-list (&rest forms) + "Make sure point is in the right place when undoing" + (let ((uc (make-symbol "undo-cleaner"))) + `(let ((,uc (cons 'apply (cons 'deactivate-cursor-after-undo (list id))))) + (setq buffer-undo-list (cons ,uc buffer-undo-list)) + ,@forms + (if (eq ,uc (car buffer-undo-list)) ;; if nothing has been added to the undo-list + (setq buffer-undo-list (cdr buffer-undo-list)) ;; then pop the cleaner right off again + (setq buffer-undo-list ;; otherwise add a function to activate this cursor + (cons (cons 'apply (cons 'activate-cursor-for-undo (list id))) buffer-undo-list)))))) + +(defun mc/all-fake-cursors (&optional start end) + (cl-remove-if-not 'mc/fake-cursor-p + (overlays-in (or start (point-min)) + (or end (point-max))))) + +(defmacro mc/for-each-fake-cursor (&rest forms) + "Runs the body for each fake cursor, bound to the name cursor" + `(mapc #'(lambda (cursor) ,@forms) + (mc/all-fake-cursors))) + +(defmacro mc/save-excursion (&rest forms) + "Saves and restores all the state that multiple-cursors cares about." + (let ((cs (make-symbol "current-state"))) + `(let ((,cs (mc/store-current-state-in-overlay + (make-overlay (point) (point) nil nil t)))) + (overlay-put ,cs 'type 'original-cursor) + (save-excursion ,@forms) + (mc/pop-state-from-overlay ,cs)))) + +(defun mc--compare-by-overlay-start (o1 o2) + (< (overlay-start o1) (overlay-start o2))) + +(defmacro mc/for-each-cursor-ordered (&rest forms) + "Runs the body for each cursor, fake and real, bound to the name cursor" + (let ((rci (make-symbol "real-cursor-id"))) + `(let ((,rci (overlay-get (mc/create-fake-cursor-at-point) 'mc-id))) + (mapc #'(lambda (cursor) + (when (mc/fake-cursor-p cursor) + ,@forms)) + (sort (overlays-in (point-min) (point-max)) 'mc--compare-by-overlay-start)) + (mc/pop-state-from-overlay (mc/cursor-with-id ,rci))))) + +(defmacro mc/save-window-scroll (&rest forms) + "Saves and restores the window scroll position" + (let ((p (make-symbol "p")) + (s (make-symbol "start")) + (h (make-symbol "hscroll"))) + `(let ((,p (set-marker (make-marker) (point))) + (,s (set-marker (make-marker) (window-start))) + (,h (window-hscroll))) + ,@forms + (goto-char ,p) + (set-window-start nil ,s t) + (set-window-hscroll nil ,h) + (set-marker ,p nil) + (set-marker ,s nil)))) + +(defun mc/cursor-is-bar () + "Return non-nil if the cursor is a bar." + (or (eq cursor-type 'bar) + (and (listp cursor-type) + (eq (car cursor-type) 'bar)))) + +(defun mc/make-cursor-overlay-at-eol (pos) + "Create overlay to look like cursor at end of line." + (let ((overlay (make-overlay pos pos nil nil nil))) + (if (mc/cursor-is-bar) + (overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face)) + (overlay-put overlay 'after-string (propertize " " 'face 'mc/cursor-face))) + overlay)) + +(defun mc/make-cursor-overlay-inline (pos) + "Create overlay to look like cursor inside text." + (let ((overlay (make-overlay pos (1+ pos) nil nil nil))) + (if (mc/cursor-is-bar) + (overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face)) + (overlay-put overlay 'face 'mc/cursor-face)) + overlay)) + +(defun mc/make-cursor-overlay-at-point () + "Create overlay to look like cursor. +Special case for end of line, because overlay over a newline +highlights the entire width of the window." + (if (eolp) + (mc/make-cursor-overlay-at-eol (point)) + (mc/make-cursor-overlay-inline (point)))) + +(defun mc/make-region-overlay-between-point-and-mark () + "Create overlay to look like active region." + (let ((overlay (make-overlay (mark) (point) nil nil t))) + (overlay-put overlay 'face 'mc/region-face) + (overlay-put overlay 'type 'additional-region) + overlay)) + +(defvar mc/cursor-specific-vars '(transient-mark-mode + kill-ring + kill-ring-yank-pointer + mark-ring + mark-active + yank-undo-function + autopair-action + autopair-wrap-action + er/history) + "A list of vars that need to be tracked on a per-cursor basis.") + +(defun mc/store-current-state-in-overlay (o) + "Store relevant info about point and mark in the given overlay." + (overlay-put o 'point (set-marker (make-marker) (point))) + (overlay-put o 'mark (set-marker (make-marker) (mark))) + (dolist (var mc/cursor-specific-vars) + (when (boundp var) (overlay-put o var (symbol-value var)))) + o) + +(defun mc/restore-state-from-overlay (o) + "Restore point and mark from stored info in the given overlay." + (goto-char (overlay-get o 'point)) + (set-marker (mark-marker) (overlay-get o 'mark)) + (dolist (var mc/cursor-specific-vars) + (when (boundp var) (set var (overlay-get o var))))) + +(defun mc/remove-fake-cursor (o) + "Delete overlay with state, including dependent overlays and markers." + (set-marker (overlay-get o 'point) nil) + (set-marker (overlay-get o 'mark) nil) + (mc/delete-region-overlay o) + (delete-overlay o)) + +(defun mc/pop-state-from-overlay (o) + "Restore the state stored in given overlay and then remove the overlay." + (mc/restore-state-from-overlay o) + (mc/remove-fake-cursor o)) + +(defun mc/delete-region-overlay (o) + "Remove the dependent region overlay for a given cursor overlay." + (ignore-errors + (delete-overlay (overlay-get o 'region-overlay)))) + +(defvar mc--current-cursor-id 0 + "Var to store increasing id of fake cursors, used to keep track of them for undo.") + +(defun mc/create-cursor-id () + "Returns a unique cursor id" + (cl-incf mc--current-cursor-id)) + +(defvar mc--max-cursors-original nil + "This variable maintains the original maximum number of cursors. +When `mc/create-fake-cursor-at-point' is called and +`mc/max-cursors' is overridden, this value serves as a backup so +that `mc/max-cursors' can take on a new value. When +`mc/remove-fake-cursors' is called, the values are reset.") + +(defcustom mc/max-cursors nil + "Safety ceiling for the number of active cursors. +If your emacs slows down or freezes when using too many cursors, +customize this value appropriately. + +Cursors will be added until this value is reached, at which point +you can either temporarily override the value or abort the +operation entirely. + +If this value is nil, there is no ceiling." + :type '(integer) + :group 'multiple-cursors) + +(defun mc/create-fake-cursor-at-point (&optional id) + "Add a fake cursor and possibly a fake active region overlay based on point and mark. +Saves the current state in the overlay to be restored later." + (unless mc--max-cursors-original + (setq mc--max-cursors-original mc/max-cursors)) + (when mc/max-cursors + (unless (< (mc/num-cursors) mc/max-cursors) + (if (yes-or-no-p (format "%d active cursors. Continue? " (mc/num-cursors))) + (setq mc/max-cursors (read-number "Enter a new, temporary maximum: ")) + (mc/remove-fake-cursors) + (error "Aborted: too many cursors")))) + (let ((overlay (mc/make-cursor-overlay-at-point))) + (overlay-put overlay 'mc-id (or id (mc/create-cursor-id))) + (overlay-put overlay 'type 'fake-cursor) + (overlay-put overlay 'priority 100) + (mc/store-current-state-in-overlay overlay) + (when (use-region-p) + (overlay-put overlay 'region-overlay + (mc/make-region-overlay-between-point-and-mark))) + overlay)) + +(defun mc/execute-command (cmd) + "Run command, simulating the parts of the command loop that makes sense for fake cursors." + (setq this-command cmd) + (run-hooks 'pre-command-hook) + (unless (eq this-command 'ignore) + (call-interactively cmd)) + (run-hooks 'post-command-hook) + (when deactivate-mark (deactivate-mark))) + +(defvar mc--executing-command-for-fake-cursor nil) + +(defun mc/execute-command-for-fake-cursor (cmd cursor) + (let ((mc--executing-command-for-fake-cursor t) + (id (overlay-get cursor 'mc-id)) + (annoying-arrows-mode nil) + (smooth-scroll-margin 0)) + (mc/add-fake-cursor-to-undo-list + (mc/pop-state-from-overlay cursor) + (ignore-errors + (mc/execute-command cmd) + (mc/create-fake-cursor-at-point id))))) + +(defun mc/execute-command-for-all-fake-cursors (cmd) + "Calls CMD interactively for each cursor. +It works by moving point to the fake cursor, setting +up the proper environment, and then removing the cursor. +After executing the command, it sets up a new fake +cursor with updated info." + (mc/save-excursion + (mc/save-window-scroll + (mc/for-each-fake-cursor + (save-excursion + (mc/execute-command-for-fake-cursor cmd cursor))))) + (mc--reset-read-prompts)) + +(defun mc/execute-command-for-all-cursors (cmd) + "Calls CMD interactively for the real cursor and all fakes." + (call-interactively cmd) + (mc/execute-command-for-all-fake-cursors cmd)) + +;; Intercept some reading commands so you won't have to +;; answer them for every single cursor + +(defvar mc--read-char nil) +(defvar multiple-cursors-mode nil) +(defadvice read-char (around mc-support activate) + (if (not multiple-cursors-mode) + ad-do-it + (unless mc--read-char + (setq mc--read-char ad-do-it)) + (setq ad-return-value mc--read-char))) + +(defvar mc--read-quoted-char nil) +(defadvice read-quoted-char (around mc-support activate) + (if (not multiple-cursors-mode) + ad-do-it + (unless mc--read-quoted-char + (setq mc--read-quoted-char ad-do-it)) + (setq ad-return-value mc--read-quoted-char))) + +(defun mc--reset-read-prompts () + (setq mc--read-char nil) + (setq mc--read-quoted-char nil)) + +(mc--reset-read-prompts) + +(defun mc/fake-cursor-p (o) + "Predicate to check if an overlay is a fake cursor" + (eq (overlay-get o 'type) 'fake-cursor)) + +(defun mc/cursor-with-id (id) + "Find the first cursor with the given id, or nil" + (cl-find-if #'(lambda (o) (and (mc/fake-cursor-p o) + (= id (overlay-get o 'mc-id)))) + (overlays-in (point-min) (point-max)))) + +(defvar mc--stored-state-for-undo nil + "Variable to keep the state of the real cursor while undoing a fake one") + +(defun activate-cursor-for-undo (id) + "Called when undoing to temporarily activate the fake cursor which action is being undone." + (let ((cursor (mc/cursor-with-id id))) + (when cursor + (setq mc--stored-state-for-undo (mc/store-current-state-in-overlay + (make-overlay (point) (point) nil nil t))) + (mc/pop-state-from-overlay cursor)))) + +(defun deactivate-cursor-after-undo (id) + "Called when undoing to reinstate the real cursor after undoing a fake one." + (when mc--stored-state-for-undo + (mc/create-fake-cursor-at-point id) + (mc/pop-state-from-overlay mc--stored-state-for-undo) + (setq mc--stored-state-for-undo nil))) + +(defcustom mc/always-run-for-all nil + "Disables whitelisting and always executes commands for every fake cursor." + :type '(boolean) + :group 'multiple-cursors) + +(defun mc/prompt-for-inclusion-in-whitelist (original-command) + "Asks the user, then adds the command either to the once-list or the all-list." + (let ((all-p (y-or-n-p (format "Do %S for all cursors?" original-command)))) + (if all-p + (add-to-list 'mc/cmds-to-run-for-all original-command) + (add-to-list 'mc/cmds-to-run-once original-command)) + (mc/save-lists) + all-p)) + +(defun mc/num-cursors () + "The number of cursors (real and fake) in the buffer." + (1+ (cl-count-if 'mc/fake-cursor-p + (overlays-in (point-min) (point-max))))) + +(defvar mc--this-command nil + "Used to store the original command being run.") +(make-variable-buffer-local 'mc--this-command) + +(defun mc/make-a-note-of-the-command-being-run () + "Used with pre-command-hook to store the original command being run. +Since that cannot be reliably determined in the post-command-hook. + +Specifically, this-original-command isn't always right, because it could have +been remapped. And certain modes (cua comes to mind) will change their +remapping based on state. So a command that changes the state will afterwards +not be recognized through the command-remapping lookup." + (unless mc--executing-command-for-fake-cursor + (let ((cmd (or (command-remapping this-original-command) + this-original-command))) + (setq mc--this-command (and (not (eq cmd 'god-mode-self-insert)) + cmd))))) + +(defun mc/execute-this-command-for-all-cursors () + "Wrap around `mc/execute-this-command-for-all-cursors-1' to protect hook." + (condition-case error + (mc/execute-this-command-for-all-cursors-1) + (error + (message "[mc] problem in `mc/execute-this-command-for-all-cursors': %s" + (error-message-string error))))) + +;; execute-kbd-macro should never be run for fake cursors. The real cursor will +;; execute the keyboard macro, resulting in new commands in the command loop, +;; and the fake cursors can pick up on those instead. +(defadvice execute-kbd-macro (around skip-fake-cursors activate) + (unless mc--executing-command-for-fake-cursor + ad-do-it)) + +(defun mc/execute-this-command-for-all-cursors-1 () + "Used with post-command-hook to execute supported commands for all cursors. + +It uses two lists of commands to know what to do: the run-once +list and the run-for-all list. If a command is in neither of these lists, +it will prompt for the proper action and then save that preference. + +Some commands are so unsupported that they are even prevented for +the original cursor, to inform about the lack of support." + (unless mc--executing-command-for-fake-cursor + + (if (eq 1 (mc/num-cursors)) ;; no fake cursors? disable mc-mode + (multiple-cursors-mode 0) + (when this-original-command + (let ((original-command (or mc--this-command + (command-remapping this-original-command) + this-original-command))) + + ;; skip keyboard macros, since they will generate actual commands that are + ;; also run in the command loop - we'll handle those later instead. + (when (functionp original-command) + + ;; if it's a lambda, we can't know if it's supported or not + ;; - so go ahead and assume it's ok, because we're just optimistic like that + (if (or (not (symbolp original-command)) + ;; lambda registered by smartrep + (string-prefix-p "(" (symbol-name original-command))) + (mc/execute-command-for-all-fake-cursors original-command) + + ;; smartrep `intern's commands into own obarray to help + ;; `describe-bindings'. So, let's re-`intern' here to + ;; make the command comparable by `eq'. + (setq original-command (intern (symbol-name original-command))) + + ;; otherwise it's a symbol, and we can be more thorough + (if (get original-command 'mc--unsupported) + (message "%S is not supported with multiple cursors%s" + original-command + (get original-command 'mc--unsupported)) + (when (and original-command + (not (memq original-command mc--default-cmds-to-run-once)) + (not (memq original-command mc/cmds-to-run-once)) + (or mc/always-run-for-all + (memq original-command mc--default-cmds-to-run-for-all) + (memq original-command mc/cmds-to-run-for-all) + (mc/prompt-for-inclusion-in-whitelist original-command))) + (mc/execute-command-for-all-fake-cursors original-command)))))))))) + +(defun mc/remove-fake-cursors () + "Remove all fake cursors. +Do not use to conclude editing with multiple cursors. For that +you should disable multiple-cursors-mode." + (mc/for-each-fake-cursor + (mc/remove-fake-cursor cursor)) + (when mc--max-cursors-original + (setq mc/max-cursors mc--max-cursors-original)) + (setq mc--max-cursors-original nil)) + +(defun mc/keyboard-quit () + "Deactivate mark if there are any active, otherwise exit multiple-cursors-mode." + (interactive) + (if (not (use-region-p)) + (multiple-cursors-mode 0) + (deactivate-mark))) + +(defvar mc/keymap nil + "Keymap while multiple cursors are active. +Main goal of the keymap is to rebind C-g and to conclude +multiple cursors editing.") +(unless mc/keymap + (setq mc/keymap (make-sparse-keymap)) + (define-key mc/keymap (kbd "C-g") 'mc/keyboard-quit) + (define-key mc/keymap (kbd "") 'multiple-cursors-mode) + (when (fboundp 'phi-search) + (define-key mc/keymap (kbd "C-s") 'phi-search)) + (when (fboundp 'phi-search-backward) + (define-key mc/keymap (kbd "C-r") 'phi-search-backward))) + +(defun mc--all-equal (list) + "Are all the items in LIST equal?" + (let ((first (car list)) + (all-equal t)) + (while (and all-equal list) + (setq all-equal (equal first (car list))) + (setq list (cdr list))) + all-equal)) + +(defun mc--kill-ring-entries () + "Return the latest kill-ring entry for each cursor. +The entries are returned in the order they are found in the buffer." + (let (entries) + (mc/for-each-cursor-ordered + (setq entries (cons (car (overlay-get cursor 'kill-ring)) entries))) + (reverse entries))) + +(defun mc--maybe-set-killed-rectangle () + "Add the latest kill-ring entry for each cursor to killed-rectangle. +So you can paste it in later with `yank-rectangle'." + (let ((entries (let (mc/max-cursors) (mc--kill-ring-entries)))) + (unless (mc--all-equal entries) + (setq killed-rectangle entries)))) + +(defvar mc/unsupported-minor-modes '(company-mode auto-complete-mode flyspell-mode jedi-mode) + "List of minor-modes that does not play well with multiple-cursors. +They are temporarily disabled when multiple-cursors are active.") + +(defvar mc/temporarily-disabled-minor-modes nil + "The list of temporarily disabled minor-modes.") +(make-variable-buffer-local 'mc/temporarily-disabled-minor-modes) + +(defun mc/temporarily-disable-minor-mode (mode) + "If MODE is available and turned on, remember that and turn it off." + (when (and (boundp mode) (eval mode)) + (add-to-list 'mc/temporarily-disabled-minor-modes mode) + (funcall mode -1))) + +(defun mc/temporarily-disable-unsupported-minor-modes () + (mapc 'mc/temporarily-disable-minor-mode mc/unsupported-minor-modes)) + +(defun mc/enable-minor-mode (mode) + (funcall mode 1)) + +(defun mc/enable-temporarily-disabled-minor-modes () + (mapc 'mc/enable-minor-mode mc/temporarily-disabled-minor-modes) + (setq mc/temporarily-disabled-minor-modes nil)) + +(defcustom mc/mode-line + `(" mc:" (:eval (format ,(propertize "%d" 'face 'font-lock-warning-face) + (mc/num-cursors)))) + "What to display in the mode line while multiple-cursors-mode is active." + :group 'multiple-cursors) +(put 'mc/mode-line 'risky-local-variable t) + +;;;###autoload +(define-minor-mode multiple-cursors-mode + "Mode while multiple cursors are active." + nil mc/mode-line mc/keymap + (if multiple-cursors-mode + (progn + (mc/temporarily-disable-unsupported-minor-modes) + (add-hook 'pre-command-hook 'mc/make-a-note-of-the-command-being-run nil t) + (add-hook 'post-command-hook 'mc/execute-this-command-for-all-cursors t t) + (run-hooks 'multiple-cursors-mode-enabled-hook)) + (remove-hook 'post-command-hook 'mc/execute-this-command-for-all-cursors t) + (remove-hook 'pre-command-hook 'mc/make-a-note-of-the-command-being-run t) + (setq mc--this-command nil) + (mc--maybe-set-killed-rectangle) + (mc/remove-fake-cursors) + (mc/enable-temporarily-disabled-minor-modes) + (run-hooks 'multiple-cursors-mode-disabled-hook))) + +(add-hook 'after-revert-hook #'(lambda () (multiple-cursors-mode 0))) + +(defun mc/maybe-multiple-cursors-mode () + "Enable multiple-cursors-mode if there is more than one currently active cursor." + (if (> (mc/num-cursors) 1) + (multiple-cursors-mode 1) + (multiple-cursors-mode 0))) + +(defmacro unsupported-cmd (cmd msg) + "Adds command to list of unsupported commands and prevents it +from being executed if in multiple-cursors-mode." + `(progn + (put (quote ,cmd) 'mc--unsupported ,msg) + (defadvice ,cmd (around unsupported-advice activate) + "command isn't supported with multiple cursors" + (unless (and multiple-cursors-mode (called-interactively-p 'any)) + ad-do-it)))) + +;; Commands that does not work with multiple-cursors +(unsupported-cmd isearch-forward ". Feel free to add a compatible version.") +(unsupported-cmd isearch-backward ". Feel free to add a compatible version.") + +;; Make sure pastes from other programs are added to all kill-rings when yanking +(defadvice current-kill (before interprogram-paste-for-all-cursors activate) + (let ((interprogram-paste (and (= n 0) + interprogram-paste-function + (funcall interprogram-paste-function)))) + (when interprogram-paste + ;; Add interprogram-paste to normal kill ring, just + ;; like current-kill usually does for itself. + ;; We have to do the work for it tho, since the funcall only returns + ;; something once. It is not a pure function. + (let ((interprogram-cut-function nil)) + (if (listp interprogram-paste) + (mapc 'kill-new (nreverse interprogram-paste)) + (kill-new interprogram-paste)) + ;; And then add interprogram-paste to the kill-rings + ;; of all the other cursors too. + (mc/for-each-fake-cursor + (let ((kill-ring (overlay-get cursor 'kill-ring)) + (kill-ring-yank-pointer (overlay-get cursor 'kill-ring-yank-pointer))) + (if (listp interprogram-paste) + (mapc 'kill-new (nreverse interprogram-paste)) + (kill-new interprogram-paste)) + (overlay-put cursor 'kill-ring kill-ring) + (overlay-put cursor 'kill-ring-yank-pointer kill-ring-yank-pointer))))))) + +(defcustom mc/list-file (locate-user-emacs-file ".mc-lists.el") + "The position of the file that keeps track of your preferences +for running commands with multiple cursors." + :type 'file + :group 'multiple-cursors) + +(defun mc/dump-list (list-symbol) + "Insert (setq 'LIST-SYMBOL LIST-VALUE) to current buffer." + (cl-symbol-macrolet ((value (symbol-value list-symbol))) + (insert "(setq " (symbol-name list-symbol) "\n" + " '(") + (newline-and-indent) + (set list-symbol + (sort value (lambda (x y) (string-lessp (symbol-name x) + (symbol-name y))))) + (mapc #'(lambda (cmd) (insert (format "%S" cmd)) (newline-and-indent)) + value) + (insert "))") + (newline))) + +(defun mc/save-lists () + "Saves preferences for running commands with multiple cursors to `mc/list-file'" + (with-temp-file mc/list-file + (emacs-lisp-mode) + (insert ";; This file is automatically generated by the multiple-cursors extension.") + (newline) + (insert ";; It keeps track of your preferences for running commands with multiple cursors.") + (newline) + (newline) + (mc/dump-list 'mc/cmds-to-run-for-all) + (newline) + (mc/dump-list 'mc/cmds-to-run-once))) + +(defvar mc/cmds-to-run-once nil + "Commands to run only once in multiple-cursors-mode.") + +(defvar mc--default-cmds-to-run-once nil + "Default set of commands to run only once in multiple-cursors-mode.") + +(setq mc--default-cmds-to-run-once '(mc/edit-lines + mc/edit-ends-of-lines + mc/edit-beginnings-of-lines + mc/mark-next-like-this + mc/mark-next-like-this-word + mc/mark-next-like-this-symbol + mc/mark-next-word-like-this + mc/mark-next-symbol-like-this + mc/mark-previous-like-this + mc/mark-previous-like-this-word + mc/mark-previous-like-this-symbol + mc/mark-previous-word-like-this + mc/mark-previous-symbol-like-this + mc/mark-all-like-this + mc/mark-all-words-like-this + mc/mark-all-symbols-like-this + mc/mark-more-like-this-extended + mc/mark-all-like-this-in-defun + mc/mark-all-words-like-this-in-defun + mc/mark-all-symbols-like-this-in-defun + mc/mark-all-like-this-dwim + mc/mark-all-dwim + mc/mark-sgml-tag-pair + mc/insert-numbers + mc/insert-letters + mc/sort-regions + mc/reverse-regions + mc/cycle-forward + mc/cycle-backward + mc/add-cursor-on-click + mc/mark-pop + mc/add-cursors-to-all-matches + mc/mmlte--left + mc/mmlte--right + mc/mmlte--up + mc/mmlte--down + mc/unmark-next-like-this + mc/unmark-previous-like-this + mc/skip-to-next-like-this + mc/skip-to-previous-like-this + rrm/switch-to-multiple-cursors + mc-hide-unmatched-lines-mode + hum/keyboard-quit + hum/unhide-invisible-overlays + save-buffer + ido-exit-minibuffer + ivy-done + exit-minibuffer + minibuffer-complete-and-exit + execute-extended-command + undo + redo + undo-tree-undo + undo-tree-redo + universal-argument + universal-argument-more + universal-argument-other-key + negative-argument + digit-argument + top-level + recenter-top-bottom + describe-mode + describe-key-1 + describe-function + describe-bindings + describe-prefix-bindings + view-echo-area-messages + other-window + kill-buffer-and-window + split-window-right + split-window-below + delete-other-windows + toggle-window-split + mwheel-scroll + scroll-up-command + scroll-down-command + mouse-set-point + mouse-drag-region + quit-window + toggle-read-only + windmove-left + windmove-right + windmove-up + windmove-down)) + +(defvar mc--default-cmds-to-run-for-all nil + "Default set of commands that should be mirrored by all cursors") + +(setq mc--default-cmds-to-run-for-all '(mc/keyboard-quit + self-insert-command + quoted-insert + previous-line + next-line + newline + newline-and-indent + open-line + delete-blank-lines + transpose-chars + transpose-lines + transpose-paragraphs + transpose-regions + join-line + right-char + right-word + forward-char + forward-word + left-char + left-word + backward-char + backward-word + forward-paragraph + backward-paragraph + upcase-word + downcase-word + capitalize-word + forward-list + backward-list + hippie-expand + hippie-expand-lines + yank + yank-pop + append-next-kill + kill-word + kill-line + kill-whole-line + backward-kill-word + backward-delete-char-untabify + delete-char delete-forward-char + delete-backward-char + py-electric-backspace + c-electric-backspace + org-delete-backward-char + cperl-electric-backspace + python-indent-dedent-line-backspace + paredit-backward-delete + autopair-backspace + just-one-space + zap-to-char + end-of-line + set-mark-command + exchange-point-and-mark + cua-set-mark + cua-replace-region + cua-delete-region + move-end-of-line + beginning-of-line + move-beginning-of-line + kill-ring-save + back-to-indentation + subword-forward + subword-backward + subword-mark + subword-kill + subword-backward-kill + subword-transpose + subword-capitalize + subword-upcase + subword-downcase + er/expand-region + er/contract-region + smart-forward + smart-backward + smart-up + smart-down)) + +(defvar mc/cmds-to-run-for-all nil + "Commands to run for all cursors in multiple-cursors-mode") + +;; load, but no errors if it does not exist yet please, and no message +;; while loading +(load mc/list-file 'noerror 'nomessage) + +(provide 'multiple-cursors-core) + +;; Local Variables: +;; coding: utf-8 +;; End: + +;;; multiple-cursors-core.el ends here diff --git a/elpa/multiple-cursors-20170813.38/multiple-cursors-pkg.el b/elpa/multiple-cursors-20170813.38/multiple-cursors-pkg.el new file mode 100644 index 0000000..e393c7a --- /dev/null +++ b/elpa/multiple-cursors-20170813.38/multiple-cursors-pkg.el @@ -0,0 +1,5 @@ +(define-package "multiple-cursors" "20170813.38" "Multiple cursors for Emacs." + '((cl-lib "0.5"))) +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/multiple-cursors-20170813.38/multiple-cursors.el b/elpa/multiple-cursors-20170813.38/multiple-cursors.el new file mode 100644 index 0000000..4a05dcc --- /dev/null +++ b/elpa/multiple-cursors-20170813.38/multiple-cursors.el @@ -0,0 +1,199 @@ +;;; multiple-cursors.el --- Multiple cursors for emacs. + +;; Copyright (C) 2012-2016 Magnar Sveen + +;; Author: Magnar Sveen +;; Version: 1.4.0 +;; Keywords: editing cursors + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Multiple cursors for Emacs. This is some pretty crazy functionality, so yes, +;; there are kinks. Don't be afraid tho, I've been using it since 2011 with +;; great success and much merriment. + +;; ## Basic usage + +;; Start out with: + +;; (require 'multiple-cursors) + +;; Then you have to set up your keybindings - multiple-cursors doesn't presume to +;; know how you'd like them laid out. Here are some examples: + +;; When you have an active region that spans multiple lines, the following will +;; add a cursor to each line: + +;; (global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines) + +;; When you want to add multiple cursors not based on continuous lines, but based on +;; keywords in the buffer, use: + +;; (global-set-key (kbd "C->") 'mc/mark-next-like-this) +;; (global-set-key (kbd "C-<") 'mc/mark-previous-like-this) +;; (global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this) + +;; First mark the word, then add more cursors. + +;; To get out of multiple-cursors-mode, press `` or `C-g`. The latter will +;; first disable multiple regions before disabling multiple cursors. If you want to +;; insert a newline in multiple-cursors-mode, use `C-j`. + +;; ## Video + +;; You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html). + +;; ## Command overview + +;; ### Mark one more occurrence + +;; - `mc/mark-next-like-this`: Adds a cursor and region at the next part of the buffer forwards that matches the current region. +;; - `mc/mark-next-like-this-word`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the word at the point. +;; - `mc/mark-next-like-this-symbol`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the symbol at the point. +;; - `mc/mark-next-word-like-this`: Like `mc/mark-next-like-this` but only for whole words. +;; - `mc/mark-next-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols. +;; - `mc/mark-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region. +;; - `mc/mark-previous-word-like-this`: Like `mc/mark-previous-like-this` but only for whole words. +;; - `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols. +;; - `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurances. +;; - `mc/add-cursor-on-click`: Bind to a mouse event to add cursors by clicking. See tips-section. + +;; ### Mark many occurrences + +;; - `mc/mark-all-like-this`: Marks all parts of the buffer that matches the current region. +;; - `mc/mark-all-words-like-this`: Like `mc/mark-all-like-this` but only for whole words. +;; - `mc/mark-all-symbols-like-this`: Like `mc/mark-all-like-this` but only for whole symbols. +;; - `mc/mark-all-in-region`: Prompts for a string to match in the region, adding cursors to all of them. +;; - `mc/mark-all-like-this-in-defun`: Marks all parts of the current defun that matches the current region. +;; - `mc/mark-all-words-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole words. +;; - `mc/mark-all-symbols-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole symbols. +;; - `mc/mark-all-like-this-dwim`: Tries to be smart about marking everything you want. Can be pressed multiple times. + +;; ### Special + +;; - `set-rectangular-region-anchor`: Think of this one as `set-mark` except you're marking a rectangular region. +;; - `mc/mark-sgml-tag-pair`: Mark the current opening and closing tag. +;; - `mc/insert-numbers`: Insert increasing numbers for each cursor, top to bottom. +;; - `mc/insert-letters`: Insert increasing letters for each cursor, top to bottom. +;; - `mc/sort-regions`: Sort the marked regions alphabetically. +;; - `mc/reverse-regions`: Reverse the order of the marked regions. + +;; ## Tips and tricks + +;; - To get out of multiple-cursors-mode, press `` or `C-g`. The latter will +;; first disable multiple regions before disabling multiple cursors. If you want to +;; insert a newline in multiple-cursors-mode, use `C-j`. +;; +;; - Sometimes you end up with cursors outside of your view. You can +;; scroll the screen to center on each cursor with `C-v` and `M-v`. +;; +;; - Try pressing `mc/mark-next-like-this` with no region selected. It will just add a cursor +;; on the next line. +;; +;; - Try pressing `mc/mark-next-like-this-word` or +;; `mc/mark-next-like-this-symbol` with no region selected. It will +;; mark the symbol and add a cursor at the next occurance +;; +;; - Try pressing `mc/mark-all-like-this-dwim` on a tagname in html-mode. +;; +;; - Notice that the number of cursors active can be seen in the modeline. +;; +;; - If you get out of multiple-cursors-mode and yank - it will yank only +;; from the kill-ring of main cursor. To yank from the kill-rings of +;; every cursor use yank-rectangle, normally found at C-x r y. +;; +;; - You can use `mc/reverse-regions` with nothing selected and just one cursor. +;; It will then flip the sexp at point and the one below it. +;; +;; - If you would like to keep the global bindings clean, and get custom keybindings +;; when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode). +;; +;; BTW, I highly recommend adding `mc/mark-next-like-this` to a key binding that's +;; right next to the key for `er/expand-region`. + +;; ### Binding mouse events + +;; To override a mouse event, you will likely have to also unbind the +;; `down-mouse` part of the event. Like this: +;; +;; (global-unset-key (kbd "M-")) +;; (global-set-key (kbd "M-") 'mc/add-cursor-on-click) +;; +;; Or you can do like me and find an unused, but less convenient, binding: +;; +;; (global-set-key (kbd "C-S-") 'mc/add-cursor-on-click) + +;; ## Unknown commands + +;; Multiple-cursors uses two lists of commands to know what to do: the run-once list +;; and the run-for-all list. It comes with a set of defaults, but it would be beyond silly +;; to try and include all the known Emacs commands. + +;; So that's why multiple-cursors occasionally asks what to do about a command. It will +;; then remember your choice by saving it in `~/.emacs.d/.mc-lists.el`. You can change +;; the location with: + +;; (setq mc/list-file "/my/preferred/file") + +;; ## Known limitations + +;; * isearch-forward and isearch-backward aren't supported with multiple cursors. +;; You should feel free to add a simplified version that can work with it. +;; * Commands run with `M-x` won't be repeated for all cursors. +;; * All key bindings that refer to lambdas are always run for all cursors. If you +;; need to limit it, you will have to give it a name. +;; * Redo might screw with your cursors. Undo works very well. + +;; ## Contribute + +;; Yes, please do. There's a suite of tests, so remember to add tests for your +;; specific feature, or I might break it later. + +;; You'll find the repo at: + +;; https://github.com/magnars/multiple-cursors.el + +;; To fetch the test dependencies: + +;; $ cd /path/to/multiple-cursors +;; $ git submodule update --init + +;; Run the tests with: + +;; $ ./util/ecukes/ecukes --graphical + +;; ## Contributors + +;; * [Takafumi Arakaki](https://github.com/tkf) made .mc-lists.el diff friendly +;; * [Marco Baringer](https://github.com/segv) contributed looping to mc/cycle and adding cursors without region for mark-more. +;; * [Ivan Andrus](https://github.com/gvol) added showing number of cursors in mode-line +;; * [Fuco](https://github.com/Fuco1) added the first version of `mc/mark-all-like-this-dwim` + +;; Thanks! + +;;; Code: + +(require 'mc-edit-lines) +(require 'mc-cycle-cursors) +(require 'mc-mark-more) +(require 'mc-mark-pop) +(require 'rectangular-region-mode) +(require 'mc-separate-operations) +(require 'mc-hide-unmatched-lines-mode) + +(provide 'multiple-cursors) + +;;; multiple-cursors.el ends here diff --git a/elpa/multiple-cursors-20170813.38/rectangular-region-mode.el b/elpa/multiple-cursors-20170813.38/rectangular-region-mode.el new file mode 100644 index 0000000..01a078d --- /dev/null +++ b/elpa/multiple-cursors-20170813.38/rectangular-region-mode.el @@ -0,0 +1,125 @@ +;;; rectangular-region-mode.el + +;; Copyright (C) 2012-2016 Magnar Sveen + +;; Author: Magnar Sveen +;; Keywords: editing cursors + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; (global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor) + +;; Think of this one as `set-mark` except you're marking a rectangular region. It is +;; an exceedingly quick way of adding multiple cursors to multiple lines. + +;;; Code: + +(require 'multiple-cursors-core) + +(defvar rrm/anchor (make-marker) + "The position in the buffer that anchors the rectangular region.") + +(defvar rectangular-region-mode-map (make-sparse-keymap) + "Keymap for rectangular region is mainly for rebinding C-g") + +(define-key rectangular-region-mode-map (kbd "C-g") 'rrm/keyboard-quit) +(define-key rectangular-region-mode-map (kbd "") 'rrm/switch-to-multiple-cursors) + +(defvar rectangular-region-mode nil) + +(defun rrm/keyboard-quit () + "Exit rectangular-region-mode." + (interactive) + (rectangular-region-mode 0) + (rrm/remove-rectangular-region-overlays) + (deactivate-mark)) + +;; Bind this to a key (for instance H-SPC) to start rectangular-region-mode +;;;###autoload +(defun set-rectangular-region-anchor () + "Anchors the rectangular region at point. + +Think of this one as `set-mark' except you're marking a rectangular region. It is +an exceedingly quick way of adding multiple cursors to multiple lines." + (interactive) + (set-marker rrm/anchor (point)) + (push-mark (point)) + (rectangular-region-mode 1)) + +(defun rrm/remove-rectangular-region-overlays () + "Remove all rectangular-region overlays." + (mc/remove-fake-cursors) + (mapc #'(lambda (o) + (when (eq (overlay-get o 'type) 'additional-region) + (delete-overlay o))) + (overlays-in (point-min) (point-max)))) + +(defun rrm/repaint () + "Start from the anchor and draw a rectangle between it and point." + (if (not rectangular-region-mode) + (remove-hook 'post-command-hook 'rrm/repaint t) + ;; else + (rrm/remove-rectangular-region-overlays) + (let* ((annoying-arrows-mode nil) + (point-column (current-column)) + (point-line (line-number-at-pos)) + (anchor-column (save-excursion (goto-char rrm/anchor) (current-column))) + (anchor-line (save-excursion (goto-char rrm/anchor) (line-number-at-pos))) + (left-column (if (< point-column anchor-column) point-column anchor-column)) + (right-column (if (> point-column anchor-column) point-column anchor-column)) + (navigation-step (if (< point-line anchor-line) 1 -1))) + (move-to-column anchor-column) + (set-mark (point)) + (move-to-column point-column) + (mc/save-excursion + (while (not (= anchor-line (line-number-at-pos))) + (forward-line navigation-step) + (move-to-column anchor-column) + (when (= anchor-column (current-column)) + (set-mark (point)) + (move-to-column point-column) + (when (= point-column (current-column)) + (mc/create-fake-cursor-at-point)))))))) + +(defun rrm/switch-to-multiple-cursors (&rest forms) + "Switch from rectangular-region-mode to multiple-cursors-mode." + (interactive) + (rectangular-region-mode 0) + (multiple-cursors-mode 1)) + +(defadvice er/expand-region (before switch-from-rrm-to-mc activate) + (when rectangular-region-mode + (rrm/switch-to-multiple-cursors))) + +(defadvice kill-ring-save (before switch-from-rrm-to-mc activate) + (when rectangular-region-mode + (rrm/switch-to-multiple-cursors))) + +;;;###autoload +(define-minor-mode rectangular-region-mode + "A mode for creating a rectangular region to edit" + nil " rr" rectangular-region-mode-map + (if rectangular-region-mode + (progn + (add-hook 'after-change-functions 'rrm/switch-to-multiple-cursors t t) + (add-hook 'post-command-hook 'rrm/repaint t t)) + (remove-hook 'after-change-functions 'rrm/switch-to-multiple-cursors t) + (remove-hook 'post-command-hook 'rrm/repaint t) + (set-marker rrm/anchor nil))) + +(provide 'rectangular-region-mode) + +;;; rectangular-region-mode.el ends here diff --git a/elpa/page-break-lines-20170517.235/page-break-lines-autoloads.el b/elpa/page-break-lines-20170517.235/page-break-lines-autoloads.el new file mode 100644 index 0000000..bbb5d5a --- /dev/null +++ b/elpa/page-break-lines-20170517.235/page-break-lines-autoloads.el @@ -0,0 +1,77 @@ +;;; page-break-lines-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "page-break-lines" "page-break-lines.el" (22830 +;;;;;; 24428 923863 486000)) +;;; Generated autoloads from page-break-lines.el + +(defvar page-break-lines-char 9472 "\ +Character used to render page break lines.") + +(custom-autoload 'page-break-lines-char "page-break-lines" t) + +(defvar page-break-lines-lighter " PgLn" "\ +Mode-line indicator for `page-break-lines-mode'.") + +(custom-autoload 'page-break-lines-lighter "page-break-lines" t) + +(defvar page-break-lines-modes '(emacs-lisp-mode lisp-mode scheme-mode compilation-mode outline-mode help-mode) "\ +Modes in which to enable `page-break-lines-mode'.") + +(custom-autoload 'page-break-lines-modes "page-break-lines" t) + +(defface page-break-lines '((t :inherit font-lock-comment-face :bold nil :italic nil)) "\ +Face used to colorize page break lines. +If using :bold or :italic, please ensure `page-break-lines-char' +is available in that variant of your font, otherwise it may be +displayed as a junk character." :group (quote page-break-lines)) + +(autoload 'page-break-lines-mode "page-break-lines" "\ +Toggle Page Break Lines mode. + +In Page Break mode, page breaks (^L characters) are displayed as a +horizontal line of `page-break-string-char' characters. + +\(fn &optional ARG)" t nil) + +(define-obsolete-function-alias 'turn-on-page-break-lines-mode 'page-break-lines-mode) + +(autoload 'page-break-lines-mode-maybe "page-break-lines" "\ +Enable `page-break-lines-mode' in the current buffer if desired. +When `major-mode' is listed in `page-break-lines-modes', then +`page-break-lines-mode' will be enabled. + +\(fn)" nil nil) + +(defvar global-page-break-lines-mode nil "\ +Non-nil if Global Page-Break-Lines mode is enabled. +See the `global-page-break-lines-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-page-break-lines-mode'.") + +(custom-autoload 'global-page-break-lines-mode "page-break-lines" nil) + +(autoload 'global-page-break-lines-mode "page-break-lines" "\ +Toggle Page-Break-Lines mode in all buffers. +With prefix ARG, enable Global Page-Break-Lines mode if ARG is positive; +otherwise, disable it. If called from Lisp, enable the mode if +ARG is omitted or nil. + +Page-Break-Lines mode is enabled in all buffers where +`page-break-lines-mode-maybe' would do it. +See `page-break-lines-mode' for more information on Page-Break-Lines mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; page-break-lines-autoloads.el ends here diff --git a/elpa/page-break-lines-20170517.235/page-break-lines-pkg.el b/elpa/page-break-lines-20170517.235/page-break-lines-pkg.el new file mode 100644 index 0000000..d2ed1e1 --- /dev/null +++ b/elpa/page-break-lines-20170517.235/page-break-lines-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "page-break-lines" "20170517.235" "Display ugly ^L page breaks as tidy horizontal lines" 'nil :commit "82f9100312dcc922fb66ff289faf5d4795d8ca7a" :url "https://github.com/purcell/page-break-lines" :keywords '("convenience" "faces")) diff --git a/elpa/page-break-lines-20170517.235/page-break-lines.el b/elpa/page-break-lines-20170517.235/page-break-lines.el new file mode 100644 index 0000000..a26d3ee --- /dev/null +++ b/elpa/page-break-lines-20170517.235/page-break-lines.el @@ -0,0 +1,169 @@ +;;; page-break-lines.el --- Display ugly ^L page breaks as tidy horizontal lines + +;; Copyright (C) 2012-2015 Steve Purcell + +;; Author: Steve Purcell +;; URL: https://github.com/purcell/page-break-lines +;; Package-Version: 20170517.235 +;; Package-X-Original-Version: DEV +;; Keywords: convenience, faces + +;; 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 +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This library provides a global mode which displays form feed +;; characters as horizontal rules. + +;; Install from Melpa or Marmalade, or add to `load-path' and use +;; (require 'page-break-lines). + +;; Use `page-break-lines-mode' to enable the mode in specific buffers, +;; or customize `page-break-lines-modes' and enable the mode globally with +;; `global-page-break-lines-mode'. + +;; Issues and limitations: + +;; If `page-break-lines-char' is displayed at a different width to +;; regular characters, the rule may be either too short or too long: +;; rules may then wrap if `truncate-lines' is nil. On some systems, +;; Emacs may erroneously choose a different font for the page break +;; symbol, which choice can be overridden using code such as: + +;; (set-fontset-font "fontset-default" +;; (cons page-break-lines-char page-break-lines-char) +;; (face-attribute 'default :family)) + +;; Use `describe-char' on a page break char to determine whether this +;; is the case. + +;; Additionally, the use of `text-scale-increase' or +;; `text-scale-decrease' will cause the rule width to be incorrect, +;; because the reported window width (in characters) will continue to +;; be the width in the frame's default font, not the scaled font used to +;; display the rule. + +;; Adapted from code http://www.emacswiki.org/emacs/PageBreaks + +;;; Code: + +(defgroup page-break-lines nil + "Display ugly ^L page breaks as tidy horizontal lines." + :prefix "page-break-lines-" + :group 'faces) + +;;;###autoload +(defcustom page-break-lines-char ?─ + "Character used to render page break lines." + :type 'character + :group 'page-break-lines) + +;;;###autoload +(defcustom page-break-lines-lighter " PgLn" + "Mode-line indicator for `page-break-lines-mode'." + :type '(choice (const :tag "No lighter" "") string) + :group 'page-break-lines) + +;;;###autoload +(defcustom page-break-lines-modes + '(emacs-lisp-mode lisp-mode scheme-mode compilation-mode outline-mode help-mode) + "Modes in which to enable `page-break-lines-mode'." + :type '(repeat symbol) + :group 'page-break-lines) + +;;;###autoload +(defface page-break-lines + '((t :inherit font-lock-comment-face :bold nil :italic nil)) + "Face used to colorize page break lines. +If using :bold or :italic, please ensure `page-break-lines-char' +is available in that variant of your font, otherwise it may be +displayed as a junk character." + :group 'page-break-lines) + + + +;;;###autoload +(define-minor-mode page-break-lines-mode + "Toggle Page Break Lines mode. + +In Page Break mode, page breaks (^L characters) are displayed as a +horizontal line of `page-break-string-char' characters." + :lighter page-break-lines-lighter + :group 'page-break-lines + (page-break-lines--update-display-tables)) + +;;;###autoload +(define-obsolete-function-alias 'turn-on-page-break-lines-mode 'page-break-lines-mode) + +(dolist (hook '(window-configuration-change-hook + window-size-change-functions + after-setting-font-hook)) + (add-hook hook 'page-break-lines--update-display-tables)) + + + +(defun page-break-lines--update-display-table (window) + "Modify a display-table that displays page-breaks prettily. +If the buffer inside WINDOW has `page-break-lines-mode' enabled, +its display table will be modified as necessary." + (with-current-buffer (window-buffer window) + (if page-break-lines-mode + (progn + (unless buffer-display-table + (setq buffer-display-table (make-display-table))) + (let ((default-height (face-attribute 'default :height nil 'default))) + (set-face-attribute 'page-break-lines nil :height default-height) + (let* ((cwidth (char-width page-break-lines-char)) + (wwidth (window-width window)) + (width (if (zerop (% wwidth cwidth)) + (1- (/ wwidth cwidth)) + (/ wwidth cwidth))) + (glyph (make-glyph-code page-break-lines-char 'page-break-lines)) + (new-display-entry (vconcat (make-list width glyph)))) + (unless (equal new-display-entry (elt buffer-display-table ?\^L)) + (aset buffer-display-table ?\^L new-display-entry))))) + (when (and (member major-mode page-break-lines-modes) + buffer-display-table) + (aset buffer-display-table ?\^L nil))))) + +(defun page-break-lines--update-display-tables (&optional frame) + "Function called for updating display table in windows of FRAME." + (mapc 'page-break-lines--update-display-table (window-list frame 'no-minibuffer))) + + + +;;;###autoload +(defun page-break-lines-mode-maybe () + "Enable `page-break-lines-mode' in the current buffer if desired. +When `major-mode' is listed in `page-break-lines-modes', then +`page-break-lines-mode' will be enabled." + (if (and (not (minibufferp)) + (apply 'derived-mode-p page-break-lines-modes)) + (page-break-lines-mode 1))) + +;;;###autoload +(define-global-minor-mode global-page-break-lines-mode + page-break-lines-mode page-break-lines-mode-maybe + :group 'page-break-lines) + + +(provide 'page-break-lines) + +;; Local Variables: +;; coding: utf-8 +;; byte-compile-warnings: (not cl-functions) +;; checkdoc-minor-mode: t +;; End: + +;;; page-break-lines.el ends here