diff options
Diffstat (limited to 'emacs')
-rw-r--r-- | emacs/guix-info.el | 558 | ||||
-rw-r--r-- | emacs/guix-utils.el | 35 |
2 files changed, 285 insertions, 308 deletions
diff --git a/emacs/guix-info.el b/emacs/guix-info.el index 05a8143202..9c46810f60 100644 --- a/emacs/guix-info.el +++ b/emacs/guix-info.el @@ -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]) ...)) - -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. - -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.") - -(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: + (ENTRY-TYPE . (METHOD ...)) + +Each METHOD should be either a function or should have the +following form: + + (PARAM INSERT-TITLE INSERT-VALUE) + +If METHOD is a function, it is called with an entry as argument. + +PARAM is a name of entry parameter. + +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. - (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. -The order of displayed parameters is the same as in this list.") +Parameters are inserted in the same order as defined by this list. +After calling each METHOD, a new line is inserted.") -(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)) +(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) +(defun guix-info-insert-entry (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." +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) - (mapc (lambda (param) - (guix-info-insert-param param entry entry-type)) - (guix-info-displayed-params entry-type)))) + (dolist (spec (guix-info-format entry-type)) + (guix-info-insert-entry-unit spec entry 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)))) - -(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." + (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: \" string at point. +If FACE is nil, use `guix-info-param-title'." (guix-format-insert title (or face 'guix-info-param-title) - (or format guix-info-param-title-format))) + "%s: ")) -(defun guix-info-insert-title-simple (title &optional face) - "Insert TITLE at point." - (guix-info-insert-title-default title face "%s:")) - -(defun guix-info-insert-val-default (val &optional face) - "Format and insert parameter value VAL at point. - -This function is intended to be called after -`guix-info-insert-title-default'. - -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'. - -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))) - -(defun guix-info-insert-val-simple (val &optional face-or-fun) - "Format and insert parameter value VAL at point. - -This function is intended to be called after -`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. - -If FACE-OR-FUN is a face, propertize inserted line(s) with this FACE. - -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-time (seconds &optional _) +(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)) + +(defun guix-info-insert-value-simple (value &optional button-or-face indent) + "Format and insert parameter VALUE at point. + +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 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-value-indent (value &optional button-or-face) + "Format and insert parameter VALUE at point. + +This function is intended to be called after inserting a title +with `guix-info-insert-title-simple'. + +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'. + +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)) + +(defun guix-info-insert-value-format (value &optional button-or-face + &rest button-properties) + "Format and insert parameter VALUE at point. + +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" diff --git a/emacs/guix-utils.el b/emacs/guix-utils.el index fbe0a613da..3c75417a08 100644 --- a/emacs/guix-utils.el +++ b/emacs/guix-utils.el @@ -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." |