[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master a8edc2a: Make el-search key binding installation more flex
[elpa] master a8edc2a: Make el-search key binding installation more flexible
Sun, 21 Jan 2018 12:21:07 -0500 (EST)
Author: Michael Heerdegen <address@hidden>
Commit: Michael Heerdegen <address@hidden>
Make el-search key binding installation more flexible
Implement a function `el-search-install-bindings-under-prefix' that
the user can call to install repeatable versions of the el-search
commands under a prefix key. Update header (list of key bindings
etc.) accordingly. Also remove the el-search-keep-hl -> 'once hack,
since it is not compatible with this change.
* el-search/el-search.el (el-search-read-expression-map): Bind M-RET
(el-search-loop-over-bindings): New abstract key binding function
(el-search-install-shift-bindings): Use it.
(el-search-install-bindings-under-prefix): New key binding function.
(el-search-bind-under-prefix-key-function): New helper variables and
(el-search-prefix-key-maybe-set-transient-map): New function to
activate the `el-search-prefix-key-transient-map'.
(el-search-continue-search, el-search-pattern-backwards): Call it.
(el-search--occur-button-action): Remove implementation of
el-search-keep-hl -> 'once hack.
packages/el-search/el-search.el | 225 +++++++++++++++++++++++++++-------------
1 file changed, 152 insertions(+), 73 deletions(-)
diff --git a/packages/el-search/el-search.el b/packages/el-search/el-search.el
index d3c67df..89f540f 100644
@@ -44,22 +44,42 @@
;; patterns and your own multi-search commands.
-;; Suggested key bindings
-;; After loading this file, you can eval
-;; (el-search-install-shift-bindings) to install a set of key bindings
-;; to try things out (no other setup is needed). Here is an overview
-;; of the most important bindings that this function will establish -
-;; most are of the form Control-Shift-Letter:
-;; C-S (el-search-pattern)
+;; Key bindings
+;; Loading this file doesn't install any key bindings - but you
+;; probably want some. There are two predefined sets of key bindings.
+;; The first set installs bindings mostly of the form
+;; "Control-Shift-Letter", e.g. C-S, C-R, C-% etc. These can be
+;; installed by calling (el-search-install-shift-bindings) - typically
+;; in your init file. For console users (and others), the function
+;; `el-search-install-bindings-under-prefix' installs bindings of the
+;; form PREFIX LETTER. If you e.g. call
+;; (el-search-install-bindings-under-prefix [(meta ?s) ?e])
+;; you install bindings M-s e s, M-s e r, M-s e % etc. When using
+;; this function to install key bindings, the bindings are
+;; "repeatable" where it makes sense, so that you can for example hit
+;; M-s e j s s s a % to reactive the last search, go to the next match
+;; three times, then go back to the first match in the current buffer,
+;; and finally invoke query-replace.
+;; Here is a complete list of key bindings installed when
+;; you call
+;; (el-search-install-bindings-under-prefix [(meta ?s) ?e])
+;; C-S, M-s e s (el-search-pattern)
;; Start a search in the current buffer/go to the next match.
-;; C-R (el-search-pattern-backwards)
+;; C-R, M-s e r (el-search-pattern-backwards)
;; Search backwards.
-;; C-% (el-search-query-replace)
+;; C-%, M-s e % (el-search-query-replace)
;; Do a query-replace.
;; M-x el-search-directory
@@ -67,44 +87,39 @@
;; Emacs-Lisp files in that directory. With prefix arg,
;; recursively search files in subdirectories.
-;; C-S in Dired (el-search-dired-marked-files)
+;; C-S, M-s e s in Dired (el-search-dired-marked-files)
;; Like above but uses the marked files and directories.
-;; C-O (el-search-occur)
+;; C-O, M-s e o (el-search-occur)
;; Pop up an occur buffer for the current search.
-;; C-O (from a search pattern prompt)
+;; C-O or M-RET (from a search pattern prompt)
;; Execute this search command as occur.
-;; C-N (el-search-continue-in-next-buffer)
+;; C-N, M-s e n (el-search-continue-in-next-buffer)
;; Skip over current buffer or file.
-;; C-D (el-search-skip-directory)
+;; C-D, M-s e d (el-search-skip-directory)
;; Prompt for a directory name and skip all subsequent files
;; located under this directory.
-;; C-A (el-search-from-beginning) Go back to the first match in this
-;; buffer or (with prefix arg) completely restart the current
-;; search from the first file or buffer.
+;; C-A, M-s e a (el-search-from-beginning)
+;; Go back to the first match in this buffer or (with prefix arg)
+;; completely restart the current search from the first file or
-;; C-J (el-search-jump-to-search-head)
+;; C-J, M-s e j (el-search-jump-to-search-head)
;; Resume the last search from the position of the last visited
;; match, or (with prefix arg) prompt for an old search to resume.
-;; C-H (el-search-this-sexp)
+;; C-H, M-s e h (el-search-this-sexp)
;; Grab the symbol or sexp under point and initiate an el-search
;; for other occurrences.
-;; These bindings may not work in a console (if you have a good idea
-;; for nice alternative bindings please mail me).
;; The setup you'll need for your init file is trivial: just define
;; the key bindings you want to use (all important commands are
-;; autoloaded) and you are done. You can either just copy
-;; (el-search-install-shift-bindings) to your init file to use the
-;; above bindings or use its definition as a template for your own key
-;; binding definitions.
+;; autoloaded) and you are done.
@@ -280,8 +295,8 @@
;; query-replace is driven by a search, call
;; `el-search-jump-to-search-head' (maybe with a prefix arg) to make
;; that search current, and invoke `el-search-query-replace' (with the
-;; default bindings, this would be C-J C-%). This will continue the
-;; query-replace session from where you left.
+;; default bindings, this would be C-J C-% or C-x o j %). This will
+;; continue the query-replace session from where you left.
;; Advanced usage: Replacement rules for semi-automatic code rewriting
@@ -362,8 +377,6 @@
-;; - The default keys are not available in the terminal
;; - Make searching work in comments, too? (->
;; `parse-sexp-ignore-comments'). Related: should the pattern
;; `symbol' also match strings that contain matches for a symbol so
@@ -476,6 +489,34 @@ The default value is ask-multi."
(const :tag "Ask" ask)
(const :tag "Ask when multibuffer" ask-multi)))
+(defvar el-search-use-transient-map nil
+ "Whether el-search should make commands repeatable."
+ ;; I originally wanted to make commands repeatable by looking at the
+ ;; command keys. But that got overly complicated: It interfered with
+ ;; user interaction: we must remember in a flag if the current command
+ ;; invocation was repeatable. Obviously, we must reset that flag in
+ ;; post-command-hook. But we must avoid resetting in
+ ;; post-command-hook when the command itself required user input, etc.
+ ;; And it can't even work when we use a button or a register to resume
+ ;; a search. So let's simply use this flag.
+ universal-argument universal-argument-more
+ digit-argument negative-argument)
+ "List of commands that don't end repeatability of el-search commands.
+When `el-search-use-transient-map' is non-nil, when any
+\"repeatable\" el-search command had been invoked, executing any
+of these commands will keep the
+`el-search-prefix-key-transient-map' further in effect.")
(let ((map (make-sparse-keymap)))
(set-keymap-parent map read-expression-map)
@@ -483,6 +524,8 @@ The default value is ask-multi."
(define-key map [up] nil)
(define-key map [down] nil)
(define-key map [(control ?j)] #'newline)
+ (define-key map [(meta return)] #'el-search-set-occur-flag-exit-minibuffer)
+ (define-key map (kbd "M-RET") #'el-search-set-occur-flag-exit-minibuffer)
"Keymap for reading input with `el-search-read-expression'.")
@@ -1413,38 +1456,75 @@ in, in order, when called with no arguments."
+(defun el-search-loop-over-bindings (function)
+ (cl-flet ((keybind (apply-partially #'funcall function)))
+ (keybind emacs-lisp-mode-map ?s #'el-search-pattern)
+ (keybind emacs-lisp-mode-map ?r #'el-search-pattern-backwards)
+ (keybind emacs-lisp-mode-map ?% #'el-search-query-replace)
+ (keybind emacs-lisp-mode-map ?h #'el-search-this-sexp) ;h like
in "highlight" or "here"
+ (keybind global-map ?j #'el-search-jump-to-search-head)
+ (keybind global-map ?a #'el-search-from-beginning)
+ (keybind global-map ?d #'el-search-skip-directory)
+ (keybind global-map ?n
+ (keybind global-map ?o #'el-search-occur)
+ (keybind el-search-read-expression-map ?s #'exit-minibuffer)
+ (keybind el-search-read-expression-map ?r #'exit-minibuffer)
+ (keybind el-search-read-expression-map ?o
+ (keybind isearch-mode-map ?s #'el-search-search-from-isearch)
+ (keybind isearch-mode-map ?r
+ (keybind isearch-mode-map ?% #'el-search-replace-from-isearch)
+ (keybind isearch-mode-map ?o #'el-search-occur-from-isearch)
+ (keybind global-map ?e #'el-search-emacs-elisp-sources)
+ (keybind global-map ?l #'el-search-load-path)
+ (keybind global-map ?b #'el-search-buffers)
+ (defvar dired-mode-map)
+ (with-eval-after-load 'dired
+ (keybind dired-mode-map ?s #'el-search-dired-marked-files))))
+ (let ((transient-map (make-sparse-keymap)))
+ (lambda (_map key command)
+ (when (memq command '(el-search-pattern
+ (define-key transient-map (vector key) command))))
+(defun el-search-prefix-key-maybe-set-transient-map ()
+ (when el-search-use-transient-map
+ (set-transient-map el-search-prefix-key-transient-map
+ (lambda () (memq this-command
+(defun el-search-shift-bindings-bind-function (map key command)
+ (define-key map `[(control ,@(if (<= ?a key ?z) `(shift ,key) `(,key)))]
(defun el-search-install-shift-bindings ()
+ (el-search-loop-over-bindings #'el-search-shift-bindings-bind-function))
- (define-key emacs-lisp-mode-map [(control ?S)] #'el-search-pattern)
- (define-key emacs-lisp-mode-map [(control ?R)] #'el-search-pattern-backwards)
- (define-key emacs-lisp-mode-map [(control ?%)] #'el-search-query-replace)
- (define-key emacs-lisp-mode-map [(control ?H)] #'el-search-this-sexp) ;H
like in "highlight" or "here"
- (define-key global-map [(control ?J)]
- (define-key global-map [(control ?A)] #'el-search-from-beginning)
- (define-key global-map [(control ?D)] #'el-search-skip-directory)
- (define-key global-map [(control ?N)]
- (define-key global-map [(control ?O)] #'el-search-occur)
- (define-key el-search-read-expression-map [(control ?S)] #'exit-minibuffer)
- (define-key el-search-read-expression-map [(control ?R)] #'exit-minibuffer)
- (define-key el-search-read-expression-map [(control ?O)]
- (define-key isearch-mode-map [(control ?S)] #'el-search-search-from-isearch)
- (define-key isearch-mode-map [(control ?R)]
- (define-key isearch-mode-map [(control ?%)] #'el-search-replace-from-isearch)
- (define-key isearch-mode-map [(control ?O)] #'el-search-occur-from-isearch)
+(defun el-search-bind-under-prefix-key-function (prefix)
+ (lambda (map key command)
+ (unless (memq map (list el-search-read-expression-map isearch-mode-map))
+ (define-key map `[,@(seq-into prefix 'list) ,key] command))))
- (define-key global-map [(control ?E)] #'el-search-emacs-elisp-sources)
- (define-key global-map [(control ?L)] #'el-search-load-path)
- (define-key global-map [(control ?B)] #'el-search-buffers)
- (defvar dired-mode-map)
- (with-eval-after-load 'dired
- (define-key dired-mode-map [(control ?S)] #'el-search-dired-marked-files)))
+(defun el-search-install-bindings-under-prefix (prefix-key)
+ (el-search-bind-under-prefix-key-function prefix-key))
+ (setq el-search-use-transient-map t))
(defun el-search-setup-search-1 (pattern get-buffer-stream &optional
(setq el-search--success nil)
@@ -1452,7 +1532,8 @@ in, in order, when called with no arguments."
(el-search-make-search pattern get-buffer-stream))
(when setup-function (funcall setup-function el-search--current-search))
(ring-insert el-search-history el-search--current-search)
- (when from-here (setq el-search--temp-buffer-flag nil)))
+ (when from-here (setq el-search--temp-buffer-flag nil))
(defun el-search-setup-search (pattern get-buffer-stream &optional
"Create and start a new el-search.
@@ -1769,10 +1850,7 @@ absolute name must be matched by all of them."
(defvar-local el-search-hl-other-overlays '())
(defvar el-search-keep-hl nil
- "Non-nil indicates we should not remove any highlighting.
-If the non-nil value is the symbol `once', inhibit highlight
-removal only once.")
+ "Non-nil indicates we should not remove any highlighting.")
(defun el-search-hl-sexp (&optional bounds)
(let ((bounds (or bounds (list (point) (el-search--end-of-sexp)))))
@@ -1951,9 +2029,7 @@ local binding of `window-scroll-functions'."
- (_ (if el-search-keep-hl
- (when (eq el-search-keep-hl 'once)
- (setq el-search-keep-hl nil))
+ (_ (unless el-search-keep-hl
(remove-hook 'post-command-hook 'el-search-hl-post-command-fun t)
(setq el-search--temp-buffer-flag nil)
@@ -2065,7 +2141,8 @@ current."
(setf (el-search-object-last-match el-search--current-search)
- (el-search-hl-other-matches (el-search--current-matcher))))))
+ (el-search-hl-other-matches (el-search--current-matcher))
(el-search--message-no-log "[Search completed - restarting]")
@@ -2149,7 +2226,8 @@ continued."
(eq (current-buffer) old-current-buffer))
- (setq el-search--success t))))
+ (setq el-search--success t)))
(defun el-search-skip-directory (directory)
@@ -2241,7 +2319,9 @@ With prefix arg, restart the current search."
(declare (interactive-only t))
(if (eq pattern (el-search--current-pattern))
- (el-search-compile-pattern-in-search el-search--current-search)
+ (el-search-compile-pattern-in-search el-search--current-search)
(let ((current-buffer (current-buffer)))
@@ -2449,7 +2529,6 @@ Prompt for a new pattern and revert."
(add-hook 'post-command-hook #'el-search-hl-post-command-fun t t)
- (setq-local el-search-keep-hl 'once)
(when do-fun (funcall do-fun)))))
(defun el-search-occur--next-match (&optional backwards)
|[Prev in Thread]
||[Next in Thread]|
- [elpa] master a8edc2a: Make el-search key binding installation more flexible,
Michael Heerdegen <=