Let's look at this logically: you want to have near-identical commands bound to C-f2
and C-f3
. The only difference between these commands is whether they store the thing under point in the f2
memory or in the f3
memory. Then you either need to construct different commands, or you need to have a single command whose behavior depends on what key it's bound to.
You can bind a key to a command that's constructed at the time you create the binding. The command argument to define-key
and friends doesn't have to be a command name in the form of a symbol, it can be a lambda expression.
(global-set-key [C-f3] (lambda ()
(interactive)
…))
This works, but it isn't very nice. For example help commands and command histories won't show you a command name.
You can put the bulk of the code in a function and define small wrapper functions. To avoid repeating a lot of code, have a function or macro generate the wrapper functions.
(defun repeat-search-thing-at-point-forward (memory)
(search-forward (symbol-value memory)))
(defun repeat-search-thing-at-point-backward (memory)
(search-backward (symbol-value memory)))
(defun search-thing-at-point (memory)
"Search the thing at point.
Store the thing in MEMORY for a future search with
`repeat-search-thing-at-point-forward' and
`repeat-search-thing-at-point-backward'."
(set memory (thing-at-point 'word))
(repeat-search-thing-at-point-forward memory))
(defun define-search-thing-at-point (map key)
"Define commands to search a thing at point "
(let* ((memory-variable (intern (format "search-memory-%s" key)))
(set-function (intern (format "search-thing-at-point-%s" key)))
(forward-function (intern (format "repeat-search-thing-at-point-forward-%s" key)))
(backward-function (intern (format "repeat-search-thing-at-point-backward-%s" key)))
(forward-key (vector key))
(backward-key (vector (list 'shift key)))
(set-key (vector (list 'control key))))
(eval `(progn
(defvar ,memory-variable nil
,(format "The last thing searched with \\[%s]." set-function))
(defun ,set-function ()
,(format "Search the thing at point.
Use \\[%s] and \\[%s] to repeat the search forward and backward
respectively." forward-function backward-function)
(interactive "@")
(search-thing-at-point ',memory-variable))
(defun ,forward-function ()
,(format "Search forward for the last thing searched with \\[%s]." set-function)
(interactive "@")
(repeat-search-thing-at-point-forward ',memory-variable))
(defun ,backward-function ()
,(format "Search backward for the last thing searched with \\[%s]." set-function)
(interactive "@")
(repeat-search-thing-at-point-backward ',memory-variable))
(define-key map ',set-key #',set-function)
(define-key map ',forward-key #',forward-function)
(define-key map ',backward-key #',backward-function)
t))))
(define-search-thing-at-point global-map 'f2)
(define-search-thing-at-point global-map 'f3)
(define-search-thing-at-point global-map 'f4)
Alternatively, you can define a single command for each functionality (first search, repeat forward, repeat backward). This is slightly less flexible (e.g. you can't rebind `search-thing-at-point-f2 to H-s if it takes your fancy) but a lot less verbose.
A command can find which key invoked it. The easiest way for you is to use the variable last-command-event
.
(defvar search-thing-memory nil
"History of things searched with `search-thing-at-point'.")
(defun search-thing-at-point (key)
"Search the thing at point.
Store the thing in MEMORY for a future search with
`repeat-search-thing-at-point-forward' and
`repeat-search-thing-at-point-backward'."
(interactive (list (event-basic-type last-command-event)))
(let ((thing (thing-at-point 'word))
(memory (assq key search-thing-memory)))
(if memory
(setcdr memory thing)
(setq search-thing-memory (cons (cons key thing)
search-thing-memory)))
(search-forward thing)))
(defun repeat-search-thing-at-point-forward (key)
"Repeat the last thing searched with `search-thing-at-point'
with a matching key binding."
(interactive (list (event-basic-type last-command-event)))
(search-forward (cdr (assq key search-thing-memory))))
(defun repeat-search-thing-at-point-backward (key)
"Repeat the last thing searched with `search-thing-at-point'
with a matching key binding."
(interactive (list (event-basic-type last-command-event)))
(search-backward (cdr (assq key search-thing-memory))))
(global-set-key [C-f2] 'search-thing-at-point)
(global-set-key [C-f3] 'search-thing-at-point)
(global-set-key [C-f4] 'search-thing-at-point)
(global-set-key [f2] 'repeat-search-thing-at-point-forward)
(global-set-key [f3] 'repeat-search-thing-at-point-forward)
(global-set-key [f4] 'repeat-search-thing-at-point-forward)
(global-set-key [S-f2] 'repeat-search-thing-at-point-backward)
(global-set-key [S-f3] 'repeat-search-thing-at-point-backward)
(global-set-key [S-f4] 'repeat-search-thing-at-point-backward)
I don't think your proposed interface is a particularly useful addition to Emacs. Emacs's basic built-in search has easy ways to search the thing at point and to repeat past searches.
C-u
; or, by prompting the user to enter a selection from the minibuffer, or ask the user to choose a particular key; e.g., press 1 for foo, press 2 for bar, press 3 for baz. [About 90% of the entire question is interesting, but not relevant to the very last question/answer (in my opinion). The second to the last question seeks an opinion.]