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.
This commit is contained in:
		
							parent
							
								
									376af769f9
								
							
						
					
					
						commit
						4ba476f949
					
				
					 4 changed files with 131 additions and 109 deletions
				
			
		| 
						 | 
					@ -382,21 +382,13 @@ following keywords are available:
 | 
				
			||||||
         (buf-name-var   (intern (concat prefix "-buffer-name")))
 | 
					         (buf-name-var   (intern (concat prefix "-buffer-name")))
 | 
				
			||||||
         (revert-var     (intern (concat prefix "-revert-no-confirm")))
 | 
					         (revert-var     (intern (concat prefix "-revert-no-confirm")))
 | 
				
			||||||
         (history-var    (intern (concat prefix "-history-size")))
 | 
					         (history-var    (intern (concat prefix "-history-size")))
 | 
				
			||||||
         (params-var     (intern (concat prefix "-required-params")))
 | 
					         (params-var     (intern (concat prefix "-required-params"))))
 | 
				
			||||||
         (buf-name-val   (format "*Guix %s %s*" Entry-type-str Buf-type-str))
 | 
					    (guix-keyword-args-let args
 | 
				
			||||||
         (revert-val     nil)
 | 
					        ((params-val :required '(id))
 | 
				
			||||||
         (history-val    20)
 | 
					         (history-val :history-size 20)
 | 
				
			||||||
         (params-val     '(id)))
 | 
					         (revert-val :revert)
 | 
				
			||||||
 | 
					         (buf-name-val :buffer-name
 | 
				
			||||||
    ;; Process the keyword args.
 | 
					                       (format "*Guix %s %s*" Entry-type-str Buf-type-str)))
 | 
				
			||||||
    (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
 | 
					      `(progn
 | 
				
			||||||
         (defgroup ,group nil
 | 
					         (defgroup ,group nil
 | 
				
			||||||
           ,(concat Buf-type-str " buffer with " entry-str ".")
 | 
					           ,(concat Buf-type-str " buffer with " entry-str ".")
 | 
				
			||||||
| 
						 | 
					@ -438,7 +430,7 @@ following keywords are available:
 | 
				
			||||||
                    "\\{" mode-map-str "}")
 | 
					                    "\\{" mode-map-str "}")
 | 
				
			||||||
           (setq-local revert-buffer-function 'guix-revert-buffer)
 | 
					           (setq-local revert-buffer-function 'guix-revert-buffer)
 | 
				
			||||||
           (setq-local guix-history-size ,history-var)
 | 
					           (setq-local guix-history-size ,history-var)
 | 
				
			||||||
         (and (fboundp ',mode-init-fun) (,mode-init-fun))))))
 | 
					           (and (fboundp ',mode-init-fun) (,mode-init-fun)))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(put 'guix-define-buffer-type 'lisp-indent-function 'defun)
 | 
					(put 'guix-define-buffer-type 'lisp-indent-function 'defun)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -416,19 +416,11 @@ This macro defines the following functions:
 | 
				
			||||||
         (prefix         (concat "guix-" entry-type-str "-list"))
 | 
					         (prefix         (concat "guix-" entry-type-str "-list"))
 | 
				
			||||||
         (mode-str       (concat prefix "-mode"))
 | 
					         (mode-str       (concat prefix "-mode"))
 | 
				
			||||||
         (init-fun       (intern (concat prefix "-mode-initialize")))
 | 
					         (init-fun       (intern (concat prefix "-mode-initialize")))
 | 
				
			||||||
         (marks-var      (intern (concat prefix "-mark-alist")))
 | 
					         (marks-var      (intern (concat prefix "-mark-alist"))))
 | 
				
			||||||
         (marks-val      nil)
 | 
					    (guix-keyword-args-let args
 | 
				
			||||||
         (sort-key       nil)
 | 
					        ((sort-key :sort-key)
 | 
				
			||||||
         (invert-sort    nil))
 | 
					         (invert-sort :invert-sort)
 | 
				
			||||||
 | 
					         (marks-val :marks))
 | 
				
			||||||
    ;; 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
 | 
					      `(progn
 | 
				
			||||||
         (defvar ,marks-var ',marks-val
 | 
					         (defvar ,marks-var ',marks-val
 | 
				
			||||||
           ,(concat "Alist of additional marks for `" mode-str "'.\n"
 | 
					           ,(concat "Alist of additional marks for `" mode-str "'.\n"
 | 
				
			||||||
| 
						 | 
					@ -454,7 +446,7 @@ This macro defines the following functions:
 | 
				
			||||||
                 (guix-list-tabulated-format ',entry-type))
 | 
					                 (guix-list-tabulated-format ',entry-type))
 | 
				
			||||||
           (setq-local guix-list-mark-alist
 | 
					           (setq-local guix-list-mark-alist
 | 
				
			||||||
                       (append guix-list-mark-alist ,marks-var))
 | 
					                       (append guix-list-mark-alist ,marks-var))
 | 
				
			||||||
         (tabulated-list-init-header)))))
 | 
					           (tabulated-list-init-header))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(put 'guix-list-define-entry-type 'lisp-indent-function 'defun)
 | 
					(put 'guix-list-define-entry-type 'lisp-indent-function 'defun)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,26 +66,14 @@ keywords are available:
 | 
				
			||||||
    `<multiple-reader-name>-string' function returning a string
 | 
					    `<multiple-reader-name>-string' function returning a string
 | 
				
			||||||
    of multiple values separated the specified separator will be
 | 
					    of multiple values separated the specified separator will be
 | 
				
			||||||
    defined."
 | 
					    defined."
 | 
				
			||||||
  (let (completions-var
 | 
					  (guix-keyword-args-let args
 | 
				
			||||||
        completions-getter
 | 
					      ((completions-var    :completions-var)
 | 
				
			||||||
        single-reader
 | 
					       (completions-getter :completions-getter)
 | 
				
			||||||
        single-prompt
 | 
					       (single-reader      :single-reader)
 | 
				
			||||||
        multiple-reader
 | 
					       (single-prompt      :single-prompt)
 | 
				
			||||||
        multiple-prompt
 | 
					       (multiple-reader    :multiple-reader)
 | 
				
			||||||
        multiple-separator)
 | 
					       (multiple-prompt    :multiple-prompt)
 | 
				
			||||||
 | 
					       (multiple-separator :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))))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    (let ((completions
 | 
					    (let ((completions
 | 
				
			||||||
           (cond ((and completions-var completions-getter)
 | 
					           (cond ((and completions-var completions-getter)
 | 
				
			||||||
                  `(or ,completions-var
 | 
					                  `(or ,completions-var
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -257,6 +257,55 @@ modifier call."
 | 
				
			||||||
    (guix-modify (funcall (car modifiers) object)
 | 
					    (guix-modify (funcall (car modifiers) object)
 | 
				
			||||||
                 (cdr modifiers))))
 | 
					                 (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
 | 
					;;; Alist accessors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -326,7 +375,8 @@ See `defun' for the meaning of arguments."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defvar guix-utils-font-lock-keywords
 | 
					(defvar guix-utils-font-lock-keywords
 | 
				
			||||||
  (eval-when-compile
 | 
					  (eval-when-compile
 | 
				
			||||||
    `((,(rx "(" (group "guix-with-indent")
 | 
					    `((,(rx "(" (group (or "guix-keyword-args-let"
 | 
				
			||||||
 | 
					                           "guix-with-indent"))
 | 
				
			||||||
            symbol-end)
 | 
					            symbol-end)
 | 
				
			||||||
       . 1)
 | 
					       . 1)
 | 
				
			||||||
      (,(rx "("
 | 
					      (,(rx "("
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in a new issue