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''
|
Specify the columns, their names, what and how is displayed in ``list''
|
||||||
buffers.
|
buffers.
|
||||||
|
|
||||||
@item guix-info-displayed-params
|
@item guix-info-format
|
||||||
@itemx guix-info-insert-methods
|
@itemx guix-info-ignore-empty-values
|
||||||
@itemx guix-info-ignore-empty-vals
|
|
||||||
@itemx guix-info-param-title-format
|
@itemx guix-info-param-title-format
|
||||||
@itemx guix-info-multiline-prefix
|
@itemx guix-info-multiline-prefix
|
||||||
@itemx guix-info-indent
|
@itemx guix-info-indent
|
||||||
@itemx guix-info-fill-column
|
@itemx guix-info-fill
|
||||||
@itemx guix-info-delimiter
|
@itemx guix-info-delimiter
|
||||||
Various settings for ``info'' buffers.
|
Various settings for ``info'' buffers.
|
||||||
|
|
||||||
|
|
|
@ -81,122 +81,175 @@
|
||||||
"Mouse face used for action buttons."
|
"Mouse face used for action buttons."
|
||||||
:group 'guix-info-faces)
|
: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."
|
"If non-nil, do not display parameters with nil values."
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:group 'guix-info)
|
: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: "
|
(defvar guix-info-param-title-format "%-18s: "
|
||||||
"String used to format a title of a parameter.
|
"String used to format a title of a parameter.
|
||||||
It should be a '%s'-sequence. After inserting a title formatted
|
It should be a '%s'-sequence. After inserting a title formatted
|
||||||
with this string, a value of the parameter is inserted.
|
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.
|
"String used to format multi-line parameter values.
|
||||||
If a value occupies more than one line, this string is inserted
|
If a value occupies more than one line, this string is inserted
|
||||||
in the beginning of each line after the first one.
|
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
|
(defvar guix-info-indent 2
|
||||||
"Number of spaces used to indent various parts of inserted text.")
|
"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"
|
(defvar guix-info-delimiter "\n\f\n"
|
||||||
"String used to separate entries.")
|
"String used to separate entries.")
|
||||||
|
|
||||||
(defvar guix-info-insert-methods
|
(defvar guix-info-format
|
||||||
'((package
|
'((package
|
||||||
(name guix-package-info-name)
|
guix-package-info-insert-heading
|
||||||
(version guix-package-info-version)
|
ignore
|
||||||
(license guix-package-info-license)
|
(synopsis ignore (simple guix-package-info-synopsis))
|
||||||
(synopsis guix-package-info-synopsis)
|
ignore
|
||||||
(description guix-package-info-insert-description
|
(description ignore (simple guix-package-info-description))
|
||||||
guix-info-insert-title-simple)
|
ignore
|
||||||
(outputs guix-package-info-insert-outputs
|
(outputs simple guix-package-info-insert-outputs)
|
||||||
guix-info-insert-title-simple)
|
(source simple guix-package-info-insert-source)
|
||||||
(source guix-package-info-insert-source
|
(location format (format guix-package-location))
|
||||||
guix-info-insert-title-simple)
|
(home-url format (format guix-url))
|
||||||
(home-url guix-info-insert-url)
|
(license format (format guix-package-info-license))
|
||||||
(inputs guix-package-info-insert-inputs)
|
(inputs format (format guix-package-input))
|
||||||
(native-inputs guix-package-info-insert-native-inputs)
|
(native-inputs format (format guix-package-native-input))
|
||||||
(propagated-inputs guix-package-info-insert-propagated-inputs)
|
(propagated-inputs format (format guix-package-propagated-input)))
|
||||||
(location guix-package-info-insert-location))
|
|
||||||
(installed
|
(installed
|
||||||
(path guix-package-info-insert-output-path
|
(path simple (indent guix-file))
|
||||||
guix-info-insert-title-simple)
|
(dependencies simple (indent guix-file)))
|
||||||
(dependencies guix-package-info-insert-output-dependencies
|
|
||||||
guix-info-insert-title-simple))
|
|
||||||
(output
|
(output
|
||||||
(name guix-package-info-name)
|
(name format (format guix-package-info-name))
|
||||||
(version guix-output-info-insert-version)
|
(version format guix-output-info-insert-version)
|
||||||
(output guix-output-info-insert-output)
|
(output format guix-output-info-insert-output)
|
||||||
(source guix-package-info-insert-source
|
(synopsis simple (indent guix-package-info-synopsis))
|
||||||
guix-info-insert-title-simple)
|
(source simple guix-package-info-insert-source)
|
||||||
(path guix-package-info-insert-output-path
|
(path simple (indent guix-file))
|
||||||
guix-info-insert-title-simple)
|
(dependencies simple (indent guix-file))
|
||||||
(dependencies guix-package-info-insert-output-dependencies
|
(location format (format guix-package-location))
|
||||||
guix-info-insert-title-simple)
|
(home-url format (format guix-url))
|
||||||
(license guix-package-info-license)
|
(license format (format guix-package-info-license))
|
||||||
(synopsis guix-package-info-synopsis)
|
(inputs format (format guix-package-input))
|
||||||
(description guix-package-info-insert-description
|
(native-inputs format (format guix-package-native-input))
|
||||||
guix-info-insert-title-simple)
|
(propagated-inputs format (format guix-package-propagated-input))
|
||||||
(home-url guix-info-insert-url)
|
(description simple (indent guix-package-info-description)))
|
||||||
(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))
|
|
||||||
(generation
|
(generation
|
||||||
(number guix-generation-info-insert-number)
|
(number format guix-generation-info-insert-number)
|
||||||
(current guix-generation-info-insert-current)
|
(prev-number format (format))
|
||||||
(path guix-info-insert-file-path)
|
(current format guix-generation-info-insert-current)
|
||||||
(time guix-info-insert-time)))
|
(path simple (indent guix-file))
|
||||||
|
(time format (time))))
|
||||||
"Methods for inserting parameter values.
|
"Methods for inserting parameter values.
|
||||||
Each element of the list should have a form:
|
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
|
Each METHOD should be either a function or should have the
|
||||||
is nil or a face, `guix-info-insert-val-default' function is
|
following form:
|
||||||
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
|
(PARAM INSERT-TITLE INSERT-VALUE)
|
||||||
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
|
If METHOD is a function, it is called with an entry as argument.
|
||||||
'((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 . (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)
|
INSERT-VALUE may be either a symbol or a list. If it is a
|
||||||
"Return list of insert methods for parameter PARAM of ENTRY-TYPE.
|
symbol, it should be a function or an alias from
|
||||||
See `guix-info-insert-methods' for details."
|
`guix-info-value-aliases', in which case it is called with value
|
||||||
(guix-assq-value guix-info-insert-methods
|
and entry as arguments. If it is a list, it should have a
|
||||||
entry-type param))
|
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)
|
(defun guix-info-displayed-params (entry-type)
|
||||||
"Return parameters of ENTRY-TYPE that should be displayed."
|
"Return a list of ENTRY-TYPE parameters that should be displayed."
|
||||||
(guix-assq-value guix-info-displayed-params
|
(delq nil
|
||||||
entry-type))
|
(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)
|
(defun guix-info-get-indent (&optional level)
|
||||||
"Return `guix-info-indent' \"multiplied\" by LEVEL spaces.
|
"Return `guix-info-indent' \"multiplied\" by LEVEL spaces.
|
||||||
|
@ -215,115 +268,122 @@ ENTRIES should have a form of `guix-entries'."
|
||||||
entries
|
entries
|
||||||
guix-info-delimiter))
|
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)
|
(defun guix-info-insert-entry (entry entry-type &optional indent-level)
|
||||||
"Insert ENTRY of ENTRY-TYPE into the current info buffer.
|
"Insert ENTRY of ENTRY-TYPE into the current info buffer.
|
||||||
Use `guix-info-insert-ENTRY-TYPE-function' or
|
If INDENT-LEVEL is non-nil, indent displayed data by this number
|
||||||
`guix-info-insert-entry-default' if it is nil."
|
of `guix-info-indent' spaces."
|
||||||
(let* ((var (intern (concat "guix-info-insert-"
|
(guix-with-indent (* (or indent-level 0)
|
||||||
(symbol-name entry-type)
|
guix-info-indent)
|
||||||
"-function")))
|
(dolist (spec (guix-info-format entry-type))
|
||||||
(fun (symbol-value var)))
|
(guix-info-insert-entry-unit spec entry entry-type))))
|
||||||
(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.
|
"Insert title and value of a PARAM at point.
|
||||||
ENTRY is alist with parameters and their values.
|
ENTRY is alist with parameters and their values.
|
||||||
ENTRY-TYPE is a type of ENTRY."
|
ENTRY-TYPE is a type of ENTRY."
|
||||||
(let ((val (guix-entry-value entry param)))
|
(pcase format-spec
|
||||||
(unless (and guix-info-ignore-empty-vals (null val))
|
((pred functionp)
|
||||||
(let* ((title (guix-get-param-title entry-type param))
|
(funcall format-spec entry)
|
||||||
(insert-methods (guix-info-insert-methods entry-type param))
|
(insert "\n"))
|
||||||
(val-method (car insert-methods))
|
(`(,param ,title-method ,value-method)
|
||||||
(title-method (cadr insert-methods)))
|
(let ((value (guix-entry-value entry param)))
|
||||||
(guix-info-method-funcall title title-method
|
(unless (and guix-info-ignore-empty-values (null value))
|
||||||
#'guix-info-insert-title-default)
|
(let ((title (guix-info-param-title entry-type param))
|
||||||
(guix-info-method-funcall val val-method
|
(insert-title (guix-info-title-method->function title-method))
|
||||||
#'guix-info-insert-val-default
|
(insert-value (guix-info-value-method->function value-method)))
|
||||||
entry)
|
(funcall insert-title title)
|
||||||
(insert "\n")))))
|
(funcall insert-value value entry)
|
||||||
|
(insert "\n")))))
|
||||||
(defun guix-info-method-funcall (val method default-fun &rest args)
|
(_ (error "Unknown format specification '%S'" format-spec))))
|
||||||
"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)))
|
|
||||||
|
|
||||||
(defun guix-info-insert-title-simple (title &optional face)
|
(defun guix-info-insert-title-simple (title &optional face)
|
||||||
"Insert TITLE at point."
|
"Insert \"TITLE: \" string at point.
|
||||||
(guix-info-insert-title-default title face "%s:"))
|
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)
|
(defun guix-info-insert-title-format (title &optional face)
|
||||||
"Format and insert parameter value VAL at point.
|
"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
|
(defun guix-info-insert-value-simple (value &optional button-or-face indent)
|
||||||
`guix-info-insert-title-default'.
|
"Format and insert parameter VALUE at point.
|
||||||
|
|
||||||
If VAL is a one-line string longer than `guix-info-fill-column',
|
VALUE may be split into several short lines to fit the current
|
||||||
split it into several short lines. See also
|
window, depending on `guix-info-fill', and each line is indented
|
||||||
`guix-info-multiline-prefix'.
|
with INDENT number of spaces.
|
||||||
|
|
||||||
If FACE is non-nil, propertize inserted line(s) with this FACE."
|
If BUTTON-OR-FACE is a button type symbol, transform VALUE into
|
||||||
(guix-split-insert val face
|
this (these) button(s) and insert each one on a new line. If it
|
||||||
guix-info-fill-column
|
is a face symbol, propertize inserted line(s) with this face."
|
||||||
(concat "\n" guix-info-multiline-prefix)))
|
(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)
|
(defun guix-info-insert-value-indent (value &optional button-or-face)
|
||||||
"Format and insert parameter value VAL at point.
|
"Format and insert parameter VALUE at point.
|
||||||
|
|
||||||
This function is intended to be called after
|
This function is intended to be called after inserting a title
|
||||||
`guix-info-insert-title-simple'.
|
with `guix-info-insert-title-simple'.
|
||||||
|
|
||||||
If VAL is a one-line string longer than `guix-info-fill-column',
|
VALUE may be split into several short lines to fit the current
|
||||||
split it into several short lines and indent each line with
|
window, depending on `guix-info-fill', and each line is indented
|
||||||
`guix-info-indent' spaces.
|
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
|
(defun guix-info-insert-value-format (value &optional button-or-face
|
||||||
VAL is a list, call the function on each element of this list."
|
&rest button-properties)
|
||||||
(if (null val)
|
"Format and insert parameter VALUE at point.
|
||||||
(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 _)
|
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."
|
"Insert formatted time string using SECONDS at point."
|
||||||
(guix-info-insert-val-default (guix-get-time-string seconds)
|
(guix-format-insert (guix-get-time-string seconds)
|
||||||
'guix-info-time))
|
(or face 'guix-info-time)))
|
||||||
|
|
||||||
|
|
||||||
;;; Buttons
|
;;; Buttons
|
||||||
|
@ -394,14 +454,6 @@ See `insert-text-button' for the meaning of PROPERTIES."
|
||||||
'help-echo message
|
'help-echo message
|
||||||
properties))
|
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
|
(defvar guix-info-mode-map
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
|
@ -418,7 +470,7 @@ See `insert-text-button' for the meaning of PROPERTIES."
|
||||||
;;; Displaying packages
|
;;; Displaying packages
|
||||||
|
|
||||||
(guix-define-buffer-type info package
|
(guix-define-buffer-type info package
|
||||||
:required (id installed non-unique))
|
:required (id name version installed non-unique))
|
||||||
|
|
||||||
(defface guix-package-info-heading
|
(defface guix-package-info-heading
|
||||||
'((t :inherit guix-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."
|
"Face used if a package is obsolete."
|
||||||
:group 'guix-package-info-faces)
|
: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)
|
(defun guix-package-info-insert-heading (entry)
|
||||||
"Insert the heading for package ENTRY.
|
"Insert package ENTRY heading (name specification) at point."
|
||||||
Show package name, version, and `guix-package-info-heading-params'."
|
|
||||||
(guix-format-insert (concat (guix-entry-value entry 'name) " "
|
(guix-format-insert (concat (guix-entry-value entry 'name) " "
|
||||||
(guix-entry-value entry 'version))
|
(guix-entry-value entry 'version))
|
||||||
'guix-package-info-heading)
|
'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))
|
|
||||||
|
|
||||||
(defmacro guix-package-info-define-insert-inputs (&optional type)
|
(defmacro guix-package-info-define-insert-inputs (&optional type)
|
||||||
"Define a face and a function for inserting package inputs.
|
"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-name (and type (concat type-str "-")))
|
||||||
(type-desc (and type (concat type-str " ")))
|
(type-desc (and type (concat type-str " ")))
|
||||||
(face (intern (concat "guix-package-info-" type-name "inputs")))
|
(face (intern (concat "guix-package-info-" type-name "inputs")))
|
||||||
(btn (intern (concat "guix-package-" type-name "input")))
|
(btn (intern (concat "guix-package-" type-name "input"))))
|
||||||
(fun (intern (concat "guix-package-info-insert-" type-name "inputs"))))
|
|
||||||
`(progn
|
`(progn
|
||||||
(defface ,face
|
(defface ,face
|
||||||
'((t :inherit guix-package-info-name-button))
|
'((t :inherit guix-package-info-name-button))
|
||||||
|
@ -554,29 +559,12 @@ Face name is `guix-package-info-TYPE-inputs'."
|
||||||
|
|
||||||
(define-button-type ',btn
|
(define-button-type ',btn
|
||||||
:supertype 'guix-package-name
|
:supertype 'guix-package-name
|
||||||
'face ',face)
|
'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)))))
|
|
||||||
|
|
||||||
(guix-package-info-define-insert-inputs)
|
(guix-package-info-define-insert-inputs)
|
||||||
(guix-package-info-define-insert-inputs native)
|
(guix-package-info-define-insert-inputs native)
|
||||||
(guix-package-info-define-insert-inputs propagated)
|
(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
|
;;; 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)"
|
(defvar guix-package-info-obsolete-string "(This package is obsolete)"
|
||||||
"String used if a 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)
|
(defun guix-package-info-insert-outputs (outputs entry)
|
||||||
"Insert OUTPUTS from package ENTRY at point."
|
"Insert OUTPUTS from package ENTRY at point."
|
||||||
(and (guix-entry-value entry 'obsolete)
|
(and (guix-entry-value entry 'obsolete)
|
||||||
|
@ -668,13 +650,6 @@ ENTRY is an alist with package info."
|
||||||
(guix-entry-id entry))
|
(guix-entry-id entry))
|
||||||
'output output)))
|
'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
|
;;; Inserting a source
|
||||||
|
|
||||||
|
@ -711,10 +686,6 @@ prompt depending on `guix-operation-confirm' variable)."
|
||||||
;; no action is bound to a source button.
|
;; no action is bound to a source button.
|
||||||
(message "Yes, this is the source URL. What did you expect?")))
|
(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)
|
(defun guix-package-info-show-source (entry-id package-id)
|
||||||
"Show file name of a package source in the current info buffer.
|
"Show file name of a package source in the current info buffer.
|
||||||
Find the file if needed (see `guix-package-info-auto-find-source').
|
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)
|
(defun guix-package-info-insert-source (source entry)
|
||||||
"Insert SOURCE from package ENTRY at point.
|
"Insert SOURCE from package ENTRY at point.
|
||||||
SOURCE is a list of URLs."
|
SOURCE is a list of URLs."
|
||||||
(guix-info-insert-indent)
|
|
||||||
(if (null source)
|
(if (null source)
|
||||||
(guix-format-insert nil)
|
(guix-format-insert nil)
|
||||||
(let* ((source-file (guix-entry-value entry 'source-file))
|
(let* ((source-file (guix-entry-value entry 'source-file))
|
||||||
|
@ -759,7 +729,7 @@ SOURCE is a list of URLs."
|
||||||
(lambda (btn)
|
(lambda (btn)
|
||||||
(guix-package-info-show-source (button-get btn 'entry-id)
|
(guix-package-info-show-source (button-get btn 'entry-id)
|
||||||
(button-get btn 'package-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
|
'entry-id entry-id
|
||||||
'package-id package-id)
|
'package-id package-id)
|
||||||
(unless (file-exists-p source-file)
|
(unless (file-exists-p source-file)
|
||||||
|
@ -770,10 +740,8 @@ SOURCE is a list of URLs."
|
||||||
(button-get btn 'package-id)))
|
(button-get btn 'package-id)))
|
||||||
"Download the source into the store"
|
"Download the source into the store"
|
||||||
'package-id package-id))
|
'package-id package-id))
|
||||||
(guix-info-insert-val-simple source-file
|
(guix-info-insert-value-indent source-file 'guix-file))
|
||||||
#'guix-info-insert-file-path))
|
(guix-info-insert-value-indent source 'guix-package-source))))
|
||||||
(guix-info-insert-val-simple source
|
|
||||||
#'guix-package-info-insert-source-url))))
|
|
||||||
|
|
||||||
(defun guix-package-info-redisplay-after-download ()
|
(defun guix-package-info-redisplay-after-download ()
|
||||||
"Redisplay an 'info' buffer after downloading the package source.
|
"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
|
;;; Displaying outputs
|
||||||
|
|
||||||
(guix-define-buffer-type info output
|
(guix-ui-info-define-interface output
|
||||||
:buffer-name "*Guix Package Info*"
|
:buffer-name "*Guix Package Info*"
|
||||||
:required (id package-id installed non-unique))
|
: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)
|
(defun guix-output-info-insert-version (version entry)
|
||||||
"Insert output VERSION and obsolete text if needed at point."
|
"Insert output VERSION and obsolete text if needed at point."
|
||||||
(guix-info-insert-val-default version
|
(guix-info-insert-value-format version
|
||||||
'guix-package-info-version)
|
'guix-package-info-version)
|
||||||
(and (guix-entry-value entry 'obsolete)
|
(and (guix-entry-value entry 'obsolete)
|
||||||
(guix-package-info-insert-obsolete-text)))
|
(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))
|
(let* ((installed (guix-entry-value entry 'installed))
|
||||||
(obsolete (guix-entry-value entry 'obsolete))
|
(obsolete (guix-entry-value entry 'obsolete))
|
||||||
(action-type (if installed 'delete 'install)))
|
(action-type (if installed 'delete 'install)))
|
||||||
(guix-info-insert-val-default
|
(guix-info-insert-value-format
|
||||||
output
|
output
|
||||||
(if installed
|
(if installed
|
||||||
'guix-package-info-installed-outputs
|
'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."
|
"Face used if a generation is not the current one."
|
||||||
:group 'guix-generation-info-faces)
|
: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 _)
|
(defun guix-generation-info-insert-number (number &optional _)
|
||||||
"Insert generation NUMBER and action buttons."
|
"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-indent)
|
||||||
(guix-info-insert-action-button
|
(guix-info-insert-action-button
|
||||||
"Packages"
|
"Packages"
|
||||||
|
@ -868,8 +826,8 @@ If nil, insert generation in a default way.")
|
||||||
(defun guix-generation-info-insert-current (val entry)
|
(defun guix-generation-info-insert-current (val entry)
|
||||||
"Insert boolean value VAL showing whether this generation is current."
|
"Insert boolean value VAL showing whether this generation is current."
|
||||||
(if val
|
(if val
|
||||||
(guix-info-insert-val-default "Yes" 'guix-generation-info-current)
|
(guix-info-insert-value-format "Yes" 'guix-generation-info-current)
|
||||||
(guix-info-insert-val-default "No" 'guix-generation-info-not-current)
|
(guix-info-insert-value-format "No" 'guix-generation-info-not-current)
|
||||||
(guix-info-insert-indent)
|
(guix-info-insert-indent)
|
||||||
(guix-info-insert-action-button
|
(guix-info-insert-action-button
|
||||||
"Switch"
|
"Switch"
|
||||||
|
|
|
@ -104,6 +104,28 @@ See `insert-text-button' for the meaning of PROPERTIES."
|
||||||
:type (or type 'button)
|
:type (or type 'button)
|
||||||
properties)))
|
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)
|
(defun guix-split-insert (val &optional face col separator)
|
||||||
"Convert VAL into a string, split it and insert at point.
|
"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)
|
(defun guix-split-string (str &optional col)
|
||||||
"Split string STR by lines and return list of result strings.
|
"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,
|
If COL is non-nil, fill STR to this column."
|
||||||
split it into several short lines."
|
(let ((str (if col
|
||||||
(let ((strings (split-string str "\n *")))
|
(guix-get-filled-string str col)
|
||||||
(if (and col
|
str)))
|
||||||
(null (cdr strings)) ; if not multi-line
|
(split-string str "\n *" t)))
|
||||||
(> (length str) col))
|
|
||||||
(split-string (guix-get-filled-string str col) "\n")
|
|
||||||
strings)))
|
|
||||||
|
|
||||||
(defun guix-get-filled-string (str col)
|
(defun guix-get-filled-string (str col)
|
||||||
"Return string by filling STR to column COL."
|
"Return string by filling STR to column COL."
|
||||||
|
|
Reference in a new issue