emacs: info: Generalize inserting and formatting.
* emacs/guix-info.el: Use a more flexible format for inserting any data. (guix-info-ignore-empty-vals): Rename to... (guix-info-ignore-empty-values): ... this. (guix-info-insert-methods): Merge this and... (guix-info-displayed-params): ... this into... (guix-info-format): ... this. Change format specifications. (guix-info-title-aliases, guix-info-value-aliases): New variables. (guix-info-displayed-params): Adjust for the new format. (guix-info-insert-entry): Likewise. (guix-package-info-fill-heading): Replace with... (guix-info-fill): ... this. (guix-info-insert-param): Replace with... (guix-info-insert-entry-unit): ... this. (guix-info-insert-title-default): Replace with... (guix-info-insert-title-format): ... this. (guix-info-insert-val-default): Replace with... (guix-info-insert-value-format): ... this. (guix-info-insert-val-simple): Replace with... (guix-info-insert-value-indent): ... this. (guix-package-info-insert-source): Adjust accordingly. (guix-package-info-insert-heading): Insert only name and version. (guix-package-info-define-insert-inputs): Do not generate 'guix-package-info-insert-ENTRY-TYPE-inputs' procedures. (guix-info-fill-column, guix-info-insert-entry-default) (guix-info-method-funcall, guix-info-insert-file-path) (guix-info-insert-url, guix-info-insert-package-function) (guix-info-insert-installed-function) (guix-info-insert-output-function) (guix-info-insert-generation-function) (guix-package-info-heading-params) (guix-package-info-insert-with-heading) (guix-package-info-insert-description) (guix-package-info-insert-location) (guix-package-info-insert-full-names) (guix-package-info-insert-source-url): Remove. (guix-info-fill-column, guix-info-param-title) (guix-info-title-function, guix-info-value-function) (guix-info-title-method->function) (guix-info-value-method->function) (guix-info-insert-value-simple): New procedures. * emacs/guix-utils.el (guix-buttonize, guix-button-type?): New procedures. (guix-split-string): Split multi-line strings and ignore empty lines. * doc/emacs.texi (Emacs Appearance): Adjust accordingly.
This commit is contained in:
		
							parent
							
								
									25d2fe8bef
								
							
						
					
					
						commit
						2c7ed388cf
					
				
					 3 changed files with 277 additions and 301 deletions
				
			
		|  | @ -484,13 +484,12 @@ the following variables (@dfn{ENTRY-TYPE} means @code{package}, | |||
| Specify the columns, their names, what and how is displayed in ``list'' | ||||
| buffers. | ||||
| 
 | ||||
| @item guix-info-displayed-params | ||||
| @itemx guix-info-insert-methods | ||||
| @itemx guix-info-ignore-empty-vals | ||||
| @item guix-info-format | ||||
| @itemx guix-info-ignore-empty-values | ||||
| @itemx guix-info-param-title-format | ||||
| @itemx guix-info-multiline-prefix | ||||
| @itemx guix-info-indent | ||||
| @itemx guix-info-fill-column | ||||
| @itemx guix-info-fill | ||||
| @itemx guix-info-delimiter | ||||
| Various settings for ``info'' buffers. | ||||
| 
 | ||||
|  |  | |||
|  | @ -81,122 +81,175 @@ | |||
|   "Mouse face used for action buttons." | ||||
|   :group 'guix-info-faces) | ||||
| 
 | ||||
| (defcustom guix-info-ignore-empty-vals nil | ||||
| (defcustom guix-info-ignore-empty-values nil | ||||
|   "If non-nil, do not display parameters with nil values." | ||||
|   :type 'boolean | ||||
|   :group 'guix-info) | ||||
| 
 | ||||
| (defcustom guix-info-fill t | ||||
|   "If non-nil, fill string parameters to fit the window. | ||||
| If nil, insert text parameters (like synopsis or description) in | ||||
| a raw form." | ||||
|   :type 'boolean | ||||
|   :group 'guix-info) | ||||
| 
 | ||||
| (defvar guix-info-param-title-format "%-18s: " | ||||
|   "String used to format a title of a parameter. | ||||
| It should be a '%s'-sequence.  After inserting a title formatted | ||||
| with this string, a value of the parameter is inserted. | ||||
| This string is used by `guix-info-insert-title-default'.") | ||||
| This string is used by `guix-info-insert-title-format'.") | ||||
| 
 | ||||
| (defvar guix-info-multiline-prefix (make-string 20 ?\s) | ||||
| (defvar guix-info-multiline-prefix | ||||
|   (make-string (length (format guix-info-param-title-format " ")) | ||||
|                ?\s) | ||||
|   "String used to format multi-line parameter values. | ||||
| If a value occupies more than one line, this string is inserted | ||||
| in the beginning of each line after the first one. | ||||
| This string is used by `guix-info-insert-val-default'.") | ||||
| This string is used by `guix-info-insert-value-format'.") | ||||
| 
 | ||||
| (defvar guix-info-indent 2 | ||||
|   "Number of spaces used to indent various parts of inserted text.") | ||||
| 
 | ||||
| (defvar guix-info-fill-column 60 | ||||
|   "Column used for filling (word wrapping) parameters with long lines. | ||||
| If a value is not multi-line and it occupies more than this | ||||
| number of characters, it will be split into several lines.") | ||||
| 
 | ||||
| (defvar guix-info-delimiter "\n\f\n" | ||||
|   "String used to separate entries.") | ||||
| 
 | ||||
| (defvar guix-info-insert-methods | ||||
| (defvar guix-info-format | ||||
|   '((package | ||||
|      (name              guix-package-info-name) | ||||
|      (version           guix-package-info-version) | ||||
|      (license           guix-package-info-license) | ||||
|      (synopsis          guix-package-info-synopsis) | ||||
|      (description       guix-package-info-insert-description | ||||
|                         guix-info-insert-title-simple) | ||||
|      (outputs           guix-package-info-insert-outputs | ||||
|                         guix-info-insert-title-simple) | ||||
|      (source            guix-package-info-insert-source | ||||
|                         guix-info-insert-title-simple) | ||||
|      (home-url          guix-info-insert-url) | ||||
|      (inputs            guix-package-info-insert-inputs) | ||||
|      (native-inputs     guix-package-info-insert-native-inputs) | ||||
|      (propagated-inputs guix-package-info-insert-propagated-inputs) | ||||
|      (location          guix-package-info-insert-location)) | ||||
|      guix-package-info-insert-heading | ||||
|      ignore | ||||
|      (synopsis ignore (simple guix-package-info-synopsis)) | ||||
|      ignore | ||||
|      (description ignore (simple guix-package-info-description)) | ||||
|      ignore | ||||
|      (outputs simple guix-package-info-insert-outputs) | ||||
|      (source simple guix-package-info-insert-source) | ||||
|      (location format (format guix-package-location)) | ||||
|      (home-url format (format guix-url)) | ||||
|      (license format (format guix-package-info-license)) | ||||
|      (inputs format (format guix-package-input)) | ||||
|      (native-inputs format (format guix-package-native-input)) | ||||
|      (propagated-inputs format (format guix-package-propagated-input))) | ||||
|     (installed | ||||
|      (path              guix-package-info-insert-output-path | ||||
|                         guix-info-insert-title-simple) | ||||
|      (dependencies      guix-package-info-insert-output-dependencies | ||||
|                         guix-info-insert-title-simple)) | ||||
|      (path simple (indent guix-file)) | ||||
|      (dependencies simple (indent guix-file))) | ||||
|     (output | ||||
|      (name              guix-package-info-name) | ||||
|      (version           guix-output-info-insert-version) | ||||
|      (output            guix-output-info-insert-output) | ||||
|      (source            guix-package-info-insert-source | ||||
|                         guix-info-insert-title-simple) | ||||
|      (path              guix-package-info-insert-output-path | ||||
|                         guix-info-insert-title-simple) | ||||
|      (dependencies      guix-package-info-insert-output-dependencies | ||||
|                         guix-info-insert-title-simple) | ||||
|      (license           guix-package-info-license) | ||||
|      (synopsis          guix-package-info-synopsis) | ||||
|      (description       guix-package-info-insert-description | ||||
|                         guix-info-insert-title-simple) | ||||
|      (home-url          guix-info-insert-url) | ||||
|      (inputs            guix-package-info-insert-inputs) | ||||
|      (native-inputs     guix-package-info-insert-native-inputs) | ||||
|      (propagated-inputs guix-package-info-insert-propagated-inputs) | ||||
|      (location          guix-package-info-insert-location)) | ||||
|      (name format (format guix-package-info-name)) | ||||
|      (version format guix-output-info-insert-version) | ||||
|      (output format guix-output-info-insert-output) | ||||
|      (synopsis simple (indent guix-package-info-synopsis)) | ||||
|      (source simple guix-package-info-insert-source) | ||||
|      (path simple (indent guix-file)) | ||||
|      (dependencies simple (indent guix-file)) | ||||
|      (location format (format guix-package-location)) | ||||
|      (home-url format (format guix-url)) | ||||
|      (license format (format guix-package-info-license)) | ||||
|      (inputs format (format guix-package-input)) | ||||
|      (native-inputs format (format guix-package-native-input)) | ||||
|      (propagated-inputs format (format guix-package-propagated-input)) | ||||
|      (description simple (indent guix-package-info-description))) | ||||
|     (generation | ||||
|      (number            guix-generation-info-insert-number) | ||||
|      (current           guix-generation-info-insert-current) | ||||
|      (path              guix-info-insert-file-path) | ||||
|      (time              guix-info-insert-time))) | ||||
|      (number format guix-generation-info-insert-number) | ||||
|      (prev-number format (format)) | ||||
|      (current format guix-generation-info-insert-current) | ||||
|      (path simple (indent guix-file)) | ||||
|      (time format (time)))) | ||||
|   "Methods for inserting parameter values. | ||||
| Each element of the list should have a form: | ||||
| 
 | ||||
|   (ENTRY-TYPE . ((PARAM INSERT-VALUE [INSERT-TITLE]) ...)) | ||||
|   (ENTRY-TYPE . (METHOD ...)) | ||||
| 
 | ||||
| INSERT-VALUE may be either nil, a face name or a function.  If it | ||||
| is nil or a face, `guix-info-insert-val-default' function is | ||||
| called with parameter value and INSERT-VALUE as arguments.  If it | ||||
| is a function, this function is called with parameter value and | ||||
| entry info (alist of parameters and their values) as arguments. | ||||
| Each METHOD should be either a function or should have the | ||||
| following form: | ||||
| 
 | ||||
| INSERT-TITLE may be either nil, a face name or a function.  If it | ||||
| is nil or a face, `guix-info-insert-title-default' function is | ||||
| called with parameter title and INSERT-TITLE as arguments.  If it | ||||
| is a function, this function is called with parameter title as | ||||
| argument.") | ||||
|   (PARAM INSERT-TITLE INSERT-VALUE) | ||||
| 
 | ||||
| (defvar guix-info-displayed-params | ||||
|   '((package name version synopsis outputs source location home-url | ||||
|              license inputs native-inputs propagated-inputs description) | ||||
|     (output name version output synopsis source path dependencies location | ||||
|             home-url license inputs native-inputs propagated-inputs | ||||
|             description) | ||||
|     (installed path dependencies) | ||||
|     (generation number prev-number current time path)) | ||||
|   "List of displayed entry parameters. | ||||
| Each element of the list should have a form: | ||||
| If METHOD is a function, it is called with an entry as argument. | ||||
| 
 | ||||
|   (ENTRY-TYPE . (PARAM ...)) | ||||
| PARAM is a name of entry parameter. | ||||
| 
 | ||||
| The order of displayed parameters is the same as in this list.") | ||||
| INSERT-TITLE may be either a symbol or a list.  If it is a | ||||
| symbol, it should be a function or an alias from | ||||
| `guix-info-title-aliases', in which case it is called with title | ||||
| as argument.  If it is a list, it should have a | ||||
| form (FUN-OR-ALIAS [ARGS ...]), in which case FUN-OR-ALIAS is | ||||
| called with title and ARGS as arguments. | ||||
| 
 | ||||
| (defun guix-info-insert-methods (entry-type param) | ||||
|   "Return list of insert methods for parameter PARAM of ENTRY-TYPE. | ||||
| See `guix-info-insert-methods' for details." | ||||
|   (guix-assq-value guix-info-insert-methods | ||||
|                    entry-type param)) | ||||
| INSERT-VALUE may be either a symbol or a list.  If it is a | ||||
| symbol, it should be a function or an alias from | ||||
| `guix-info-value-aliases', in which case it is called with value | ||||
| and entry as arguments.  If it is a list, it should have a | ||||
| form (FUN-OR-ALIAS [ARGS ...]), in which case FUN-OR-ALIAS is | ||||
| called with value and ARGS as arguments. | ||||
| 
 | ||||
| Parameters are inserted in the same order as defined by this list. | ||||
| After calling each METHOD, a new line is inserted.") | ||||
| 
 | ||||
| (defun guix-info-param-title (entry-type param) | ||||
|   "Return a title of an ENTRY-TYPE parameter PARAM." | ||||
|   (guix-get-param-title entry-type param)) | ||||
| 
 | ||||
| (defun guix-info-format (entry-type) | ||||
|   "Return 'info' format for ENTRY-TYPE." | ||||
|   (guix-assq-value guix-info-format entry-type)) | ||||
| 
 | ||||
| (defun guix-info-displayed-params (entry-type) | ||||
|   "Return parameters of ENTRY-TYPE that should be displayed." | ||||
|   (guix-assq-value guix-info-displayed-params | ||||
|                    entry-type)) | ||||
|   "Return a list of ENTRY-TYPE parameters that should be displayed." | ||||
|   (delq nil | ||||
|         (mapcar (lambda (spec) | ||||
|                   (pcase spec | ||||
|                     (`(,param . ,_) param))) | ||||
|                 (guix-info-format entry-type)))) | ||||
| 
 | ||||
