aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Kost <alezost@gmail.com>2015-11-18 22:28:13 +0300
committerAlex Kost <alezost@gmail.com>2016-01-02 17:25:35 +0300
commit4ba476f94992247cd54541ac09b0a516660f20e5 (patch)
treefc7fbed8d2aef413850f469fe96710d775942404
parent376af769f9cad7f521611c230d192ac639159fda (diff)
downloadgnu-guix-4ba476f94992247cd54541ac09b0a516660f20e5.tar
gnu-guix-4ba476f94992247cd54541ac09b0a516660f20e5.tar.gz
emacs: Add 'guix-keyword-args-let'.
* emacs/guix-utils.el (guix-keyword-args-let): New macro. (guix-utils-font-lock-keywords): Add it. * emacs/guix-base.el (guix-define-buffer-type): Use it. * emacs/guix-list.el (guix-list-define-entry-type): Use it. * emacs/guix-read.el (guix-define-readers): Use it.
-rw-r--r--emacs/guix-base.el106
-rw-r--r--emacs/guix-list.el70
-rw-r--r--emacs/guix-read.el28
-rw-r--r--emacs/guix-utils.el52
4 files changed, 139 insertions, 117 deletions
diff --git a/emacs/guix-base.el b/emacs/guix-base.el
index 91b52db188..f55e1c67e0 100644
--- a/emacs/guix-base.el
+++ b/emacs/guix-base.el
@@ -382,63 +382,55 @@ following keywords are available:
(buf-name-var (intern (concat prefix "-buffer-name")))
(revert-var (intern (concat prefix "-revert-no-confirm")))
(history-var (intern (concat prefix "-history-size")))
- (params-var (intern (concat prefix "-required-params")))
- (buf-name-val (format "*Guix %s %s*" Entry-type-str Buf-type-str))
- (revert-val nil)
- (history-val 20)
- (params-val '(id)))
-
- ;; Process the keyword args.
- (while (keywordp (car args))
- (pcase (pop args)
- (`:required (setq params-val (pop args)))
- (`:history-size (setq history-val (pop args)))
- (`:revert (setq revert-val (pop args)))
- (`:buffer-name (setq buf-name-val (pop args)))
- (_ (pop args))))
-
- `(progn
- (defgroup ,group nil
- ,(concat Buf-type-str " buffer with " entry-str ".")
- :prefix ,(concat prefix "-")
- :group ',(intern (concat "guix-" buf-type-str)))
-
- (defgroup ,faces-group nil
- ,(concat "Faces for " buf-type-str " buffer with " entry-str ".")
- :group ',(intern (concat "guix-" buf-type-str "-faces")))
-
- (defcustom ,buf-name-var ,buf-name-val
- ,(concat "Default name of the " buf-str " for displaying " entry-str ".")
- :type 'string
- :group ',group)
-
- (defcustom ,history-var ,history-val
- ,(concat "Maximum number of items saved in the history of the " buf-str ".\n"
- "If 0, the history is disabled.")
- :type 'integer
- :group ',group)
-
- (defcustom ,revert-var ,revert-val
- ,(concat "If non-nil, do not ask to confirm for reverting the " buf-str ".")
- :type 'boolean
- :group ',group)
-
- (defvar ,params-var ',params-val
- ,(concat "List of required " entry-type-str " parameters.\n\n"
- "Displayed parameters and parameters from this list are received\n"
- "for each " entry-type-str ".\n\n"
- "May be a special value `all', in which case all supported\n"
- "parameters are received (this may be very slow for a big number\n"
- "of entries).\n\n"
- "Do not remove `id' from this list as it is required for\n"
- "identifying an entry."))
-
- (define-derived-mode ,mode ,parent-mode ,(concat "Guix-" Buf-type-str)
- ,(concat "Major mode for displaying information about " entry-str ".\n\n"
- "\\{" mode-map-str "}")
- (setq-local revert-buffer-function 'guix-revert-buffer)
- (setq-local guix-history-size ,history-var)
- (and (fboundp ',mode-init-fun) (,mode-init-fun))))))
+ (params-var (intern (concat prefix "-required-params"))))
+ (guix-keyword-args-let args
+ ((params-val :required '(id))
+ (history-val :history-size 20)
+ (revert-val :revert)
+ (buf-name-val :buffer-name
+ (format "*Guix %s %s*" Entry-type-str Buf-type-str)))
+ `(progn
+ (defgroup ,group nil
+ ,(concat Buf-type-str " buffer with " entry-str ".")
+ :prefix ,(concat prefix "-")
+ :group ',(intern (concat "guix-" buf-type-str)))
+
+ (defgroup ,faces-group nil
+ ,(concat "Faces for " buf-type-str " buffer with " entry-str ".")
+ :group ',(intern (concat "guix-" buf-type-str "-faces")))
+
+ (defcustom ,buf-name-var ,buf-name-val
+ ,(concat "Default name of the " buf-str " for displaying " entry-str ".")
+ :type 'string
+ :group ',group)
+
+ (defcustom ,history-var ,history-val
+ ,(concat "Maximum number of items saved in the history of the " buf-str ".\n"
+ "If 0, the history is disabled.")
+ :type 'integer
+ :group ',group)
+
+ (defcustom ,revert-var ,revert-val
+ ,(concat "If non-nil, do not ask to confirm for reverting the " buf-str ".")
+ :type 'boolean
+ :group ',group)
+
+ (defvar ,params-var ',params-val
+ ,(concat "List of required " entry-type-str " parameters.\n\n"
+ "Displayed parameters and parameters from this list are received\n"
+ "for each " entry-type-str ".\n\n"
+ "May be a special value `all', in which case all supported\n"
+ "parameters are received (this may be very slow for a big number\n"
+ "of entries).\n\n"
+ "Do not remove `id' from this list as it is required for\n"
+ "identifying an entry."))
+
+ (define-derived-mode ,mode ,parent-mode ,(concat "Guix-" Buf-type-str)
+ ,(concat "Major mode for displaying information about " entry-str ".\n\n"
+ "\\{" mode-map-str "}")
+ (setq-local revert-buffer-function 'guix-revert-buffer)
+ (setq-local guix-history-size ,history-var)
+ (and (fboundp ',mode-init-fun) (,mode-init-fun)))))))
(put 'guix-define-buffer-type 'lisp-indent-function 'defun)
diff --git a/emacs/guix-list.el b/emacs/guix-list.el
index f0e20193c0..3e846a3377 100644
--- a/emacs/guix-list.el
+++ b/emacs/guix-list.el
@@ -416,45 +416,37 @@ This macro defines the following functions:
(prefix (concat "guix-" entry-type-str "-list"))
(mode-str (concat prefix "-mode"))
(init-fun (intern (concat prefix "-mode-initialize")))
- (marks-var (intern (concat prefix "-mark-alist")))
- (marks-val nil)
- (sort-key nil)
- (invert-sort nil))
-
- ;; Process the keyword args.
- (while (keywordp (car args))
- (pcase (pop args)
- (`:sort-key (setq sort-key (pop args)))
- (`:invert-sort (setq invert-sort (pop args)))
- (`:marks (setq marks-val (pop args)))
- (_ (pop args))))
-
- `(progn
- (defvar ,marks-var ',marks-val
- ,(concat "Alist of additional marks for `" mode-str "'.\n"
- "Marks from this list are added to `guix-list-mark-alist'."))
-
- ,@(mapcar (lambda (mark-spec)
- (let* ((mark-name (car mark-spec))
- (mark-name-str (symbol-name mark-name)))
- `(defun ,(intern (concat prefix "-mark-" mark-name-str "-simple")) ()
- ,(concat "Put '" mark-name-str "' mark and move to the next line.\n"
- "Also add the current entry to `guix-list-marked'.")
- (interactive)
- (guix-list--mark ',mark-name t))))
- marks-val)
-
- (defun ,init-fun ()
- ,(concat "Initial settings for `" mode-str "'.")
- ,(when sort-key
- `(setq tabulated-list-sort-key
- (guix-list-tabulated-sort-key
- ',entry-type ',sort-key ,invert-sort)))
- (setq tabulated-list-format
- (guix-list-tabulated-format ',entry-type))
- (setq-local guix-list-mark-alist
- (append guix-list-mark-alist ,marks-var))
- (tabulated-list-init-header)))))
+ (marks-var (intern (concat prefix "-mark-alist"))))
+ (guix-keyword-args-let args
+ ((sort-key :sort-key)
+ (invert-sort :invert-sort)
+ (marks-val :marks))
+ `(progn
+ (defvar ,marks-var ',marks-val
+ ,(concat "Alist of additional marks for `" mode-str "'.\n"
+ "Marks from this list are added to `guix-list-mark-alist'."))
+
+ ,@(mapcar (lambda (mark-spec)
+ (let* ((mark-name (car mark-spec))
+ (mark-name-str (symbol-name mark-name)))
+ `(defun ,(intern (concat prefix "-mark-" mark-name-str "-simple")) ()
+ ,(concat "Put '" mark-name-str "' mark and move to the next line.\n"
+ "Also add the current entry to `guix-list-marked'.")
+ (interactive)
+ (guix-list--mark ',mark-name t))))
+ marks-val)
+
+ (defun ,init-fun ()
+ ,(concat "Initial settings for `" mode-str "'.")
+ ,(when sort-key
+ `(setq tabulated-list-sort-key
+ (guix-list-tabulated-sort-key
+ ',entry-type ',sort-key ,invert-sort)))
+ (setq tabulated-list-format
+ (guix-list-tabulated-format ',entry-type))
+ (setq-local guix-list-mark-alist
+ (append guix-list-mark-alist ,marks-var))
+ (tabulated-list-init-header))))))
(put 'guix-list-define-entry-type 'lisp-indent-function 'defun)
diff --git a/emacs/guix-read.el b/emacs/guix-read.el
index e60af9c2f7..82eccbd678 100644
--- a/emacs/guix-read.el
+++ b/emacs/guix-read.el
@@ -66,26 +66,14 @@ keywords are available:
`<multiple-reader-name>-string' function returning a string
of multiple values separated the specified separator will be
defined."
- (let (completions-var
- completions-getter
- single-reader
- single-prompt
- multiple-reader
- multiple-prompt
- multiple-separator)
-
- ;; Process the keyword args.
- (while (keywordp (car args))
- (pcase (pop args)
- (`:completions-var (setq completions-var (pop args)))
- (`:completions-getter (setq completions-getter (pop args)))
- (`:single-reader (setq single-reader (pop args)))
- (`:single-prompt (setq single-prompt (pop args)))
- (`:multiple-reader (setq multiple-reader (pop args)))
- (`:multiple-prompt (setq multiple-prompt (pop args)))
- (`:multiple-separator (setq multiple-separator (pop args)))
- (_ (pop args))))
-
+ (guix-keyword-args-let args
+ ((completions-var :completions-var)
+ (completions-getter :completions-getter)
+ (single-reader :single-reader)
+ (single-prompt :single-prompt)
+ (multiple-reader :multiple-reader)
+ (multiple-prompt :multiple-prompt)
+ (multiple-separator :multiple-separator))
(let ((completions
(cond ((and completions-var completions-getter)
`(or ,completions-var
diff --git a/emacs/guix-utils.el b/emacs/guix-utils.el
index e24b58fb17..3748350b87 100644
--- a/emacs/guix-utils.el
+++ b/emacs/guix-utils.el
@@ -257,6 +257,55 @@ modifier call."
(guix-modify (funcall (car modifiers) object)
(cdr modifiers))))
+(defmacro guix-keyword-args-let (args varlist &rest body)
+ "Parse ARGS, bind variables from VARLIST and eval BODY.
+
+Find keyword values in ARGS, bind them to variables according to
+VARLIST, then evaluate BODY.
+
+ARGS is a keyword/value property list.
+
+Each element of VARLIST has a form:
+
+ (SYMBOL KEYWORD [DEFAULT-VALUE])
+
+SYMBOL is a varible name. KEYWORD is a symbol that will be
+searched in ARGS for an according value. If the value of KEYWORD
+does not exist, bind SYMBOL to DEFAULT-VALUE or nil.
+
+The rest arguments (that present in ARGS but not in VARLIST) will
+be bound to `%foreign-args' variable.
+
+Example:
+
+ (guix-keyword-args-let '(:two 8 :great ! :guix is)
+ ((one :one 1)
+ (two :two 2)
+ (foo :smth))
+ (list one two foo %foreign-args))
+
+ => (1 8 nil (:guix is :great !))"
+ (declare (indent 2))
+ (let ((args-var (make-symbol "args")))
+ `(let (,@(mapcar (lambda (spec)
+ (pcase-let ((`(,name ,_ ,val) spec))
+ (list name val)))
+ varlist)
+ (,args-var ,args)
+ %foreign-args)
+ (while ,args-var
+ (pcase ,args-var
+ (`(,key ,val . ,rest-args)
+ (cl-case key
+ ,@(mapcar (lambda (spec)
+ (pcase-let ((`(,name ,key ,_) spec))
+ `(,key (setq ,name val))))
+ varlist)
+ (t (setq %foreign-args
+ (cl-list* key val %foreign-args))))
+ (setq ,args-var rest-args))))
+ ,@body)))
+
;;; Alist accessors
@@ -326,7 +375,8 @@ See `defun' for the meaning of arguments."
(defvar guix-utils-font-lock-keywords
(eval-when-compile
- `((,(rx "(" (group "guix-with-indent")
+ `((,(rx "(" (group (or "guix-keyword-args-let"
+ "guix-with-indent"))
symbol-end)
. 1)
(,(rx "("