unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#18729: [PATCH] subr.el (set-key): New macro making creating new bindings more concise.
@ 2014-10-15  7:48 Michal Nazarewicz
  2014-10-15 14:20 ` Stefan Monnier
  2015-01-19 15:40 ` Michal Nazarewicz
  0 siblings, 2 replies; 6+ messages in thread
From: Michal Nazarewicz @ 2014-10-15  7:48 UTC (permalink / raw)
  To: 18729


---
 lisp/ChangeLog |  6 +++++
 lisp/subr.el   | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

 I found this macro very convenient for my configuration file, so
 perhaps it's a good match for inclusion in Emacs?  It handles the
 majority of uses of 

diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 6916143..a5c4632 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,9 @@
+2014-10-15  Michal Nazarewicz  <mina86@mina86.com>
+
+	* subr.el (set-key): New macro making creating new bindings more
+	concise and thus somehow easier/faster to type in user
+	configuration file.
+
 2014-10-15  Eli Zaretskii  <eliz@gnu.org>
 
 	* emacs-lisp/tabulated-list.el (tabulated-list-mode): Force
diff --git a/lisp/subr.el b/lisp/subr.el
index 585f936..9b1ceb3 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -836,6 +836,79 @@ cases is shared with all other buffers in the same major mode."
 	(signal 'wrong-type-argument (list 'arrayp key)))
     (define-key map key command)))
 
+(defun set-key--current-local-map ()
+  "Return current local map creating one if not set yet."
+  (or (current-local-map)
+      (let ((map (make-sparse-keymap)))
+        (use-local-map map)
+        map)))
+
+(defmacro set-key (keymap key &rest def)
+  "(set-key [KEYMAP] KEY . DEF)
+
+In KEYMAP, define key sequence KEY as DEF.
+
+KEYMAP can be :global (to mean global keymap, the default), :local (to mean
+the local keymap) or an unquoted symbol (to mean a keymap in given variable).
+
+KEY is anything `define-key' accepts as a key except that if KEYMAP was not
+given, KEY cannot be an unquoted symbol, i.e.:
+    (let ((key \"a\"))
+      (set-key         key self-insert-command)  ; will *not* work
+      (set-key :global key self-insert-command)) ; will work
+
+If DEF is a single unquoted symbol it will be quoted, otherwise if it is
+a single non-cons value it will not be quoted, otherwise it will be processed
+as a lambda (see below).  Thus the following do what one might expect:
+    (set-key \"a\" self-insert-command)
+        ;; same as (global-set-key \"a\" 'self-insert-command)
+    (set-key \"\\C-h\" [(backspace)])
+        ;; same as (global-set-key \"\\C-h\" [(backspace)])
+    (set-key \"\\C-d\" ())
+        ;; same as (global-set-key \"\\C-h\" ())
+However, the following will not work:
+    (let ((callback 'self-insert-command))
+      (set-key \"a\" callback))
+        ;; same as (global-set-key \"a\" 'callback)
+
+If DEF is a cons value its format is:
+    ([:args ARGS INTERACTIVE] . BODY)
+and results in the following lambda:
+    (lambda ARGS (interactive INTERACTIVE) . BODY)
+or if :args is not given (at which point DEF == BODY):
+    (lambda () (interactive) . BODY)
+For example:
+    (set-key \"\\C-B\" (goto-char (- (point) 2)))
+        ;; same as (global-set-key \"\\C-B\"
+        ;;           (lambda () (interactive) (goto-char (- (point) 2))))
+    (set-key \"\\C-B\" :args (n) \"P\" (goto-char (- (point) (* 2 n))))
+        ;; same as (global-set-key \"\\C-B\"
+        ;;           (lambda (n) (interactive \"P\")
+        ;;             (goto-char (- (point) (* 2 n)))))
+
+This macro is not a replacement for `define-key', `global-set-key' or
+`local-set-key', since it is not capable of dealing with some forms of DEFs
+that those functions accept.  Instead it is meant as a helper to use in user
+configuration file to make setting up bindings more concise especially when
+lambdas are used."
+  (setq keymap (cond ((eq :local keymap)  '(set-key--current-local-map))
+                     ((eq :global keymap) '(current-global-map))
+                     ((symbolp keymap) keymap)
+                     (t
+                      (setq def (cons key def) key keymap) ; shift args
+                      '(current-global-map))))
+  (unless def
+    (error "DEF argument missing"))
+  (list
+   'define-key keymap key
+   (cond ((or (cdr def) (consp (car def)))
+          (let ((args        (if (eq :args (car def)) (cadr def)))
+                (interactive (if (eq :args (car def)) (list (car (cddr def)))))
+                (body        (if (eq :args (car def)) (cdr (cddr def)) def)))
+            `(function (lambda ,args (interactive . ,interactive) ,@body))))
+         ((symbolp (car def)) (list 'quote (car def)))
+         ((car def)))))
+
 (defun global-unset-key (key)
   "Remove global binding of KEY.
 KEY is a string or vector representing a sequence of keystrokes."





^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-01-19 15:40 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-15  7:48 bug#18729: [PATCH] subr.el (set-key): New macro making creating new bindings more concise Michal Nazarewicz
2014-10-15 14:20 ` Stefan Monnier
2014-10-16 12:39   ` Michal Nazarewicz
2014-10-16 14:50     ` Stefan Monnier
2014-10-27 17:52       ` Michal Nazarewicz
2015-01-19 15:40 ` Michal Nazarewicz

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).