|  | ||||
| ;;; Inserting entries | ||||
| 
 | ||||
| (defvar guix-info-title-aliases | ||||
|   '((format . guix-info-insert-title-format) | ||||
|     (simple . guix-info-insert-title-simple)) | ||||
|   "Alist of aliases and functions to insert titles.") | ||||
| 
 | ||||
| (defvar guix-info-value-aliases | ||||
|   '((format . guix-info-insert-value-format) | ||||
|     (indent . guix-info-insert-value-indent) | ||||
|     (simple . guix-info-insert-value-simple) | ||||
|     (time   . guix-info-insert-time)) | ||||
|   "Alist of aliases and functions to insert values.") | ||||
| 
 | ||||
| (defun guix-info-title-function (fun-or-alias) | ||||
|   "Convert FUN-OR-ALIAS into a function to insert a title." | ||||
|   (or (guix-assq-value guix-info-title-aliases fun-or-alias) | ||||
|       fun-or-alias)) | ||||
| 
 | ||||
| (defun guix-info-value-function (fun-or-alias) | ||||
|   "Convert FUN-OR-ALIAS into a function to insert a value." | ||||
|   (or (guix-assq-value guix-info-value-aliases fun-or-alias) | ||||
|       fun-or-alias)) | ||||
| 
 | ||||
