-
Notifications
You must be signed in to change notification settings - Fork 23
/
window-purpose-prefix-overload.el
108 lines (92 loc) · 3.74 KB
/
window-purpose-prefix-overload.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
;;; window-purpose-prefix-overload.el --- Bind several commands to the same key -*- lexical-binding: t -*-
;; Copyright (C) 2015-2021 Bar Magal & contributors
;; Author: Bar Magal
;; Package: purpose
;; This file is not part of GNU Emacs.
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This file contains functions and macros for using the same
;; key-binding for several commands (overloading). The correct command
;; is chosen by considering the prefix argument.
;;
;; For example, this binds `find-file' and
;; `find-file-without-purpose' to C-x C-f:
;; (def-prefix-overload purpose-find-file-overload
;; '(find-file find-file-without-purpose))
;; (define-key purpose-mode-map (kbd "C-x C-f")
;; #'purpose-find-file-overload)
;; To call `find-file', the user presses C-x C-f. To call
;; `find-file-without-purpose', the user presses C-u C-x C-f.
;;; Code:
(require 'cl-lib)
(defun purpose--prefix-arg-to-index (prefix-argument)
"Turn prefix argument PREFIX-ARGUMENT to a logical index.
Examples:
C-u <command>: index 1
C-u C-u <command>: index 2
C-u 2 <command>: index 2
C-u 1 2 <command>: index 12
<command>: index 0 (no prefix argument used)"
(cond
((null prefix-argument)
0)
((listp prefix-argument)
(round (log (car prefix-argument) 4)))
((eq prefix-argument '-)
-1)
(t
prefix-argument)))
(defun purpose--generate-documentation-def-prefix-overload (name commands)
(let ((doc-first (format "\\[%s]: `%s'" name (car commands)))
(doc-rest
(cl-loop for c in (cdr commands)
for i from 1
collect (format "%s \\[%s], C-u %s \\[%s]: `%s'"
(mapconcat #'identity
(cl-loop for j from 1 to i
collect "C-u")
" ")
name
i
name
c))))
(mapconcat
#'identity
(append
(list "This function was generated by `define-purpose-prefix-overload'."
""
doc-first)
doc-rest)
"\n")))
(defmacro define-purpose-prefix-overload (name commands)
"Define an interactive function named NAME, which calls interactively
one command from COMMANDS.
The command is chosen by the prefix argument:
no prefix argument: first command;
C-u or C-u 1: second command;
C-u C-u or C-u 2: third command;
and so on.
Use it like this:
(define-purpose-prefix-overload hello '(command1 command2 command3))"
(declare (indent defun) (debug (&define name (&rest sexp))))
(unless (eval commands)
(error "Argument COMMANDS cannot be empty"))
`(defun ,name (&optional arg)
,(purpose--generate-documentation-def-prefix-overload name (eval commands))
(interactive "P")
(let* ((index (purpose--prefix-arg-to-index arg))
(command (nth index ,commands)))
(if command
(call-interactively command)
(error "Index %s too big" index)))))
(provide 'window-purpose-prefix-overload)
;;; window-purpose-prefix-overload.el ends here