emacs: Generalize buffer interface.
Extract the code for defining buffer interface from "guix-base.el", generalize it and move to "guix-buffer.el". * emacs.am (ELFILES): Add "emacs/guix-buffer.el". * emacs/guix-base.el (guix-profile, guix-entries, guix-buffer-type) (guix-entry-type, guix-search-type, guix-search-vals, guix-set-vars) (guix-get-symbol, guix-show-entries, guix-get-show-entries) (guix-set-buffer, guix-history-call, guix-make-history-item) (guix-get-params-for-receiving): Remove. (guix-switch-to-buffer): Rename to 'guix-buffer-display' and move to "guix-buffer.el". (guix-get-entries): Rename to 'guix-ui-get-entries' and move to "guix-ui.el". (guix-buffer-data, guix-buffer-value, guix-buffer-param-title) (guix-buffer-name, guix-buffer-history-size) (guix-buffer-revert-confirm?, guix-buffer-map, guix-buffer-revert) (guix-buffer-after-redisplay-hook, guix-buffer-redisplay) (guix-buffer-redisplay-goto-button): Move to... * emacs/guix-buffer.el: ... here. New file. (guix-buffer-item): New variable. (guix-buffer-with-item, guix-buffer-with-current-item) (guix-buffer-define-current-item-accessor) (guix-buffer-define-current-item-accessors) (guix-buffer-define-current-args-accessor) (guix-buffer-define-current-args-accessors): New macros. (guix-buffer-get-entries, guix-buffer-mode-enable) (guix-buffer-mode-initialize, guix-buffer-insert-entries) (guix-buffer-show-entries-default, guix-buffer-show-entries) (guix-buffer-message, guix-buffer-history-item, guix-buffer-set) (guix-buffer-display-entries-current) (guix-buffer-get-display-entries-current) (guix-buffer-display-entries, guix-buffer-get-display-entries): New procedures. * emacs/guix-info.el: Adjust for the procedures renaming. (guix-info-define-interface): Add ':show-entries-function' keyword. * emacs/guix-list.el: Likewise. * emacs/guix-ui.el (guix-ui-define-interface): Generate 'guix-ENTRY-TYPE-BUFFER-TYPE-get-entries' procedure based on 'guix-ui-get-entries'. * emacs/guix.el (guix-get-show-packages, guix-get-show-generations): Adjust for the procedures renaming.master
parent
8103c22fea
commit
6c40b7b703
1
emacs.am
1
emacs.am
|
@ -22,6 +22,7 @@ ELFILES = \
|
|||
emacs/guix-backend.el \
|
||||
emacs/guix-base.el \
|
||||
emacs/guix-build-log.el \
|
||||
emacs/guix-buffer.el \
|
||||
emacs/guix-command.el \
|
||||
emacs/guix-devel.el \
|
||||
emacs/guix-emacs.el \
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
;; This file provides some base and common definitions for guix.el
|
||||
;; package.
|
||||
|
||||
;; List and info buffers have many common patterns that are defined
|
||||
;; using `guix-buffer-define-interface' macro from this file.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
|
@ -34,8 +31,6 @@
|
|||
(require 'guix-guile)
|
||||
(require 'guix-utils)
|
||||
(require 'guix-ui)
|
||||
(require 'guix-history)
|
||||
(require 'guix-messages)
|
||||
|
||||
|
||||
;;; Parameters of the entries
|
||||
|
@ -142,227 +137,6 @@ For the meaning of location, see `guix-find-location'."
|
|||
'package-names-lists)))
|
||||
#'string<))
|
||||
|
||||
|
||||
;;; Buffers
|
||||
|
||||
(defun guix-switch-to-buffer (buffer)
|
||||
"Switch to a 'list' or 'info' BUFFER."
|
||||
(pop-to-buffer buffer
|
||||
'((display-buffer-reuse-window
|
||||
display-buffer-same-window))))
|
||||
|
||||
|
||||
;;; Common definitions for buffer types
|
||||
|
||||
(defvar guix-buffer-data nil
|
||||
"Alist with 'buffer' data.
|
||||
This alist is filled by `guix-buffer-define-interface' macro.")
|
||||
|
||||
(defun guix-buffer-value (buffer-type entry-type symbol)
|
||||
"Return SYMBOL's value for BUFFER-TYPE/ENTRY-TYPE from `guix-buffer-data'."
|
||||
(symbol-value
|
||||
(guix-assq-value guix-buffer-data buffer-type entry-type symbol)))
|
||||
|
||||
(defun guix-buffer-param-title (buffer-type entry-type param)
|
||||
"Return PARAM title for BUFFER-TYPE/ENTRY-TYPE."
|
||||
(or (guix-assq-value (guix-buffer-value buffer-type entry-type 'titles)
|
||||
param)
|
||||
;; Fallback to a title defined in 'info' interface.
|
||||
(unless (eq buffer-type 'info)
|
||||
(guix-assq-value (guix-buffer-value 'info entry-type 'titles)
|
||||
param))
|
||||
(guix-symbol-title param)))
|
||||
|
||||
(defun guix-buffer-name (buffer-type entry-type profile)
|
||||
"Return name of BUFFER-TYPE buffer for displaying ENTRY-TYPE entries."
|
||||
(let ((str-or-fun (guix-buffer-value buffer-type entry-type
|
||||
'buffer-name)))
|
||||
(if (stringp str-or-fun)
|
||||
str-or-fun
|
||||
(funcall str-or-fun profile))))
|
||||
|
||||
(defun guix-buffer-history-size (buffer-type entry-type)
|
||||
"Return history size for BUFFER-TYPE/ENTRY-TYPE."
|
||||
(guix-buffer-value buffer-type entry-type 'history-size))
|
||||
|
||||
(defun guix-buffer-revert-confirm? (buffer-type entry-type)
|
||||
"Return 'revert-confirm' value for BUFFER-TYPE/ENTRY-TYPE."
|
||||
(guix-buffer-value buffer-type entry-type 'revert-confirm))
|
||||
|
||||
(defvar guix-buffer-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "l") 'guix-history-back)
|
||||
(define-key map (kbd "r") 'guix-history-forward)
|
||||
(define-key map (kbd "g") 'revert-buffer)
|
||||
(define-key map (kbd "R") 'guix-buffer-redisplay)
|
||||
map)
|
||||
"Parent keymap for Guix buffer modes.")
|
||||
|
||||
(defvar-local guix-profile nil
|
||||
"Profile used for the current buffer.")
|
||||
(put 'guix-profile 'permanent-local t)
|
||||
|
||||
(defvar-local guix-entries nil
|
||||
"List of the currently displayed entries.
|
||||
Each element of the list is alist with entry info of the
|
||||
following form:
|
||||
|
||||
((PARAM . VAL) ...)
|
||||
|
||||
PARAM is a name of the entry parameter.
|
||||
VAL is a value of this parameter.")
|
||||
(put 'guix-entries 'permanent-local t)
|
||||
|
||||
(defvar-local guix-buffer-type nil
|
||||
"Type of the current buffer.")
|
||||
(put 'guix-buffer-type 'permanent-local t)
|
||||
|
||||
(defvar-local guix-entry-type nil
|
||||
"Type of the current entry.")
|
||||
(put 'guix-entry-type 'permanent-local t)
|
||||
|
||||
(defvar-local guix-search-type nil
|
||||
"Type of the current search.")
|
||||
(put 'guix-search-type 'permanent-local t)
|
||||
|
||||
(defvar-local guix-search-vals nil
|
||||
"Values of the current search.")
|
||||
(put 'guix-search-vals 'permanent-local t)
|
||||
|
||||
(defsubst guix-set-vars (profile entries buffer-type entry-type
|
||||
search-type search-vals)
|
||||
"Set local variables for the current Guix buffer."
|
||||
(setq default-directory profile
|
||||
guix-profile profile
|
||||
guix-entries entries
|
||||
guix-buffer-type buffer-type
|
||||
guix-entry-type entry-type
|
||||
guix-search-type search-type
|
||||
guix-search-vals search-vals))
|
||||
|
||||
(defun guix-get-symbol (postfix buffer-type &optional entry-type)
|
||||
(intern (concat "guix-"
|
||||
(when entry-type
|
||||
(concat (symbol-name entry-type) "-"))
|
||||
(symbol-name buffer-type) "-" postfix)))
|
||||
|
||||
(defmacro guix-buffer-define-interface (buffer-type entry-type &rest args)
|
||||
"Define BUFFER-TYPE interface for displaying ENTRY-TYPE entries.
|
||||
Remaining arguments (ARGS) should have a form [KEYWORD VALUE] ...
|
||||
In the following description TYPE means ENTRY-TYPE-BUFFER-TYPE.
|
||||
|
||||
The following stuff should be defined outside this macro:
|
||||
|
||||
- `guix-BUFFER-TYPE-mode' - parent mode of the generated mode.
|
||||
|
||||
- `guix-TYPE-mode-initialize' (optional) - function for
|
||||
additional mode settings; it is called without arguments.
|
||||
|
||||
Required keywords:
|
||||
|
||||
- `:buffer-name' - default value of the generated
|
||||
`guix-TYPE-buffer-name' variable.
|
||||
|
||||
Optional keywords:
|
||||
|
||||
- `:titles' - default value of the generated
|
||||
`guix-TYPE-titles' variable.
|
||||
|
||||
- `:history-size' - default value of the generated
|
||||
`guix-TYPE-history-size' variable.
|
||||
|
||||
- `:revert-confirm?' - default value of the generated
|
||||
`guix-TYPE-revert-confirm' variable.
|
||||
|
||||
- `:reduced?' - if non-nil, generate only group, faces group
|
||||
and titles variable."
|
||||
(declare (indent 2))
|
||||
(let* ((entry-type-str (symbol-name entry-type))
|
||||
(buffer-type-str (symbol-name buffer-type))
|
||||
(Entry-type-str (capitalize entry-type-str))
|
||||
(Buffer-type-str (capitalize buffer-type-str))
|
||||
(entry-str (concat entry-type-str " entries"))
|
||||
(prefix (concat "guix-" entry-type-str "-"
|
||||
buffer-type-str))
|
||||
(group (intern prefix))
|
||||
(faces-group (intern (concat prefix "-faces")))
|
||||
(mode-map-str (concat prefix "-mode-map"))
|
||||
(parent-mode (intern (concat "guix-" buffer-type-str "-mode")))
|
||||
(mode (intern (concat prefix "-mode")))
|
||||
(mode-init-fun (intern (concat prefix "-mode-initialize")))
|
||||
(buffer-name-var (intern (concat prefix "-buffer-name")))
|
||||
(titles-var (intern (concat prefix "-titles")))
|
||||
(history-size-var (intern (concat prefix "-history-size")))
|
||||
(revert-confirm-var (intern (concat prefix "-revert-confirm"))))
|
||||
(guix-keyword-args-let args
|
||||
((buffer-name-val :buffer-name)
|
||||
(titles-val :titles)
|
||||
(history-size-val :history-size 20)
|
||||
(revert-confirm-val :revert-confirm? t)
|
||||
(reduced? :reduced?))
|
||||
`(progn
|
||||
(defgroup ,group nil
|
||||
,(format "Display '%s' entries in '%s' buffer."
|
||||
entry-type-str buffer-type-str)
|
||||
:prefix ,(concat prefix "-")
|
||||
:group ',(intern (concat "guix-" buffer-type-str)))
|
||||
|
||||
(defgroup ,faces-group nil
|
||||
,(format "Faces for displaying '%s' entries in '%s' buffer."
|
||||
entry-type-str buffer-type-str)
|
||||
:group ',(intern (concat "guix-" buffer-type-str "-faces")))
|
||||
|
||||
(defcustom ,titles-var ,titles-val
|
||||
,(format "Alist of titles of '%s' parameters."
|
||||
entry-type-str)
|
||||
:type '(alist :key-type symbol :value-type string)
|
||||
:group ',group)
|
||||
|
||||
,(unless reduced?
|
||||
`(progn
|
||||
(defcustom ,buffer-name-var ,buffer-name-val
|
||||
,(format "\
|
||||
Default name of '%s' buffer for displaying '%s' entries."
|
||||
buffer-type-str entry-type-str)
|
||||
:type 'string
|
||||
:group ',group)
|
||||
|
||||
(defcustom ,history-size-var ,history-size-val
|
||||
,(format "\
|
||||
Maximum number of items saved in history of `%S' buffer.
|
||||
If 0, the history is disabled."
|
||||
buffer-name-var)
|
||||
:type 'integer
|
||||
:group ',group)
|
||||
|
||||
(defcustom ,revert-confirm-var ,revert-confirm-val
|
||||
,(format "\
|
||||
If non-nil, ask to confirm for reverting `%S' buffer."
|
||||
buffer-name-var)
|
||||
:type 'boolean
|
||||
:group ',group)
|
||||
|
||||
(guix-alist-put!
|
||||
'((buffer-name . ,buffer-name-var)
|
||||
(history-size . ,history-size-var)
|
||||
(revert-confirm . ,revert-confirm-var))
|
||||
'guix-buffer-data ',buffer-type ',entry-type)
|
||||
|
||||
(define-derived-mode ,mode ,parent-mode
|
||||
,(concat "Guix-" Buffer-type-str)
|
||||
,(concat "Major mode for displaying information about "
|
||||
entry-str ".\n\n"
|
||||
"\\{" mode-map-str "}")
|
||||
(setq-local revert-buffer-function 'guix-buffer-revert)
|
||||
(setq-local guix-history-size
|
||||
(guix-buffer-history-size
|
||||
',buffer-type ',entry-type))
|
||||
(and (fboundp ',mode-init-fun) (,mode-init-fun)))))
|
||||
|
||||
(guix-alist-put!
|
||||
',titles-var 'guix-buffer-data
|
||||
',buffer-type ',entry-type 'titles)))))
|
||||
|
||||
|
||||
;;; Getting and displaying info about packages and generations
|
||||
|
||||
|
@ -384,159 +158,6 @@ information)."
|
|||
(const :tag "Display outputs" output))
|
||||
:group 'guix)
|
||||
|
||||
(defun guix-get-entries (profile entry-type search-type search-vals
|
||||
&optional params)
|
||||
"Search for entries of ENTRY-TYPE.
|
||||
|
||||
Call an appropriate scheme function and return a list of the
|
||||
form of `guix-entries'.
|
||||
|
||||
ENTRY-TYPE should be one of the following symbols: `package',
|
||||
`output' or `generation'.
|
||||
|
||||
SEARCH-TYPE may be one of the following symbols:
|
||||
|
||||
- If ENTRY-TYPE is `package' or `output': `id', `name', `regexp',
|
||||
`all-available', `newest-available', `installed', `obsolete',
|
||||
`generation'.
|
||||
|
||||
- If ENTRY-TYPE is `generation': `id', `last', `all', `time'.
|
||||
|
||||
PARAMS is a list of parameters for receiving. If nil, get
|
||||
information with all available parameters."
|
||||
(guix-eval-read (guix-make-guile-expression
|
||||
'entries
|
||||
profile params entry-type search-type search-vals)))
|
||||
|
||||
(defun guix-get-show-entries (profile buffer-type entry-type search-type
|
||||
&rest search-vals)
|
||||
"Search for ENTRY-TYPE entries and show results in BUFFER-TYPE buffer.
|
||||
See `guix-get-entries' for the meaning of SEARCH-TYPE and SEARCH-VALS."
|
||||
(let ((entries (guix-get-entries profile entry-type search-type search-vals
|
||||
(guix-get-params-for-receiving
|
||||
buffer-type entry-type))))
|
||||
(guix-set-buffer profile entries buffer-type entry-type
|
||||
search-type search-vals)))
|
||||
|
||||
(defun guix-set-buffer (profile entries buffer-type entry-type search-type
|
||||
search-vals &optional history-replace no-display)
|
||||
"Set up BUFFER-TYPE buffer for displaying ENTRY-TYPE ENTRIES.
|
||||
|
||||
Insert ENTRIES in buffer, set variables and make history item.
|
||||
ENTRIES should have a form of `guix-entries'.
|
||||
|
||||
See `guix-get-entries' for the meaning of SEARCH-TYPE and SEARCH-VALS.
|
||||
|
||||
If HISTORY-REPLACE is non-nil, replace current history item,
|
||||
otherwise add the new one.
|
||||
|
||||
If NO-DISPLAY is non-nil, do not switch to the buffer."
|
||||
(when entries
|
||||
(let ((buf (if (and (eq major-mode
|
||||
(guix-get-symbol "mode" buffer-type entry-type))
|
||||
(equal guix-profile profile))
|
||||
(current-buffer)
|
||||
(get-buffer-create
|
||||
(guix-buffer-name buffer-type entry-type profile)))))
|
||||
(with-current-buffer buf
|
||||
(guix-show-entries entries buffer-type entry-type)
|
||||
(guix-set-vars profile entries buffer-type entry-type
|
||||
search-type search-vals)
|
||||
(funcall (if history-replace
|
||||
#'guix-history-replace
|
||||
#'guix-history-add)
|
||||
(guix-make-history-item)))
|
||||
(or no-display
|
||||
(guix-switch-to-buffer buf))))
|
||||
(guix-result-message profile entries entry-type
|
||||
search-type search-vals))
|
||||
|
||||
(defun guix-show-entries (entries buffer-type entry-type)
|
||||
"Display ENTRY-TYPE ENTRIES in the current BUFFER-TYPE buffer."
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(funcall (symbol-function (guix-get-symbol
|
||||
"mode" buffer-type entry-type)))
|
||||
(funcall (guix-get-symbol "insert-entries" buffer-type)
|
||||
entries entry-type)
|
||||
(goto-char (point-min))))
|
||||
|
||||
(defun guix-history-call (profile entries buffer-type entry-type
|
||||
search-type search-vals)
|
||||
"Function called for moving by history."
|
||||
(guix-show-entries entries buffer-type entry-type)
|
||||
(guix-set-vars profile entries buffer-type entry-type
|
||||
search-type search-vals)
|
||||
(guix-result-message profile entries entry-type
|
||||
search-type search-vals))
|
||||
|
||||
(defun guix-make-history-item ()
|
||||
"Make and return a history item for the current buffer."
|
||||
(list #'guix-history-call
|
||||
guix-profile guix-entries guix-buffer-type guix-entry-type
|
||||
guix-search-type guix-search-vals))
|
||||
|
||||
(defun guix-get-params-for-receiving (buffer-type entry-type)
|
||||
"Return parameters that should be received for BUFFER-TYPE, ENTRY-TYPE."
|
||||
(let* ((required-var (guix-get-symbol "required-params"
|
||||
buffer-type entry-type))
|
||||
(required (symbol-value required-var)))
|
||||
(unless (equal required 'all)
|
||||
(cl-union required
|
||||
(funcall (guix-get-symbol "displayed-params"
|
||||
buffer-type)
|
||||
entry-type)))))
|
||||
|
||||
(defun guix-buffer-revert (_ignore-auto noconfirm)
|
||||
"Update information in the current buffer.
|
||||
The function is suitable for `revert-buffer-function'.
|
||||
See `revert-buffer' for the meaning of NOCONFIRM."
|
||||
(when (or noconfirm
|
||||
(guix-buffer-revert-confirm? guix-buffer-type
|
||||
guix-entry-type)
|
||||
(y-or-n-p "Update current information? "))
|
||||
(let* ((params (guix-get-params-for-receiving guix-buffer-type
|
||||
guix-entry-type))
|
||||
(entries (guix-get-entries
|
||||
guix-profile guix-entry-type
|
||||
guix-search-type guix-search-vals params)))
|
||||
(guix-set-buffer guix-profile entries guix-buffer-type guix-entry-type
|
||||
guix-search-type guix-search-vals t t))))
|
||||
|
||||
(defvar guix-buffer-after-redisplay-hook nil
|
||||
"Hook run by `guix-buffer-redisplay'.
|
||||
This hook is called before seting up a window position.")
|
||||
|
||||
(defun guix-buffer-redisplay ()
|
||||
"Redisplay the current Guix buffer.
|
||||
Restore the point and window positions after redisplaying.
|
||||
|
||||
This function does not update the buffer data, use
|
||||
'\\[revert-buffer]' if you want the full update."
|
||||
(interactive)
|
||||
(let* ((old-point (point))
|
||||
;; For simplicity, ignore an unlikely case when multiple
|
||||
;; windows display the same buffer.
|
||||
(window (car (get-buffer-window-list (current-buffer) nil t)))
|
||||
(window-start (and window (window-start window))))
|
||||
(guix-set-buffer guix-profile guix-entries guix-buffer-type
|
||||
guix-entry-type guix-search-type guix-search-vals
|
||||
t t)
|
||||
(goto-char old-point)
|
||||
(run-hooks 'guix-buffer-after-redisplay-hook)
|
||||
(when window
|
||||
(set-window-point window (point))
|
||||
(set-window-start window window-start))))
|
||||
|
||||
(defun guix-buffer-redisplay-goto-button ()
|
||||
"Redisplay the current buffer and go to the next button, if needed."
|
||||
(let ((guix-buffer-after-redisplay-hook
|
||||
(cons (lambda ()
|
||||
(unless (button-at (point))
|
||||
(forward-button 1)))
|
||||
guix-buffer-after-redisplay-hook)))
|
||||
(guix-buffer-redisplay)))
|
||||
|
||||
|
||||
;;; Generations
|
||||
|
||||
|
@ -640,13 +261,14 @@ Create the buffer if needed."
|
|||
|
||||
(defun guix-profile-generation-manifest-file (generation)
|
||||
"Return the file name of a GENERATION's manifest.
|
||||
GENERATION is a generation number of `guix-profile' profile."
|
||||
(guix-manifest-file guix-profile generation))
|
||||
GENERATION is a generation number of the current profile."
|
||||
(guix-manifest-file (guix-ui-current-profile) generation))
|
||||
|
||||
(defun guix-profile-generation-packages-buffer (generation)
|
||||
"Insert GENERATION's package outputs in a buffer and return it.
|
||||
GENERATION is a generation number of `guix-profile' profile."
|
||||
(guix-generation-packages-buffer guix-profile generation))
|
||||
GENERATION is a generation number of the current profile."
|
||||
(guix-generation-packages-buffer (guix-ui-current-profile)
|
||||
generation))
|
||||
|
||||
|
||||
;;; Actions on packages and generations
|
||||
|
@ -757,7 +379,7 @@ Ask a user if needed (see `guix-operation-confirm').
|
|||
INSTALL, UPGRADE, REMOVE are 'package action specifications'.
|
||||
See `guix-process-package-actions' for details."
|
||||
(or (null guix-operation-confirm)
|
||||
(let* ((entries (guix-get-entries
|
||||
(let* ((entries (guix-ui-get-entries
|
||||
profile 'package 'id
|
||||
(append (mapcar #'car install)
|
||||
(mapcar #'car upgrade)
|
||||
|
@ -930,12 +552,12 @@ See Info node `(guix) Invoking guix package' for details.
|
|||
Interactively, use the current profile and prompt for manifest
|
||||
FILE. With a prefix argument, also prompt for PROFILE."
|
||||
(interactive
|
||||
(let* ((default-profile (or guix-profile guix-current-profile))
|
||||
(let* ((current-profile (guix-ui-current-profile))
|
||||
(profile (if current-prefix-arg
|
||||
(guix-profile-prompt)
|
||||
default-profile))
|
||||
(or current-profile guix-current-profile)))
|
||||
(file (read-file-name "File with manifest: "))
|
||||
(buffer (and guix-profile (current-buffer))))
|
||||
(buffer (and current-profile (current-buffer))))
|
||||
(list profile file buffer)))
|
||||
(when (or (not guix-operation-confirm)
|
||||
(y-or-n-p (format "Apply manifest from '%s' to profile '%s'? "
|
||||
|
|
|
@ -0,0 +1,566 @@
|
|||
;;; guix-buffer.el --- Buffer interface for displaying data -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
|
||||
|
||||
;; This file is part of GNU Guix.
|
||||
|
||||
;; GNU Guix is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Guix is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file provides a general 'buffer' interface for displaying an
|
||||
;; arbitrary data.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'guix-history)
|
||||
(require 'guix-utils)
|
||||
|
||||
(defvar guix-buffer-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "l") 'guix-history-back)
|
||||
(define-key map (kbd "r") 'guix-history-forward)
|
||||
(define-key map (kbd "g") 'revert-buffer)
|
||||
(define-key map (kbd "R") 'guix-buffer-redisplay)
|
||||
map)
|
||||
"Parent keymap for Guix buffer modes.")
|
||||
|
||||
|
||||
;;; Buffer item
|
||||
|
||||
(cl-defstruct (guix-buffer-item
|
||||
(:constructor nil)
|
||||
(:constructor guix-buffer-make-item
|
||||
(entries buffer-type entry-type args))
|
||||
(:copier nil))
|
||||
entries buffer-type entry-type args)
|
||||
|
||||
(defvar-local guix-buffer-item nil
|
||||
"Data (structure) for the current Guix buffer.
|
||||
The structure consists of the following elements:
|
||||
|
||||
- `entries': list of the currently displayed entries.
|
||||
|
||||
Each element of the list is an alist with an entry data of the
|
||||
following form:
|
||||
|
||||
((PARAM . VAL) ...)
|
||||
|
||||
PARAM is a name of the entry parameter.
|
||||
VAL is a value of this parameter.
|
||||
|
||||
- `entry-type': type of the currently displayed entries.
|
||||
|
||||
- `buffer-type': type of the current buffer.
|
||||
|
||||
- `args': search arguments used to get the current entries.")
|
||||
(put 'guix-buffer-item 'permanent-local t)
|
||||
|
||||
(defmacro guix-buffer-with-item (item &rest body)
|
||||
"Evaluate BODY using buffer ITEM.
|
||||
The following local variables are available inside BODY:
|
||||
`%entries', `%buffer-type', `%entry-type', `%args'.
|
||||
See `guix-buffer-item' for details."
|
||||
(declare (indent 1) (debug t))
|
||||
(let ((item-var (make-symbol "item")))
|
||||
`(let ((,item-var ,item))
|
||||
(let ((%entries (guix-buffer-item-entries ,item-var))
|
||||
(%buffer-type (guix-buffer-item-buffer-type ,item-var))
|
||||
(%entry-type (guix-buffer-item-entry-type ,item-var))
|
||||
(%args (guix-buffer-item-args ,item-var)))
|
||||
,@body))))
|
||||
|
||||
(defmacro guix-buffer-with-current-item (&rest body)
|
||||
"Evaluate BODY using `guix-buffer-item'.
|
||||
See `guix-buffer-with-item' for details."
|
||||
(declare (indent 0) (debug t))
|
||||
`(guix-buffer-with-item guix-buffer-item
|
||||
,@body))
|
||||
|
||||
(defmacro guix-buffer-define-current-item-accessor (name)
|
||||
"Define `guix-buffer-current-NAME' function to access NAME
|
||||
element of `guix-buffer-item' structure.
|
||||
NAME should be a symbol."
|
||||
(let* ((name-str (symbol-name name))
|
||||
(accessor (intern (concat "guix-buffer-item-" name-str)))
|
||||
(fun-name (intern (concat "guix-buffer-current-" name-str)))
|
||||
(doc (format "\
|
||||
Return '%s' of the current Guix buffer.
|
||||
See `guix-buffer-item' for details."
|
||||
name-str)))
|
||||
`(defun ,fun-name ()
|
||||
,doc
|
||||
(and guix-buffer-item
|
||||
(,accessor guix-buffer-item)))))
|
||||
|
||||
(defmacro guix-buffer-define-current-item-accessors (&rest names)
|
||||
"Define `guix-buffer-current-NAME' functions for NAMES.
|
||||
See `guix-buffer-define-current-item-accessor' for details."
|
||||
`(progn
|
||||
,@(mapcar (lambda (name)
|
||||
`(guix-buffer-define-current-item-accessor ,name))
|
||||
names)))
|
||||
|
||||
(guix-buffer-define-current-item-accessors
|
||||
entries entry-type buffer-type args)
|
||||
|
||||
(defmacro guix-buffer-define-current-args-accessor (n prefix name)
|
||||
"Define `PREFIX-NAME' function to access Nth element of 'args'
|
||||
field of `guix-buffer-item' structure.
|
||||
PREFIX and NAME should be strings."
|
||||
(let ((fun-name (intern (concat prefix "-" name)))
|
||||
(doc (format "\
|
||||
Return '%s' of the current Guix buffer.
|
||||
'%s' is the element number %d in 'args' of `guix-buffer-item'."
|
||||
name name n)))
|
||||
`(defun ,fun-name ()
|
||||
,doc
|
||||
(nth ,n (guix-buffer-current-args)))))
|
||||
|
||||
(defmacro guix-buffer-define-current-args-accessors (prefix &rest names)
|
||||
"Define `PREFIX-NAME' functions for NAMES.
|
||||
See `guix-buffer-define-current-args-accessor' for details."
|
||||
`(progn
|
||||
,@(cl-loop for name in names
|
||||
for i from 0
|
||||
collect `(guix-buffer-define-current-args-accessor
|
||||
,i ,prefix ,name))))
|
||||
|
||||
|
||||
;;; Wrappers for defined variables
|
||||
|
||||
(defvar guix-buffer-data nil
|
||||
"Alist with 'buffer' data.
|
||||
This alist is filled by `guix-buffer-define-interface' macro.")
|
||||
|
||||
(defun guix-buffer-value (buffer-type entry-type symbol)
|
||||
"Return SYMBOL's value for BUFFER-TYPE/ENTRY-TYPE from `guix-buffer-data'."
|
||||
(symbol-value
|
||||
(guix-assq-value guix-buffer-data buffer-type entry-type symbol)))
|
||||
|
||||
(defun guix-buffer-get-entries (buffer-type entry-type args)
|
||||
"Return ENTRY-TYPE entries.
|
||||
Call an appropriate 'get-entries' function from `guix-buffer'
|
||||
using ARGS as its arguments."
|
||||
(apply (guix-buffer-value buffer-type entry-type 'get-entries)
|
||||
args))
|
||||
|
||||
(defun guix-buffer-mode-enable (buffer-type entry-type)
|
||||
"Turn on major mode to display ENTRY-TYPE ENTRIES in BUFFER-TYPE buffer."
|
||||
(funcall (guix-buffer-value buffer-type entry-type 'mode)))
|
||||
|
||||
(defun guix-buffer-mode-initialize (buffer-type entry-type)
|
||||
"Set up the current BUFFER-TYPE buffer to display ENTRY-TYPE entries."
|
||||
(let ((fun (guix-buffer-value buffer-type entry-type 'mode-init)))
|
||||
(when fun
|
||||
(funcall fun))))
|
||||
|
||||
(defun guix-buffer-insert-entries (entries buffer-type entry-type)
|
||||
"Show ENTRY-TYPE ENTRIES in the current BUFFER-TYPE buffer."
|
||||
(funcall (guix-buffer-value buffer-type entry-type 'insert-entries)
|
||||
entries))
|
||||
|
||||
(defun guix-buffer-show-entries-default (entries buffer-type entry-type)
|
||||
"Show ENTRY-TYPE ENTRIES in the current BUFFER-TYPE buffer."
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(guix-buffer-mode-enable buffer-type entry-type)
|
||||
(guix-buffer-insert-entries entries buffer-type entry-type)
|
||||
(goto-char (point-min))))
|
||||
|
||||
(defun guix-buffer-show-entries (entries buffer-type entry-type)
|
||||
"Show ENTRY-TYPE ENTRIES in the current BUFFER-TYPE buffer."
|
||||
(funcall (guix-buffer-value buffer-type entry-type 'show-entries)
|
||||
entries))
|
||||
|
||||
(defun guix-buffer-message (entries buffer-type entry-type args)
|
||||
"Display a message for BUFFER-ITEM after showing entries."
|
||||
(let ((fun (guix-buffer-value buffer-type entry-type 'message)))
|
||||
(when fun
|
||||
(apply fun entries args))))
|
||||
|
||||
(defun guix-buffer-name (buffer-type entry-type args)
|
||||
"Return name of BUFFER-TYPE buffer for displaying ENTRY-TYPE entries."
|
||||
(let ((str-or-fun (guix-buffer-value buffer-type entry-type
|
||||
'buffer-name)))
|
||||
(if (stringp str-or-fun)
|
||||
str-or-fun
|
||||
(apply str-or-fun args))))
|
||||
|
||||
(defun guix-buffer-param-title (buffer-type entry-type param)
|
||||
"Return PARAM title for BUFFER-TYPE/ENTRY-TYPE."
|
||||
(or (guix-assq-value (guix-buffer-value buffer-type entry-type 'titles)
|
||||
param)
|
||||
;; Fallback to a title defined in 'info' interface.
|
||||
(unless (eq buffer-type 'info)
|
||||
(guix-assq-value (guix-buffer-value 'info entry-type 'titles)
|
||||
param))
|
||||
(guix-symbol-title param)))
|
||||
|
||||
(defun guix-buffer-history-size (buffer-type entry-type)
|
||||
"Return history size for BUFFER-TYPE/ENTRY-TYPE."
|
||||
(guix-buffer-value buffer-type entry-type 'history-size))
|
||||
|
||||
(defun guix-buffer-revert-confirm? (buffer-type entry-type)
|
||||
"Return 'revert-confirm' value for BUFFER-TYPE/ENTRY-TYPE."
|
||||
(guix-buffer-value buffer-type entry-type 'revert-confirm))
|
||||
|
||||
|
||||
;;; Displaying entries
|
||||
|
||||
(defun guix-buffer-display (buffer)
|
||||
"Switch to a Guix BUFFER."
|
||||
(pop-to-buffer buffer
|
||||
'((display-buffer-reuse-window
|
||||
display-buffer-same-window))))
|
||||
|
||||
(defun guix-buffer-history-item (buffer-item)
|
||||
"Make and return a history item for displaying BUFFER-ITEM."
|
||||
(list #'guix-buffer-set buffer-item))
|
||||
|
||||
(defun guix-buffer-set (buffer-item &optional history)
|
||||
"Set up the current buffer for displaying BUFFER-ITEM.
|
||||
HISTORY should be one of the following:
|
||||
|
||||
`nil' - do not save BUFFER-ITEM in history,
|
||||
|
||||
`add' - add it to history,
|
||||
|
||||
`replace' - replace the current history item."
|
||||
(guix-buffer-with-item buffer-item
|
||||
(when %entries
|
||||
(guix-buffer-show-entries %entries %buffer-type %entry-type)
|
||||
(setq guix-buffer-item buffer-item)
|
||||
(when history
|
||||
(funcall (cl-ecase history
|
||||
(add #'guix-history-add)
|
||||
(replace #'guix-history-replace))
|
||||
(guix-buffer-history-item buffer-item))))
|
||||
(guix-buffer-message %entries %buffer-type %entry-type %args)))
|
||||
|
||||
(defun guix-buffer-display-entries-current
|
||||
(entries buffer-type entry-type args &optional history)
|
||||
"Show ENTRIES in the current Guix buffer.
|
||||
See `guix-buffer-item' for the meaning of BUFFER-TYPE, ENTRY-TYPE
|
||||
and ARGS, and `guix-buffer-set' for the meaning of HISTORY."
|
||||
(let ((item (guix-buffer-make-item entries buffer-type
|
||||
entry-type args)))
|
||||
(guix-buffer-set item history)))
|
||||
|
||||
(defun guix-buffer-get-display-entries-current
|
||||
(buffer-type entry-type args &optional history)
|
||||
"Search for entries and show them in the current Guix buffer.
|
||||
See `guix-buffer-display-entries-current' for details."
|
||||
(guix-buffer-display-entries-current
|
||||
(guix-buffer-get-entries buffer-type entry-type args)
|
||||
buffer-type entry-type args history))
|
||||
|
||||
(defun guix-buffer-display-entries
|
||||
(entries buffer-type entry-type args &optional history)
|
||||
"Show ENTRIES in a BUFFER-TYPE buffer.
|
||||
See `guix-buffer-display-entries-current' for details."
|
||||
(let ((buffer (get-buffer-create
|
||||
(guix-buffer-name buffer-type entry-type args))))
|
||||
(with-current-buffer buffer
|
||||
(guix-buffer-display-entries-current
|
||||
entries buffer-type entry-type args history))
|
||||
(when entries
|
||||
(guix-buffer-display buffer))))
|
||||
|
||||
(defun guix-buffer-get-display-entries
|
||||
(buffer-type entry-type args &optional history)
|
||||
"Search for entries and show them in a BUFFER-TYPE buffer.
|
||||
See `guix-buffer-display-entries-current' for details."
|
||||
(guix-buffer-display-entries
|
||||
(guix-buffer-get-entries buffer-type entry-type args)
|
||||
buffer-type entry-type args history))
|
||||
|
||||
(defun guix-buffer-revert (_ignore-auto noconfirm)
|
||||
"Update the data in the current Guix buffer.
|
||||
This function is suitable for `revert-buffer-function'.
|
||||
See `revert-buffer' for the meaning of NOCONFIRM."
|
||||
(guix-buffer-with-current-item
|
||||
(when (or noconfirm
|
||||
(not (guix-buffer-revert-confirm? %buffer-type %entry-type))
|
||||
(y-or-n-p "Update the current buffer? "))
|
||||
(guix-buffer-get-display-entries-current
|
||||
%buffer-type %entry-type %args 'replace))))
|
||||
|
||||
(defvar guix-buffer-after-redisplay-hook nil
|
||||
"Hook run by `guix-buffer-redisplay'.
|
||||
This hook is called before seting up a window position.")
|
||||
|
||||
(defun guix-buffer-redisplay ()
|
||||
"Redisplay the current Guix buffer.
|
||||
Restore the point and window positions after redisplaying.
|
||||
|
||||
This function does not update the buffer data, use
|
||||
'\\[revert-buffer]' if you want the full update."
|
||||
(interactive)
|
||||
(let* ((old-point (point))
|
||||
;; For simplicity, ignore an unlikely case when multiple
|
||||
;; windows display the same buffer.
|
||||
(window (car (get-buffer-window-list (current-buffer) nil t)))
|
||||
(window-start (and window (window-start window))))
|
||||
(guix-buffer-set guix-buffer-item)
|
||||
(goto-char old-point)
|
||||
(run-hooks 'guix-buffer-after-redisplay-hook)
|
||||
(when window
|
||||
(set-window-point window (point))
|
||||
(set-window-start window window-start))))
|
||||
|
||||
(defun guix-buffer-redisplay-goto-button ()
|
||||
"Redisplay the current buffer and go to the next button, if needed."
|
||||
(let ((guix-buffer-after-redisplay-hook
|
||||
(cons (lambda ()
|
||||
(unless (button-at (point))
|
||||
(forward-button 1)))
|
||||
guix-buffer-after-redisplay-hook)))
|
||||
(guix-buffer-redisplay)))
|
||||
|
||||
|
||||
;;; Interface definer
|
||||
|
||||
(defmacro guix-buffer-define-interface (buffer-type entry-type &rest args)
|
||||
"Define BUFFER-TYPE interface for displaying ENTRY-TYPE entries.
|
||||
Remaining arguments (ARGS) should have a form [KEYWORD VALUE] ...
|
||||
In the following description TYPE means ENTRY-TYPE-BUFFER-TYPE.
|
||||
|
||||
Required keywords:
|
||||
|
||||
- `:buffer-name' - default value of the generated
|
||||
`guix-TYPE-buffer-name' variable.
|
||||
|
||||
- `:get-entries-function' - default value of the generated
|
||||
`guix-TYPE-get-function' variable.
|
||||
|
||||
- `:show-entries-function' - default value of the generated
|
||||
`guix-TYPE-show-function' variable.
|
||||
|
||||
Alternatively, if `:show-entries-function' is not specified, a
|
||||
default `guix-TYPE-show-entries' will be generated, and the
|
||||
following keyword should be specified instead:
|
||||
|
||||
- `:insert-entries-function' - default value of the generated
|
||||
`guix-TYPE-insert-function' variable.
|
||||
|
||||
Optional keywords:
|
||||
|
||||
- `:message-function' - default value of the generated
|
||||
`guix-TYPE-message-function' variable.
|
||||
|
||||
- `:titles' - default value of the generated
|
||||
`guix-TYPE-titles' variable.
|
||||
|
||||
- `:history-size' - default value of the generated
|
||||
`guix-TYPE-history-size' variable.
|
||||
|
||||
- `:revert-confirm?' - default value of the generated
|
||||
`guix-TYPE-revert-confirm' variable.
|
||||
|
||||
- `:mode-name' - name (a string appeared in the mode-line) of
|
||||
the generated `guix-TYPE-mode'.
|
||||
|
||||
- `:mode-init-function' - default value of the generated
|
||||
`guix-TYPE-mode-initialize-function' variable.
|
||||
|
||||
- `:reduced?' - if non-nil, generate only group, faces group
|
||||
and titles variable (if specified); all keywords become
|
||||
optional."
|
||||
(declare (indent 2))
|
||||
(let* ((entry-type-str (symbol-name entry-type))
|
||||
(buffer-type-str (symbol-name buffer-type))
|
||||
(prefix (concat "guix-" entry-type-str "-"
|
||||
buffer-type-str))
|
||||
(group (intern prefix))
|
||||
(faces-group (intern (concat prefix "-faces")))
|
||||
(get-entries-var (intern (concat prefix "-get-function")))
|
||||
(show-entries-var (intern (concat prefix "-show-function")))
|
||||
(show-entries-fun (intern (concat prefix "-show-entries")))
|
||||
(message-var (intern (concat prefix "-message-function")))
|
||||
(buffer-name-var (intern (concat prefix "-buffer-name")))
|
||||
(titles-var (intern (concat prefix "-titles")))
|
||||
(history-size-var (intern (concat prefix "-history-size")))
|
||||
(revert-confirm-var (intern (concat prefix "-revert-confirm"))))
|
||||
(guix-keyword-args-let args
|
||||
((get-entries-val :get-entries-function)
|
||||
(show-entries-val :show-entries-function)
|
||||
(insert-entries-val :insert-entries-function)
|
||||
(mode-name :mode-name (capitalize prefix))
|
||||
(mode-init-val :mode-init-function)
|
||||
(message-val :message-function)
|
||||
(buffer-name-val :buffer-name)
|
||||
(titles-val :titles)
|
||||
(history-size-val :history-size 20)
|
||||
(revert-confirm-val :revert-confirm? t)
|
||||
(reduced? :reduced?))
|
||||
`(progn
|
||||
(defgroup ,group nil
|
||||
,(format "Display '%s' entries in '%s' buffer."
|
||||
entry-type-str buffer-type-str)
|
||||
:prefix ,(concat prefix "-")
|
||||
:group ',(intern (concat "guix-" buffer-type-str)))
|
||||
|
||||
(defgroup ,faces-group nil
|
||||
,(format "Faces for displaying '%s' entries in '%s' buffer."
|
||||
entry-type-str buffer-type-str)
|
||||
:group ',(intern (concat "guix-" buffer-type-str "-faces")))
|
||||
|
||||
(defcustom ,titles-var ,titles-val
|
||||
,(format "Alist of titles of '%s' parameters."
|
||||
entry-type-str)
|
||||
:type '(alist :key-type symbol :value-type string)
|
||||
:group ',group)
|
||||
|
||||
,(unless reduced?
|
||||
`(progn
|
||||
(defvar ,get-entries-var ,get-entries-val
|
||||
,(format "\
|
||||
Function used to receive '%s' entries for '%s' buffer."
|
||||
entry-type-str buffer-type-str))
|
||||
|
||||
(defvar ,show-entries-var
|
||||
,(or show-entries-val `',show-entries-fun)
|
||||
,(format "\
|
||||
Function used to show '%s' entries in '%s' buffer."
|
||||
entry-type-str buffer-type-str))
|
||||
|
||||
(defvar ,message-var ,message-val
|
||||
,(format "\
|
||||
Function used to display a message after showing '%s' entries.
|
||||
If nil, do not display messages."
|
||||
entry-type-str))
|
||||
|
||||
(defcustom ,buffer-name-var ,buffer-name-val
|
||||
,(format "\
|
||||
Default name of '%s' buffer for displaying '%s' entries.
|
||||
May be a string or a function returning a string. The function
|
||||
is called with the same arguments as `%S'."
|
||||
buffer-type-str entry-type-str get-entries-var)
|
||||
:type '(choice string function)
|
||||
:group ',group)
|
||||
|
||||
(defcustom ,history-size-var ,history-size-val
|
||||
,(format "\
|
||||
Maximum number of items saved in history of `%S' buffer.
|
||||
If 0, the history is disabled."
|
||||
buffer-name-var)
|
||||
:type 'integer
|
||||
:group ',group)
|
||||
|
||||
(defcustom ,revert-confirm-var ,revert-confirm-val
|
||||
,(format "\
|
||||
If non-nil, ask to confirm for reverting `%S' buffer."
|
||||
buffer-name-var)
|
||||
:type 'boolean
|
||||
:group ',group)
|
||||
|
||||
(guix-alist-put!
|
||||
'((get-entries . ,get-entries-var)
|
||||
(show-entries . ,show-entries-var)
|
||||
(message . ,message-var)
|
||||
(buffer-name . ,buffer-name-var)
|
||||
(history-size . ,history-size-var)
|
||||
(revert-confirm . ,revert-confirm-var))
|
||||
'guix-buffer-data ',buffer-type ',entry-type)
|
||||
|
||||
,(unless show-entries-val
|
||||
`(defun ,show-entries-fun (entries)
|
||||
,(format "\
|
||||
Show '%s' ENTRIES in the current '%s' buffer."
|
||||
entry-type-str buffer-type-str)
|
||||
(guix-buffer-show-entries-default
|
||||
entries ',buffer-type ',entry-type)))
|
||||
|
||||
,(when (or insert-entries-val
|
||||
(null show-entries-val))
|
||||
(let ((insert-entries-var
|
||||
(intern (concat prefix "-insert-function"))))
|
||||
`(progn
|
||||
(defvar ,insert-entries-var ,insert-entries-val
|
||||
,(format "\
|
||||
Function used to print '%s' entries in '%s' buffer."
|
||||
entry-type-str buffer-type-str))
|
||||
|
||||
(guix-alist-put!
|
||||
',insert-entries-var 'guix-buffer-data
|
||||
',buffer-type ',entry-type
|
||||
'insert-entries))))
|
||||
|
||||
,(when (or mode-name
|
||||
mode-init-val
|
||||
(null show-entries-val))
|
||||
(let* ((mode-str (concat prefix "-mode"))
|
||||
(mode-map-str (concat mode-str "-map"))
|
||||
(mode (intern mode-str))
|
||||
(parent-mode (intern
|
||||
(concat "guix-" buffer-type-str
|
||||
"-mode")))
|
||||
(mode-var (intern
|
||||
(concat mode-str "-function")))
|
||||
(mode-init-var (intern
|
||||
(concat mode-str
|
||||
"-initialize-function"))))
|
||||
`(progn
|
||||
(defvar ,mode-var ',mode
|
||||
,(format "\
|
||||
Major mode for displaying '%s' entries in '%s' buffer."
|
||||
entry-type-str buffer-type-str))
|
||||
|
||||
(defvar ,mode-init-var ,mode-init-val
|
||||
,(format "\
|
||||
Function used to set up '%s' buffer for displaying '%s' entries."
|
||||
buffer-type-str entry-type-str))
|
||||
|
||||
(define-derived-mode ,mode ,parent-mode ,mode-name
|
||||
,(format "\
|
||||
Major mode for displaying '%s' entries in '%s' buffer.
|
||||
|
||||
\\{%s}"
|
||||
entry-type-str buffer-type-str mode-map-str)
|
||||
(setq-local revert-buffer-function
|
||||
'guix-buffer-revert)
|
||||
(setq-local guix-history-size
|
||||
(guix-buffer-history-size
|
||||
',buffer-type ',entry-type))
|
||||
(guix-buffer-mode-initialize
|
||||
',buffer-type ',entry-type))
|
||||
|
||||
(guix-alist-put!
|
||||
',mode-var 'guix-buffer-data
|
||||
',buffer-type ',entry-type 'mode)
|
||||
(guix-alist-put!
|
||||
',mode-init-var 'guix-buffer-data
|
||||
',buffer-type ',entry-type
|
||||
'mode-init))))))
|
||||
|
||||
(guix-alist-put!
|
||||
',titles-var 'guix-buffer-data
|
||||
',buffer-type ',entry-type 'titles)))))
|
||||
|
||||
|
||||
(defvar guix-buffer-font-lock-keywords
|
||||
(eval-when-compile
|
||||
`((,(rx "(" (group (or "guix-buffer-with-item"
|
||||
"guix-buffer-with-current-item"
|
||||
"guix-buffer-define-interface"))
|
||||
symbol-end)
|
||||
. 1))))
|
||||
|
||||
(font-lock-add-keywords 'emacs-lisp-mode guix-buffer-font-lock-keywords)
|
||||
|
||||
(provide 'guix-buffer)
|
||||
|
||||
;;; guix-buffer.el ends here
|
|
@ -202,8 +202,7 @@ LEVEL is 1 by default."
|
|||
(insert (guix-info-get-indent level)))
|
||||
|
||||
(defun guix-info-insert-entries (entries entry-type)
|
||||
"Display ENTRIES of ENTRY-TYPE in the current info buffer.
|
||||
ENTRIES should have a form of `guix-entries'."
|
||||
"Display ENTRY-TYPE ENTRIES in the current info buffer."
|
||||
(guix-mapinsert (lambda (entry)
|
||||
(guix-info-insert-entry entry entry-type))
|
||||
entries
|
||||
|
@ -371,8 +370,11 @@ BUTTON-OR-FACE is a button type)."
|
|||
'face 'guix-package-info-name-button
|
||||
'help-echo "Describe this package"
|
||||
'action (lambda (btn)
|
||||
(guix-get-show-entries guix-profile 'info guix-package-info-type
|
||||
'name (button-label btn))))
|
||||
(guix-buffer-get-display-entries-current
|
||||
'info guix-package-info-type
|
||||
(list (guix-ui-current-profile)
|
||||
'name (button-label btn))
|
||||
'add)))
|
||||
|
||||
(defun guix-info-button-copy-label (&optional pos)
|
||||
"Copy a label of the button at POS into kill ring.
|
||||
|
@ -407,7 +409,8 @@ See `insert-text-button' for the meaning of PROPERTIES."
|
|||
"Keymap for `guix-info-mode' buffers.")
|
||||
|
||||
(define-derived-mode guix-info-mode special-mode "Guix-Info"
|
||||
"Parent mode for displaying information in info buffers.")
|
||||
"Parent mode for displaying data in 'info' form."
|
||||
(setq-local revert-buffer-function 'guix-buffer-revert))
|
||||
|
||||
(defun guix-info-mode-initialize ()
|
||||
"Set up the current 'info' buffer."
|
||||
|
@ -435,7 +438,8 @@ The rest keyword arguments are passed to
|
|||
(group (intern prefix))
|
||||
(format-var (intern (concat prefix "-format"))))
|
||||
(guix-keyword-args-let args
|
||||
((format-val :format))
|
||||
((show-entries-val :show-entries-function)
|
||||
(format-val :format))
|
||||
`(progn
|
||||
(defcustom ,format-var ,format-val
|
||||
,(format "\
|
||||
|
@ -473,9 +477,23 @@ After calling each METHOD, a new line is inserted."
|
|||
'((format . ,format-var))
|
||||
'guix-info-data ',entry-type)
|
||||
|
||||
(guix-buffer-define-interface info ,entry-type
|
||||
:mode-init-function 'guix-info-mode-initialize
|
||||
,@%foreign-args)))))
|
||||
,(if show-entries-val
|
||||
`(guix-buffer-define-interface info ,entry-type
|
||||
:show-entries-function ,show-entries-val
|
||||
,@%foreign-args)
|
||||
|
||||
(let ((insert-fun (intern (concat prefix "-insert-entries"))))
|
||||
`(progn
|
||||
(defun ,insert-fun (entries)
|
||||
,(format "\
|
||||
Print '%s' ENTRIES in the current 'info' buffer."
|
||||
entry-type-str)
|
||||
(guix-info-insert-entries entries ',entry-type))
|
||||
|
||||
(guix-buffer-define-interface info ,entry-type
|
||||
:insert-entries-function ',insert-fun
|
||||
:mode-init-function 'guix-info-mode-initialize
|
||||
,@%foreign-args))))))))
|
||||
|
||||
|
||||
;;; Displaying packages
|
||||
|
@ -675,7 +693,7 @@ ENTRY is an alist with package info."
|
|||
type-str
|
||||
(lambda (btn)
|
||||
(guix-process-package-actions
|
||||
guix-profile
|
||||
(guix-ui-current-profile)
|
||||
`((,(button-get btn 'action-type) (,(button-get btn 'id)
|
||||
,(button-get btn 'output))))
|
||||
(current-buffer)))
|
||||
|
@ -726,15 +744,16 @@ prompt depending on `guix-operation-confirm' variable)."
|
|||
Find the file if needed (see `guix-package-info-auto-find-source').
|
||||
ENTRY-ID is an ID of the current entry (package or output).
|
||||
PACKAGE-ID is an ID of the package which source to show."
|
||||
(let* ((entries guix-entries)
|
||||
(entry (guix-entry-by-id entry-id guix-entries))
|
||||
(let* ((entries (guix-buffer-current-entries))
|
||||
(entry (guix-entry-by-id entry-id entries))
|
||||
(file (guix-package-source-path package-id)))
|
||||
(or file
|
||||
(error "Couldn't define file name of the package source"))
|
||||
(let* ((new-entry (cons (cons 'source-file file)
|
||||
entry))
|
||||
(new-entries (guix-replace-entry entry-id new-entry entries)))
|
||||
(setq guix-entries new-entries)
|
||||
(setf (guix-buffer-item-entries guix-buffer-item)
|
||||
new-entries)
|
||||
(guix-buffer-redisplay-goto-button)
|
||||
(if (file-exists-p file)
|
||||
(if guix-package-info-auto-find-source
|
||||
|
@ -872,15 +891,19 @@ This function is used to hide a \"Download\" button if needed."
|
|||
(guix-info-insert-action-button
|
||||
"Packages"
|
||||
(lambda (btn)
|
||||
(guix-get-show-entries guix-profile 'list guix-package-list-type
|
||||
'generation (button-get btn 'number)))
|
||||
(guix-buffer-get-display-entries
|
||||
'list guix-package-list-type
|
||||
(list (guix-ui-current-profile)
|
||||
'generation (button-get btn 'number))
|
||||
'add))
|
||||
"Show installed packages for this generation"
|
||||
'number number)
|
||||
(guix-info-insert-indent)
|
||||
(guix-info-insert-action-button
|
||||
"Delete"
|
||||
(lambda (btn)
|
||||
(guix-delete-generations guix-profile (list (button-get btn 'number))
|
||||
(guix-delete-generations (guix-ui-current-profile)
|
||||
(list (button-get btn 'number))
|
||||
(current-buffer)))
|
||||
"Delete this generation"
|
||||
'number number))
|
||||
|
@ -894,7 +917,8 @@ This function is used to hide a \"Download\" button if needed."
|
|||
(guix-info-insert-action-button
|
||||
"Switch"
|
||||
(lambda (btn)
|
||||
(guix-switch-to-generation guix-profile (button-get btn 'number)
|
||||
(guix-switch-to-generation (guix-ui-current-profile)
|
||||
(button-get btn 'number)
|
||||
(current-buffer)))
|
||||
"Switch to this generation (make it the current one)"
|
||||
'number (guix-entry-value entry 'number))))
|
||||
|
|
|
@ -61,7 +61,7 @@ With prefix argument, describe entries marked with any mark."
|
|||
(let* ((ids (or (apply #'guix-list-get-marked-id-list mark-names)
|
||||
(list (guix-list-current-id))))
|
||||
(count (length ids))
|
||||
(entry-type guix-entry-type))
|
||||
(entry-type (guix-buffer-current-entry-type)))
|
||||
(when (or (<= count (guix-list-describe-warning-count entry-type))
|
||||
(y-or-n-p (format "Do you really want to describe %d entries? "
|
||||
count)))
|
||||
|
@ -168,8 +168,7 @@ Return a vector made of values of FUN calls."
|
|||
rest-spec))))
|
||||
|
||||
(defun guix-list-insert-entries (entries entry-type)
|
||||
"Display ENTRIES of ENTRY-TYPE in the current list buffer.
|
||||
ENTRIES should have a form of `guix-entries'."
|
||||
"Print ENTRY-TYPE ENTRIES in the current buffer."
|
||||
(setq tabulated-list-entries
|
||||
(guix-list-tabulated-entries entries entry-type))
|
||||
(tabulated-list-print))
|
||||
|
@ -212,14 +211,18 @@ VAL may be nil."
|
|||
'follow-link t
|
||||
'help-echo "Find file"))
|
||||
|
||||
|
||||
;;; 'List' lines
|
||||
|
||||
(defun guix-list-current-id ()
|
||||
"Return ID of the current entry."
|
||||
"Return ID of the entry at point."
|
||||
(or (tabulated-list-get-id)
|
||||
(user-error "No entry here")))
|
||||
|
||||
(defun guix-list-current-entry ()
|
||||
"Return alist of the current entry info."
|
||||
(guix-entry-by-id (guix-list-current-id) guix-entries))
|
||||
"Return entry at point."
|
||||
(guix-entry-by-id (guix-list-current-id)
|
||||
(guix-buffer-current-entries)))
|
||||
|
||||
(defun guix-list-for-each-line (fun &rest args)
|
||||
"Call FUN with ARGS for each entry line."
|
||||
|
@ -429,8 +432,6 @@ The rest keyword arguments are passed to
|
|||
(let* ((entry-type-str (symbol-name entry-type))
|
||||
(prefix (concat "guix-" entry-type-str "-list"))
|
||||
(group (intern prefix))
|
||||
(mode-str (concat prefix "-mode"))
|
||||
(init-fun (intern (concat prefix "-mode-initialize")))
|
||||
(describe-var (intern (concat prefix "-describe-function")))
|
||||
(describe-count-var (intern (concat prefix
|
||||
"-describe-warning-count")))
|
||||
|
@ -438,7 +439,8 @@ The rest keyword arguments are passed to
|
|||
(sort-key-var (intern (concat prefix "-sort-key")))
|
||||
(marks-var (intern (concat prefix "-marks"))))
|
||||
(guix-keyword-args-let args
|
||||
((describe-val :describe-function)
|
||||
((show-entries-val :show-entries-function)
|
||||
(describe-val :describe-function)
|
||||
(describe-count-val :describe-count 10)
|
||||
(format-val :format)
|
||||
(sort-key-val :sort-key)
|
||||
|
@ -498,10 +500,6 @@ See also `guix-list-describe'."
|
|||
,(format "Function used to describe '%s' entries."
|
||||
entry-type-str))
|
||||
|
||||
(defun ,init-fun ()
|
||||
,(concat "Initial settings for `" mode-str "'.")
|
||||
(guix-list-mode-initialize ',entry-type))
|
||||
|
||||
(guix-alist-put!
|
||||
'((describe . ,describe-var)
|
||||
(describe-count . ,describe-count-var)
|
||||
|
@ -510,8 +508,30 @@ See also `guix-list-describe'."
|
|||
(marks . ,marks-var))
|
||||
'guix-list-data ',entry-type)
|
||||
|
||||
(guix-buffer-define-interface list ,entry-type
|
||||
,@%foreign-args)))))
|
||||
,(if show-entries-val
|
||||
`(guix-buffer-define-interface list ,entry-type
|
||||
:show-entries-function ,show-entries-val
|
||||
,@%foreign-args)
|
||||
|
||||
(let ((insert-fun (intern (concat prefix "-insert-entries")))
|
||||
(mode-init-fun (intern (concat prefix "-mode-initialize"))))
|
||||
`(progn
|
||||
(defun ,insert-fun (entries)
|
||||
,(format "\
|
||||
Print '%s' ENTRIES in the current 'list' buffer."
|
||||
entry-type-str)
|
||||
(guix-list-insert-entries entries ',entry-type))
|
||||
|
||||
(defun ,mode-init-fun ()
|
||||
,(format "\
|
||||
Set up the current 'list' buffer for displaying '%s' entries."
|
||||
entry-type-str)
|
||||
(guix-list-mode-initialize ',entry-type))
|
||||
|
||||
(guix-buffer-define-interface list ,entry-type
|
||||
:insert-entries-function ',insert-fun
|
||||
:mode-init-function ',mode-init-fun
|
||||
,@%foreign-args))))))))
|
||||
|
||||
|
||||
;;; Displaying packages
|
||||
|
@ -584,7 +604,7 @@ Colorize it with `guix-package-list-installed' or
|
|||
(when (and (not guix-package-list-generation-marking-enabled)
|
||||
(or (derived-mode-p 'guix-package-list-mode)
|
||||
(derived-mode-p 'guix-output-list-mode))
|
||||
(eq guix-search-type 'generation))
|
||||
(eq (guix-ui-current-search-type) 'generation))
|
||||
(error "Action marks are disabled for lists of 'generation packages'")))
|
||||
|
||||
(defun guix-package-list-mark-outputs (mark default
|
||||
|
@ -655,7 +675,7 @@ accept an entry as argument."
|
|||
(let ((obsolete (cl-remove-if-not
|
||||
(lambda (entry)
|
||||
(guix-entry-value entry 'obsolete))
|
||||
guix-entries)))
|
||||
(guix-buffer-current-entries))))
|
||||
(guix-list-for-each-line
|
||||
(lambda ()
|
||||
(let* ((id (guix-list-current-id))
|
||||
|
@ -682,8 +702,8 @@ FUN should accept action-type as argument."
|
|||
(let ((actions (delq nil
|
||||
(mapcar fun '(install delete upgrade)))))
|
||||
(if actions
|
||||
(guix-process-package-actions
|
||||
guix-profile actions (current-buffer))
|
||||
(guix-process-package-actions (guix-ui-current-profile)
|
||||
actions (current-buffer))
|
||||
(user-error "No operations specified"))))
|
||||
|
||||
(defun guix-package-list-execute ()
|
||||
|
@ -714,7 +734,7 @@ The specification is suitable for `guix-process-package-actions'."
|
|||
(output nil 9 t)
|
||||
(installed nil 12 t)
|
||||
(synopsis guix-list-get-one-line 30 nil))
|
||||
:required '(package-id)
|
||||
:required '(id package-id)
|
||||
:sort-key '(name)
|
||||
:marks '((install . ?I)
|
||||
(upgrade . ?U)
|
||||
|
@ -784,15 +804,19 @@ The specification is suitable for `guix-process-output-actions'."
|
|||
"Describe outputs with IDS (list of output identifiers).
|
||||
See `guix-package-info-type'."
|
||||
(if (eq guix-package-info-type 'output)
|
||||
(apply #'guix-get-show-entries
|
||||
guix-profile 'info 'output 'id ids)
|
||||
(guix-buffer-get-display-entries
|
||||
'info 'output
|
||||
(cl-list* (guix-ui-current-profile) 'id ids)
|
||||
'add)
|
||||
(let ((pids (mapcar (lambda (oid)
|
||||
(car (guix-package-id-and-output-by-output-id
|
||||
oid)))
|
||||
ids)))
|
||||
(apply #'guix-get-show-entries
|
||||
guix-profile 'info 'package 'id
|
||||
(cl-remove-duplicates pids)))))
|
||||
(guix-buffer-get-display-entries
|
||||
'info 'package
|
||||
(cl-list* (guix-ui-current-profile)
|
||||
'id (cl-remove-duplicates pids))
|
||||
'add))))
|
||||
|
||||
(defun guix-output-list-edit ()
|
||||
"Go to the location of the current package."
|
||||
|
@ -837,13 +861,15 @@ VAL is a boolean value."
|
|||
(number (guix-entry-value entry 'number)))
|
||||
(if current
|
||||
(user-error "This generation is already the current one")
|
||||
(guix-switch-to-generation guix-profile number (current-buffer)))))
|
||||
(guix-switch-to-generation (guix-ui-current-profile)
|
||||
number (current-buffer)))))
|
||||
|
||||
(defun guix-generation-list-show-packages ()
|
||||
"List installed packages for the generation at point."
|
||||
(interactive)
|
||||
(guix-get-show-entries guix-profile 'list guix-package-list-type
|
||||
'generation (guix-list-current-id)))
|
||||
(guix-get-show-packages
|
||||
(guix-ui-current-profile)
|
||||
'generation (guix-list-current-id)))
|
||||
|
||||
(defun guix-generation-list-generations-to-compare ()
|
||||
"Return a sorted list of 2 marked generations for comparing."
|
||||
|
@ -858,9 +884,12 @@ If 2 generations are marked with \\[guix-list-mark], display
|
|||
outputs installed in the latest marked generation that were not
|
||||
installed in the other one."
|
||||
(interactive)
|
||||
(apply #'guix-get-show-entries
|
||||
guix-profile 'list 'output 'generation-diff
|
||||
(reverse (guix-generation-list-generations-to-compare))))
|
||||
(guix-buffer-get-display-entries
|
||||
'list 'output
|
||||
(cl-list* (guix-ui-current-profile)
|
||||
'generation-diff
|
||||
(reverse (guix-generation-list-generations-to-compare)))
|
||||
'add))
|
||||
|
||||
(defun guix-generation-list-show-removed-packages ()
|
||||
"List package outputs removed from the latest marked generation.
|
||||
|
@ -868,9 +897,12 @@ If 2 generations are marked with \\[guix-list-mark], display
|
|||
outputs not installed in the latest marked generation that were
|
||||
installed in the other one."
|
||||
(interactive)
|
||||
(apply #'guix-get-show-entries
|
||||
guix-profile 'list 'output 'generation-diff
|
||||
(guix-generation-list-generations-to-compare)))
|
||||
(guix-buffer-get-display-entries
|
||||
'list 'output
|
||||
(cl-list* (guix-ui-current-profile)
|
||||
'generation-diff
|
||||
(guix-generation-list-generations-to-compare))
|
||||
'add))
|
||||
|
||||
(defun guix-generation-list-compare (diff-fun gen-fun)
|
||||
"Run GEN-FUN on the 2 marked generations and run DIFF-FUN on the results."
|
||||
|
@ -938,7 +970,8 @@ With ARG, mark all generations for deletion."
|
|||
(let ((marked (guix-list-get-marked-id-list 'delete)))
|
||||
(or marked
|
||||
(user-error "No generations marked for deletion"))
|
||||
(guix-delete-generations guix-profile marked (current-buffer))))
|
||||
(guix-delete-generations (guix-ui-current-profile)
|
||||
marked (current-buffer))))
|
||||
|
||||
|
||||
(defvar guix-list-font-lock-keywords
|
||||
|
|
|
@ -26,7 +26,10 @@
|
|||
|
||||
(require 'cl-lib)
|
||||
(require 'guix-backend)
|
||||
(require 'guix-buffer)
|
||||
(require 'guix-guile)
|
||||
(require 'guix-utils)
|
||||
(require 'guix-messages)
|
||||
|
||||
(defgroup guix-ui nil
|
||||
"Settings for Guix package management.
|
||||
|
@ -41,10 +44,38 @@ generations in 'list' and 'info' buffers."
|
|||
map)
|
||||
"Parent keymap for Guix package/generation buffers.")
|
||||
|
||||
(guix-buffer-define-current-args-accessors
|
||||
"guix-ui-current" "profile" "search-type" "search-values")
|
||||
|
||||
(defun guix-ui-get-entries (profile entry-type search-type search-values
|
||||
&optional params)
|
||||
"Receive ENTRY-TYPE entries for PROFILE.
|
||||
Call an appropriate scheme procedure and return a list of entries.
|
||||
|
||||
ENTRY-TYPE should be one of the following symbols: `package',
|
||||
`output' or `generation'.
|
||||
|
||||
SEARCH-TYPE may be one of the following symbols:
|
||||
|
||||
- If ENTRY-TYPE is `package' or `output': `id', `name', `regexp',
|
||||
`all-available', `newest-available', `installed', `obsolete',
|
||||
`generation'.
|
||||
|
||||
- If ENTRY-TYPE is `generation': `id', `last', `all', `time'.
|
||||
|
||||
PARAMS is a list of parameters for receiving. If nil, get data
|
||||
with all available parameters."
|
||||
(guix-eval-read
|
||||
(guix-make-guile-expression
|
||||
'entries
|
||||
profile params entry-type search-type search-values)))
|
||||
|
||||
(defun guix-ui-list-describe (ids)
|
||||
"Describe 'ui' entries with IDS (list of identifiers)."
|
||||
(apply #'guix-get-show-entries
|
||||
guix-profile 'info guix-entry-type 'id ids))
|
||||
(guix-buffer-get-display-entries
|
||||
'info (guix-buffer-current-entry-type)
|
||||
(cl-list* (guix-ui-current-profile) 'id ids)
|
||||
'add))
|
||||
|
||||
|
||||
;;; Buffers and auto updating
|
||||
|
@ -161,7 +192,16 @@ Optional keywords:
|
|||
`guix-TYPE-required-params' variable.
|
||||
|
||||
The rest keyword arguments are passed to
|
||||
`guix-BUFFER-TYPE-define-interface' macro."
|
||||
`guix-BUFFER-TYPE-define-interface' macro.
|
||||
|
||||
Along with the mentioned definitions, this macro also defines:
|
||||
|
||||
- `guix-TYPE-mode-map' - keymap based on `guix-ui-map' and
|
||||
`guix-BUFFER-TYPE-mode-map'.
|
||||
|
||||
- `guix-TYPE-get-entries' - a wrapper around `guix-ui-get-entries'.
|
||||
|
||||
- `guix-TYPE-message' - a wrapper around `guix-result-message'."
|
||||
(declare (indent 2))
|
||||
(let* ((entry-type-str (symbol-name entry-type))
|
||||
(buffer-type-str (symbol-name buffer-type))
|
||||
|
@ -173,6 +213,10 @@ The rest keyword arguments are passed to
|
|||
buffer-type-str)))
|
||||
(required-var (intern (concat prefix "-required-params")))
|
||||
(buffer-name-fun (intern (concat prefix "-buffer-name")))
|
||||
(get-fun (intern (concat prefix "-get-entries")))
|
||||
(message-fun (intern (concat prefix "-message")))
|
||||
(displayed-fun (intern (format "guix-%s-displayed-params"
|
||||
buffer-type-str)))
|
||||
(definer (intern (format "guix-%s-define-interface"
|
||||
buffer-type-str))))
|
||||
(guix-keyword-args-let args
|
||||
|
@ -188,9 +232,13 @@ The rest keyword arguments are passed to
|
|||
|
||||
(defvar ,required-var ,required-val
|
||||
,(format "\
|
||||
List of the required '%s' parameters for '%s' buffer.
|
||||
These parameters are received along with the displayed parameters."
|
||||
entry-type-str buffer-type-str))
|
||||
List of the required '%s' parameters.
|
||||
These parameters are received by `%S'
|
||||
along with the displayed parameters.
|
||||
|
||||
Do not remove `id' from this list as it is required for
|
||||
identifying an entry."
|
||||
entry-type-str get-fun))
|
||||
|
||||
(defun ,buffer-name-fun (profile &rest _)
|
||||
,(format "\
|
||||
|
@ -199,7 +247,27 @@ See `guix-ui-buffer-name' for details."
|
|||
buffer-type-str entry-type-str)
|
||||
(guix-ui-buffer-name ,buffer-name-val profile))
|
||||
|
||||
(defun ,get-fun (profile search-type &rest search-values)
|
||||
,(format "\
|
||||
Receive '%s' entries for displaying them in '%s' buffer.
|
||||
See `guix-ui-get-entries' for details."
|
||||
entry-type-str buffer-type-str)
|
||||
(guix-ui-get-entries
|
||||
profile ',entry-type search-type search-values
|
||||
(cl-union ,required-var
|
||||
(,displayed-fun ',entry-type))))
|
||||
|
||||
(defun ,message-fun (entries profile search-type
|
||||
&rest search-values)
|
||||
,(format "\
|
||||
Display a message after showing '%s' entries."
|
||||
entry-type-str)
|
||||
(guix-result-message
|
||||
profile entries ',entry-type search-type search-values))
|
||||
|
||||
(,definer ,entry-type
|
||||
:get-entries-function ',get-fun
|
||||
:message-function ',message-fun
|
||||
:buffer-name ',buffer-name-fun
|
||||
,@%foreign-args)))))
|
||||
|
||||
|
|
|
@ -56,42 +56,39 @@ If nil, show a single package in the info buffer."
|
|||
(defvar guix-search-history nil
|
||||
"A history of minibuffer prompts.")
|
||||
|
||||
(defun guix-get-show-packages (profile search-type &rest search-vals)
|
||||
(defun guix-get-show-packages (profile search-type &rest search-values)
|
||||
"Search for packages and show results.
|
||||
|
||||
If PROFILE is nil, use `guix-current-profile'.
|
||||
|
||||
See `guix-get-entries' for the meaning of SEARCH-TYPE and
|
||||
SEARCH-VALS.
|
||||
See `guix-ui-get-entries' for the meaning of SEARCH-TYPE and
|
||||
SEARCH-VALUES.
|
||||
|
||||
Results are displayed in the list buffer, unless a single package
|
||||
is found and `guix-list-single-package' is nil."
|
||||
(or profile (setq profile guix-current-profile))
|
||||
(let ((packages (guix-get-entries profile guix-package-list-type
|
||||
search-type search-vals
|
||||
(guix-get-params-for-receiving
|
||||
'list guix-package-list-type))))
|
||||
(let* ((args (cl-list* (or profile guix-current-profile)
|
||||
search-type search-values))
|
||||
(entries (guix-buffer-get-entries
|
||||
'list guix-package-list-type args)))
|
||||
(if (or guix-list-single-package
|
||||
(cdr packages))
|
||||
(guix-set-buffer profile packages 'list guix-package-list-type
|
||||
search-type search-vals)
|
||||
(let ((packages (guix-get-entries profile guix-package-info-type
|
||||
search-type search-vals
|
||||
(guix-get-params-for-receiving
|
||||
'info guix-package-info-type))))
|
||||
(guix-set-buffer profile packages 'info guix-package-info-type
|
||||
search-type search-vals)))))
|
||||
(null entries)
|
||||
(cdr entries))
|
||||
(guix-buffer-display-entries
|
||||
entries 'list guix-package-list-type args 'add)
|
||||
(guix-buffer-get-display-entries
|
||||
'info guix-package-info-type args 'add))))
|
||||
|
||||
(defun guix-get-show-generations (profile search-type &rest search-vals)
|
||||
(defun guix-get-show-generations (profile search-type &rest search-values)
|
||||
"Search for generations and show results.
|
||||
|
||||
If PROFILE is nil, use `guix-current-profile'.
|
||||
|
||||
See `guix-get-entries' for the meaning of SEARCH-TYPE and
|
||||
SEARCH-VALS."
|
||||
(apply #'guix-get-show-entries
|
||||
(or profile guix-current-profile)
|
||||
'list 'generation search-type search-vals))
|
||||
See `guix-ui-get-entries' for the meaning of SEARCH-TYPE and
|
||||
SEARCH-VALUES."
|
||||
(let ((args (cl-list* (or profile guix-current-profile)
|
||||
search-type search-values)))
|
||||
(guix-buffer-get-display-entries
|
||||
'list 'generation args 'add)))
|
||||
|
||||
;;;###autoload
|
||||
(defun guix-search-by-name (name &optional profile)
|
||||
|
|
Loading…
Reference in New Issue