| (defun guix-info-title-method->function (method) | ||||
|   "Convert title METHOD into a function to insert a title." | ||||
|   (pcase method | ||||
|     ((pred null) #'ignore) | ||||
|     ((pred symbolp) (guix-info-title-function method)) | ||||
|     (`(,fun-or-alias . ,rest-args) | ||||
|      (lambda (title) | ||||
|        (apply (guix-info-title-function fun-or-alias) | ||||
|               title rest-args))) | ||||
|     (_ (error "Unknown title method '%S'" method)))) | ||||
| 
 | ||||
| (defun guix-info-value-method->function (method) | ||||
|   "Convert value METHOD into a function to insert a value." | ||||
|   (pcase method | ||||
|     ((pred null) #'ignore) | ||||
|     ((pred functionp) method) | ||||
|     (`(,fun-or-alias . ,rest-args) | ||||
|      (lambda (value _) | ||||
|        (apply (guix-info-value-function fun-or-alias) | ||||
|               value rest-args))) | ||||
|     (_ (error "Unknown value method '%S'" method)))) | ||||
| 
 | ||||
| (defun guix-info-fill-column () | ||||
|   "Return fill column for the current window." | ||||
|   (min (window-width) fill-column)) | ||||
| 
 | ||||
| (defun guix-info-get-indent (&optional level) | ||||
|   "Return `guix-info-indent' \"multiplied\" by LEVEL spaces. | ||||
|  | @ -215,115 +268,122 @@ ENTRIES should have a form of `guix-entries'." | |||
|                   entries | ||||
|                   guix-info-delimiter)) | ||||
| 
 | ||||
| (defun guix-info-insert-entry-default (entry entry-type | ||||
|                                        &optional indent-level) | ||||
|   "Insert ENTRY of ENTRY-TYPE into the current info buffer. | ||||
| If INDENT-LEVEL is non-nil, indent displayed information by this | ||||
| number of `guix-info-indent' spaces." | ||||
|   (guix-with-indent (* (or indent-level 0) | ||||
|                        guix-info-indent) | ||||
|     (mapc (lambda (param) | ||||
|             (guix-info-insert-param param entry entry-type)) | ||||
|           (guix-info-displayed-params entry-type)))) | ||||
| 
 | ||||
| (defun guix-info-insert-entry (entry entry-type &optional indent-level) | ||||
|   "Insert ENTRY of ENTRY-TYPE into the current info buffer. | ||||
| Use `guix-info-insert-ENTRY-TYPE-function' or | ||||
| `guix-info-insert-entry-default' if it is nil." | ||||
|   (let* ((var (intern (concat "guix-info-insert-" | ||||
|                               (symbol-name entry-type) | ||||
|                               "-function"))) | ||||
|          (fun (symbol-value var))) | ||||
|     (if (functionp fun) | ||||
|         (funcall fun entry) | ||||
|       (guix-info-insert-entry-default entry entry-type indent-level)))) | ||||
| If INDENT-LEVEL is non-nil, indent displayed data by this number | ||||
| of `guix-info-indent' spaces." | ||||
|   (guix-with-indent (* (or indent-level 0) | ||||
|                        guix-info-indent) | ||||
|     (dolist (spec (guix-info-format entry-type)) | ||||
|       (guix-info-insert-entry-unit spec entry entry-type)))) | ||||
| 
 | ||||
| (defun guix-info-insert-param (param entry entry-type) | ||||
| (defun guix-info-insert-entry-unit (format-spec entry entry-type) | ||||
|   "Insert title and value of a PARAM at point. | ||||
| ENTRY is alist with parameters and their values. | ||||
| ENTRY-TYPE is a type of ENTRY." | ||||
|   (let ((val (guix-entry-value entry param))) | ||||
|     (unless (and guix-info-ignore-empty-vals (null val)) | ||||
|       (let* ((title          (guix-get-param-title entry-type param)) | ||||
|              (insert-methods (guix-info-insert-methods entry-type param)) | ||||
|              (val-method     (car insert-methods)) | ||||
|              (title-method   (cadr insert-methods))) | ||||
|         (guix-info-method-funcall title title-method | ||||
|                                   #'guix-info-insert-title-default) | ||||
|         (guix-info-method-funcall val val-method | ||||
|                                   #'guix-info-insert-val-default | ||||
|                                   entry) | ||||
|         (insert "\n"))))) | ||||
| 
 | ||||
| (defun guix-info-method-funcall (val method default-fun &rest args) | ||||
|   "Call METHOD or DEFAULT-FUN. | ||||
| 
 | ||||
| If METHOD is a function and VAL is non-nil, call this | ||||
| function by applying it to VAL and ARGS. | ||||
| 
 | ||||
| If METHOD is a face, propertize inserted VAL with this face." | ||||
|   (cond ((or (null method) | ||||
|              (facep method)) | ||||
|          (funcall default-fun val method)) | ||||
|         ((functionp method) | ||||
|          (apply method val args)) | ||||
|         (t (error "Unknown method '%S'" method)))) | ||||
| 
 | ||||
| (defun guix-info-insert-title-default (title &optional face format) | ||||
|   "Insert TITLE formatted with `guix-info-param-title-format' at point." | ||||
|   (guix-format-insert title | ||||
|                       (or face 'guix-info-param-title) | ||||
|                       (or format guix-info-param-title-format))) | ||||
|   (pcase format-spec | ||||
|     ((pred functionp) | ||||
|      (funcall format-spec entry) | ||||
|      (insert "\n")) | ||||
|     (`(,param ,title-method ,value-method) | ||||
|      (let ((value (guix-entry-value entry param))) | ||||
|        (unless (and guix-info-ignore-empty-values (null value)) | ||||
|          (let ((title        (guix-info-param-title entry-type param)) | ||||
|                (insert-title (guix-info-title-method->function title-method)) | ||||
|                (insert-value (guix-info-value-method->function value-method))) | ||||
|            (funcall insert-title title) | ||||
|            (funcall insert-value value entry) | ||||
|            (insert "\n"))))) | ||||
|     (_ (error "Unknown format specification '%S'" format-spec)))) | ||||
| 
 | ||||
| (defun guix-info-insert-title-simple (title &optional face) | ||||
|   "Insert TITLE at point." | ||||
|   (guix-info-insert-title-default title face "%s:")) | ||||
|   "Insert \"TITLE: \" string at point. | ||||
| If FACE is nil, use `guix-info-param-title'." | ||||
|   (guix-format-insert title | ||||
|                       (or face 'guix-info-param-title) | ||||
|                       "%s: ")) | ||||
| 
 | ||||
| (defun guix-info-insert-val-default (val &optional face) | ||||
|   "Format and insert parameter value VAL at point. | ||||
| (defun guix-info-insert-title-format (title &optional face) | ||||
|   "Insert TITLE using `guix-info-param-title-format' at point. | ||||
| If FACE is nil, use `guix-info-param-title'." | ||||
|   (guix-format-insert title | ||||
|                       (or face 'guix-info-param-title) | ||||
|                       guix-info-param-title-format)) | ||||
| 
 | ||||
| This function is intended to be called after | ||||
| `guix-info-insert-title-default'. | ||||
| (defun guix-info-insert-value-simple (value &optional button-or-face indent) | ||||
|   "Format and insert parameter VALUE at point. | ||||
| 
 | ||||
| If VAL is a one-line string longer than `guix-info-fill-column', | ||||
| split it into several short lines.  See also | ||||
| `guix-info-multiline-prefix'. | ||||
| VALUE may be split into several short lines to fit the current | ||||
| window, depending on `guix-info-fill', and each line is indented | ||||
| with INDENT number of spaces. | ||||
| 
 | ||||
| If FACE is non-nil, propertize inserted line(s) with this FACE." | ||||
|   (guix-split-insert val face | ||||
|                      guix-info-fill-column | ||||
|                      (concat "\n" guix-info-multiline-prefix))) | ||||
| If BUTTON-OR-FACE is a button type symbol, transform VALUE into | ||||
| this (these) button(s) and insert each one on a new line.  If it | ||||
| is a face symbol, propertize inserted line(s) with this face." | ||||
|   (or indent (setq indent 0)) | ||||
|   (guix-with-indent indent | ||||
|     (let* ((button?  (guix-button-type? button-or-face)) | ||||
|            (face     (unless button? button-or-face)) | ||||
|            (fill-col (unless (or button? | ||||
|                                  (and (stringp value) | ||||
|                                       (not guix-info-fill))) | ||||
|                        (- (guix-info-fill-column) indent))) | ||||
|            (value    (if (and value button?) | ||||
|                          (guix-buttonize value button-or-face "\n") | ||||
|                        value))) | ||||
|       (guix-split-insert value face fill-col "\n")))) | ||||
| 
 | ||||
| (defun guix-info-insert-val-simple (val &optional face-or-fun) | ||||
|   "Format and insert parameter value VAL at point. | ||||
| (defun guix-info-insert-value-indent (value &optional button-or-face) | ||||
|   "Format and insert parameter VALUE at point. | ||||
| 
 | ||||
| This function is intended to be called after | ||||
| `guix-info-insert-title-simple'. | ||||
| This function is intended to be called after inserting a title | ||||
| with `guix-info-insert-title-simple'. | ||||
| 
 | ||||
| If VAL is a one-line string longer than `guix-info-fill-column', | ||||
| split it into several short lines and indent each line with | ||||
| `guix-info-indent' spaces. | ||||
| VALUE may be split into several short lines to fit the current | ||||
| window, depending on `guix-info-fill', and each line is indented | ||||
| with `guix-info-indent'. | ||||
| 
 | ||||
| If FACE-OR-FUN is a face, propertize inserted line(s) with this FACE. | ||||
| For the meaning of BUTTON-OR-FACE, see `guix-info-insert-value-simple'." | ||||
|   (when value (insert "\n")) | ||||
|   (guix-info-insert-value-simple value button-or-face guix-info-indent)) | ||||
| 
 | ||||
| If FACE-OR-FUN is a function, call it with VAL as argument.  If | ||||
| VAL is a list, call the function on each element of this list." | ||||
|   (if (null val) | ||||
|       (progn (guix-info-insert-indent) | ||||
|              (guix-format-insert nil)) | ||||
|     (let ((prefix (concat "\n" (guix-info-get-indent)))) | ||||
|       (insert prefix) | ||||
|       (if (functionp face-or-fun) | ||||
|           (guix-mapinsert face-or-fun | ||||
|                           (if (listp val) val (list val)) | ||||
|                           prefix) | ||||
|         (guix-split-insert val face-or-fun | ||||
|                            guix-info-fill-column prefix))))) | ||||
| (defun guix-info-insert-value-format (value &optional button-or-face | ||||
|                                             &rest button-properties) | ||||
|   "Format and insert parameter VALUE at point. | ||||
| 
 | ||||
| (defun guix-info-insert-time (seconds &optional _) | ||||
| This function is intended to be called after inserting a title | ||||
| with `guix-info-insert-title-format'. | ||||
| 
 | ||||
| VALUE may be split into several short lines to fit the current | ||||
| window, depending on `guix-info-fill' and | ||||
| `guix-info-multiline-prefix'.  If VALUE is a list, its elements | ||||
| will be separated with `guix-list-separator'. | ||||
| 
 | ||||
| If BUTTON-OR-FACE is a button type symbol, transform VALUE into | ||||
| this (these) button(s).  If it is a face symbol, propertize | ||||
| inserted line(s) with this face. | ||||
| 
 | ||||
| BUTTON-PROPERTIES are passed to `guix-buttonize' (only if | ||||
| BUTTON-OR-FACE is a button type)." | ||||
|   (let* ((button?  (guix-button-type? button-or-face)) | ||||
|          (face     (unless button? button-or-face)) | ||||
|          (fill-col (when (or button? | ||||
|                              guix-info-fill | ||||
|                              (not (stringp value))) | ||||
|                      (- (guix-info-fill-column) | ||||
|                         (length guix-info-multiline-prefix)))) | ||||
|          (value    (if (and value button?) | ||||
|                        (apply #'guix-buttonize | ||||
|                               value button-or-face guix-list-separator | ||||
|                               button-properties) | ||||
|                      value))) | ||||
|     (guix-split-insert value face fill-col | ||||
|                        (concat "\n" guix-info-multiline-prefix)))) | ||||
| 
 | ||||
| (defun guix-info-insert-time (seconds &optional face) | ||||
|   "Insert formatted time string using SECONDS at point." | ||||
|   (guix-info-insert-val-default (guix-get-time-string seconds) | ||||
|                                 'guix-info-time)) | ||||
|   (guix-format-insert (guix-get-time-string seconds) | ||||
|                       (or face 'guix-info-time))) | ||||
| 
 | ||||
|  | ||||
| ;;; Buttons | ||||
|  | @ -394,14 +454,6 @@ See `insert-text-button' for the meaning of PROPERTIES." | |||
|          'help-echo message | ||||
|          properties)) | ||||
| 
 | ||||
| (defun guix-info-insert-file-path (path &optional _) | ||||
|   "Make button from file PATH and insert it at point." | ||||
|   (guix-insert-button path 'guix-file)) | ||||
| 
 | ||||
| (defun guix-info-insert-url (url &optional _) | ||||
|   "Make button from URL and insert it at point." | ||||
|   (guix-insert-button url 'guix-url)) | ||||
| 
 | ||||
|  | ||||
| (defvar guix-info-mode-map | ||||
|   (let ((map (make-sparse-keymap))) | ||||
|  | @ -418,7 +470,7 @@ See `insert-text-button' for the meaning of PROPERTIES." | |||
| ;;; Displaying packages | ||||
| 
 | ||||
| (guix-define-buffer-type info package | ||||
|   :required (id installed non-unique)) | ||||
|   :required (id name version installed non-unique)) | ||||
| 
 | ||||
| (defface guix-package-info-heading | ||||
|   '((t :inherit guix-info-heading)) | ||||
|  | @ -483,57 +535,11 @@ See `insert-text-button' for the meaning of PROPERTIES." | |||
|   "Face used if a package is obsolete." | ||||
|   :group 'guix-package-info-faces) | ||||
| 
 | ||||
| (defvar guix-info-insert-package-function | ||||
|   #'guix-package-info-insert-with-heading | ||||
|   "Function used to insert a package information. | ||||
| It is called with a single argument - alist of package parameters. | ||||
| If nil, insert package in a default way.") | ||||
| 
 | ||||
| (defvar guix-package-info-heading-params '(synopsis description) | ||||
|   "List of parameters displayed in a heading along with name and version.") | ||||
| 
 | ||||
| (defcustom guix-package-info-fill-heading t | ||||
|   "If nil, insert heading parameters in a raw form, without | ||||
| filling them to fit the window." | ||||
|   :type 'boolean | ||||
|   :group 'guix-package-info) | ||||
| 
 | ||||
| (defun guix-package-info-insert-heading (entry) | ||||
|   "Insert the heading for package ENTRY. | ||||
| Show package name, version, and `guix-package-info-heading-params'." | ||||
|   "Insert package ENTRY heading (name specification) at point." | ||||
|   (guix-format-insert (concat (guix-entry-value entry 'name) " " | ||||
|                               (guix-entry-value entry 'version)) | ||||
|                       'guix-package-info-heading) | ||||
|   (insert "\n\n") | ||||
|   (mapc (lambda (param) | ||||
|           (let ((val  (guix-entry-value entry param)) | ||||
|                 (face (guix-get-symbol (symbol-name param) | ||||
|                                        'info 'package))) | ||||
|             (when val | ||||
|               (let* ((col (min (window-width) fill-column)) | ||||
|                      (val (if guix-package-info-fill-heading | ||||
|                               (guix-get-filled-string val col) | ||||
|                             val))) | ||||
|                 (guix-format-insert val (and (facep face) face)) | ||||
|                 (insert "\n\n"))))) | ||||
|         guix-package-info-heading-params)) | ||||
| 
 | ||||
| (defun guix-package-info-insert-with-heading (entry) | ||||
|   "Insert package ENTRY with its heading at point." | ||||
|   (guix-package-info-insert-heading entry) | ||||
|   (mapc (lambda (param) | ||||
|           (unless (or (memq param '(name version)) | ||||
|                       (memq param guix-package-info-heading-params)) | ||||
|             (guix-info-insert-param param entry 'package))) | ||||
|         (guix-info-displayed-params 'package))) | ||||
| 
 | ||||
| (defun guix-package-info-insert-description (desc &optional _) | ||||
|   "Insert description DESC at point." | ||||
|   (guix-info-insert-val-simple desc 'guix-package-info-description)) | ||||
| 
 | ||||
| (defun guix-package-info-insert-location (location &optional _) | ||||
|   "Make button from file LOCATION and insert it at point." | ||||
|   (guix-insert-button location 'guix-package-location)) | ||||
|                       'guix-package-info-heading)) | ||||
| 
 | ||||
| (defmacro guix-package-info-define-insert-inputs (&optional type) | ||||
|   "Define a face and a function for inserting package inputs. | ||||
|  | @ -544,8 +550,7 @@ Face name is `guix-package-info-TYPE-inputs'." | |||
|          (type-name (and type (concat type-str "-"))) | ||||
|          (type-desc (and type (concat type-str " "))) | ||||
|          (face (intern (concat "guix-package-info-" type-name "inputs"))) | ||||
|          (btn  (intern (concat "guix-package-" type-name "input"))) | ||||
|          (fun  (intern (concat "guix-package-info-insert-" type-name "inputs")))) | ||||
|          (btn  (intern (concat "guix-package-" type-name "input")))) | ||||
|     `(progn | ||||
|        (defface ,face | ||||
|          '((t :inherit guix-package-info-name-button)) | ||||
|  | @ -554,29 +559,12 @@ Face name is `guix-package-info-TYPE-inputs'." | |||
| 
 | ||||
|        (define-button-type ',btn | ||||
|          :supertype 'guix-package-name | ||||
|          'face ',face) | ||||
| 
 | ||||
|        (defun ,fun (inputs &optional _) | ||||
|          ,(concat "Make buttons from " type-desc "INPUTS and insert them at point.") | ||||
|          (guix-package-info-insert-full-names inputs ',btn))))) | ||||
|          'face ',face)))) | ||||
| 
 | ||||
| (guix-package-info-define-insert-inputs) | ||||
| (guix-package-info-define-insert-inputs native) | ||||
| (guix-package-info-define-insert-inputs propagated) | ||||
| 
 | ||||
| (defun guix-package-info-insert-full-names (names button-type) | ||||
|   "Make BUTTON-TYPE buttons from package NAMES and insert them at point. | ||||
| NAMES is a list of strings." | ||||
|   (if names | ||||
|       (guix-info-insert-val-default | ||||
|        (with-temp-buffer | ||||
|          (guix-mapinsert (lambda (name) | ||||
|                            (guix-insert-button name button-type)) | ||||
|                          names | ||||
|                          guix-list-separator) | ||||
|          (buffer-substring (point-min) (point-max)))) | ||||
|     (guix-format-insert nil))) | ||||
| 
 | ||||
|  | ||||
| ;;; Inserting outputs and installed parameters | ||||
| 
 | ||||
|  | @ -588,12 +576,6 @@ formatted with this string, an action button is inserted.") | |||
| (defvar guix-package-info-obsolete-string "(This package is obsolete)" | ||||
|   "String used if a package is obsolete.") | ||||
| 
 | ||||
| (defvar guix-info-insert-installed-function nil | ||||
|   "Function used to insert an installed information. | ||||
| It is called with a single argument - alist of installed | ||||
| parameters (`output', `path', `dependencies'). | ||||
| If nil, insert installed info in a default way.") | ||||
| 
 | ||||
| (defun guix-package-info-insert-outputs (outputs entry) | ||||
|   "Insert OUTPUTS from package ENTRY at point." | ||||
|   (and (guix-entry-value entry 'obsolete) | ||||
|  | @ -668,13 +650,6 @@ ENTRY is an alist with package info." | |||
|              (guix-entry-id entry)) | ||||
|      'output output))) | ||||
| 
 | ||||
| (defun guix-package-info-insert-output-path (path &optional _) | ||||
|   "Insert PATH of the installed output." | ||||
|   (guix-info-insert-val-simple path #'guix-info-insert-file-path)) | ||||
| 
 | ||||
| (defalias 'guix-package-info-insert-output-dependencies | ||||
|   'guix-package-info-insert-output-path) | ||||
| 
 | ||||
|  | ||||
| ;;; Inserting a source | ||||
| 
 | ||||
|  | @ -711,10 +686,6 @@ prompt depending on `guix-operation-confirm' variable)." | |||
|             ;; no action is bound to a source button. | ||||
|             (message "Yes, this is the source URL. What did you expect?"))) | ||||
| 
 | ||||
| (defun guix-package-info-insert-source-url (url &optional _) | ||||
|   "Make button from source URL and insert it at point." | ||||
|   (guix-insert-button url 'guix-package-source)) | ||||
| 
 | ||||
| (defun guix-package-info-show-source (entry-id package-id) | ||||
|   "Show file name of a package source in the current info buffer. | ||||
| Find the file if needed (see `guix-package-info-auto-find-source'). | ||||
|  | @ -746,7 +717,6 @@ PACKAGE-ID is an ID of the package which source to show." | |||
| (defun guix-package-info-insert-source (source entry) | ||||
|   "Insert SOURCE from package ENTRY at point. | ||||
| SOURCE is a list of URLs." | ||||
|   (guix-info-insert-indent) | ||||
|   (if (null source) | ||||
|       (guix-format-insert nil) | ||||
|     (let* ((source-file (guix-entry-value entry 'source-file)) | ||||
|  | @ -759,7 +729,7 @@ SOURCE is a list of URLs." | |||
|            (lambda (btn) | ||||
|              (guix-package-info-show-source (button-get btn 'entry-id) | ||||
|                                             (button-get btn 'package-id))) | ||||
|            "Show the source store path of the current package" | ||||
|            "Show the source store directory of the current package" | ||||
|            'entry-id entry-id | ||||
|            'package-id package-id) | ||||
|         (unless (file-exists-p source-file) | ||||
|  | @ -770,10 +740,8 @@ SOURCE is a list of URLs." | |||
|               (button-get btn 'package-id))) | ||||
|            "Download the source into the store" | ||||
|            'package-id package-id)) | ||||
|         (guix-info-insert-val-simple source-file | ||||
|                                      #'guix-info-insert-file-path)) | ||||
|       (guix-info-insert-val-simple source | ||||
|                                    #'guix-package-info-insert-source-url)))) | ||||
|         (guix-info-insert-value-indent source-file 'guix-file)) | ||||
|       (guix-info-insert-value-indent source 'guix-package-source)))) | ||||
| 
 | ||||
| (defun guix-package-info-redisplay-after-download () | ||||
|   "Redisplay an 'info' buffer after downloading the package source. | ||||
|  | @ -788,19 +756,14 @@ This function is used to hide a \"Download\" button if needed." | |||
|  | ||||
| ;;; Displaying outputs | ||||
| 
 | ||||
| (guix-define-buffer-type info output | ||||
| (guix-ui-info-define-interface output | ||||
|   :buffer-name "*Guix Package Info*" | ||||
|   :required (id package-id installed non-unique)) | ||||
| 
 | ||||
| (defvar guix-info-insert-output-function nil | ||||
|   "Function used to insert an output information. | ||||
| It is called with a single argument - alist of output parameters. | ||||
| If nil, insert output in a default way.") | ||||
| 
 | ||||
| (defun guix-output-info-insert-version (version entry) | ||||
|   "Insert output VERSION and obsolete text if needed at point." | ||||
|   (guix-info-insert-val-default version | ||||
|                                 'guix-package-info-version) | ||||
|   (guix-info-insert-value-format version | ||||
|                                  'guix-package-info-version) | ||||
|   (and (guix-entry-value entry 'obsolete) | ||||
|        (guix-package-info-insert-obsolete-text))) | ||||
| 
 | ||||
|  | @ -809,7 +772,7 @@ If nil, insert output in a default way.") | |||
|   (let* ((installed (guix-entry-value entry 'installed)) | ||||
|          (obsolete  (guix-entry-value entry 'obsolete)) | ||||
|          (action-type (if installed 'delete 'install))) | ||||
|     (guix-info-insert-val-default | ||||
|     (guix-info-insert-value-format | ||||
|      output | ||||
|      (if installed | ||||
|          'guix-package-info-installed-outputs | ||||
|  | @ -840,14 +803,9 @@ If nil, insert output in a default way.") | |||
|   "Face used if a generation is not the current one." | ||||
|   :group 'guix-generation-info-faces) | ||||
| 
 | ||||
| (defvar guix-info-insert-generation-function nil | ||||
|   "Function used to insert a generation information. | ||||
| It is called with a single argument - alist of generation parameters. | ||||
| If nil, insert generation in a default way.") | ||||
| 
 | ||||
| (defun guix-generation-info-insert-number (number &optional _) | ||||
|   "Insert generation NUMBER and action buttons." | ||||
|   (guix-info-insert-val-default number 'guix-generation-info-number) | ||||
|   (guix-info-insert-value-format number 'guix-generation-info-number) | ||||
|   (guix-info-insert-indent) | ||||
|   (guix-info-insert-action-button | ||||
|    "Packages" | ||||
|  | @ -868,8 +826,8 @@ If nil, insert generation in a default way.") | |||
| (defun guix-generation-info-insert-current (val entry) | ||||
|   "Insert boolean value VAL showing whether this generation is current." | ||||
|   (if val | ||||
|       (guix-info-insert-val-default "Yes" 'guix-generation-info-current) | ||||
|     (guix-info-insert-val-default "No" 'guix-generation-info-not-current) | ||||
|       (guix-info-insert-value-format "Yes" 'guix-generation-info-current) | ||||
|     (guix-info-insert-value-format "No" 'guix-generation-info-not-current) | ||||
|     (guix-info-insert-indent) | ||||
|     (guix-info-insert-action-button | ||||
|      "Switch" | ||||
|  |  | |||
|  | @ -104,6 +104,28 @@ See `insert-text-button' for the meaning of PROPERTIES." | |||
|            :type (or type 'button) | ||||
|            properties))) | ||||
| 
 | ||||
| (defun guix-buttonize (value button-type separator &rest properties) | ||||
|   "Make BUTTON-TYPE button(s) from VALUE. | ||||
| Return a string with button(s). | ||||
| 
 | ||||
| VALUE should be a string or a list of strings.  If it is a list | ||||
| of strings, buttons are separated with SEPARATOR string. | ||||
| 
 | ||||
| PROPERTIES are passed to `guix-insert-button'." | ||||
|   (with-temp-buffer | ||||
|     (let ((labels (if (listp value) value (list value)))) | ||||
|       (guix-mapinsert (lambda (label) | ||||
|                         (apply #'guix-insert-button | ||||
|                                label button-type properties)) | ||||
|                       labels | ||||
|                       separator)) | ||||
|     (buffer-substring (point-min) (point-max)))) | ||||
| 
 | ||||
| (defun guix-button-type? (symbol) | ||||
|   "Return non-nil, if SYMBOL is a button type." | ||||
|   (and symbol | ||||
|        (get symbol 'button-category-symbol))) | ||||
| 
 | ||||
| (defun guix-split-insert (val &optional face col separator) | ||||
|   "Convert VAL into a string, split it and insert at point. | ||||
| 
 | ||||
|  | @ -122,14 +144,11 @@ Separate inserted lines with SEPARATOR." | |||
| 
 | ||||
| (defun guix-split-string (str &optional col) | ||||
|   "Split string STR by lines and return list of result strings. | ||||
| If COL is non-nil and STR is a one-line string longer than COL, | ||||
| split it into several short lines." | ||||
|   (let ((strings (split-string str "\n *"))) | ||||
|     (if (and col | ||||
|              (null (cdr strings))       ; if not multi-line | ||||
|              (> (length str) col)) | ||||
|         (split-string (guix-get-filled-string str col) "\n") | ||||
|       strings))) | ||||
| If COL is non-nil, fill STR to this column." | ||||
|   (let ((str (if col | ||||
|                  (guix-get-filled-string str col) | ||||
|                str))) | ||||
|     (split-string str "\n *" t))) | ||||
| 
 | ||||
| (defun guix-get-filled-string (str col) | ||||
|   "Return string by filling STR to column COL." | ||||
|  |  | |||
		Reference in a new issue