emacs: Improve interface for working with multiple profiles.

Suggested by David Thompson, Ludovic Courtès and Mathieu Lirzin.

* emacs/guix-base.el (guix-profile-prompt): New procedure.
  (guix-set-current-profile): Use it.
  (guix-buffer-name-simple, guix-buffer-name-default, guix-buffer-name): New
  procedures.
  (guix-buffer-name-function, guix-profile): New variables.
  (guix-set-vars, guix-get-entries, guix-get-show-entries, guix-set-buffer,
  guix-history-call, guix-process-package-actions,
  guix-continue-package-operation-p, guix-delete-generations,
  guix-switch-to-generation): Add 'profile' argument.
* emacs/guix.el (guix-get-show-packages, guix-get-show-generations,
  guix-search-by-name, guix-search-by-regexp, guix-installed-packages,
  guix-obsolete-packages, guix-all-available-packages,
  guix-newest-available-packages, guix-generations, guix-generations-by-time):
  Likewise.
  (guix-last-generations): New command.
* emacs/guix-info.el: Adjust for using 'profile' argument where needed.
* emacs/guix-list.el: Likewise.
* doc/emacs.texi (Emacs Commands): Document 'guix-last-generations' and using
  "C-u" for commands.
  (Emacs Buffer Names): Document 'guix-buffer-name-function'.
This commit is contained in:
Alex Kost 2014-10-17 22:21:32 +04:00
parent 7c3c0374de
commit 23459fa59b
5 changed files with 272 additions and 136 deletions

View File

@ -76,19 +76,26 @@ can be displayed in a ``list'' or ``info'' buffer.
@node Emacs Commands @node Emacs Commands
@subsubsection Commands @subsubsection Commands
You may use the following commands to display packages and generations: All commands for displaying packages and generations use the current
profile, which can be changed with
@kbd{M-x@tie{}guix-set-current-profile}. Alternatively, if you call any
of these commands with prefix argument (@kbd{C-u}), you will be prompted
for a profile just for that command.
Commands for displaying packages:
@table @kbd @table @kbd
@item M-x guix-all-available-packages @item M-x guix-all-available-packages
@itemx M-x guix-newest-available-packages @itemx M-x guix-newest-available-packages
Display all/newest available packages. Display all/newest available packages.
@item M-x guix-installed-packages @item M-x guix-installed-packages
Display all packages installed in the current profile. Display all installed packages.
@item M-x guix-obsolete-packages @item M-x guix-obsolete-packages
Display obsolete packages (the packages that are installed in the Display obsolete packages (the packages that are installed in a profile
current profile but cannot be found among available packages). but cannot be found among available packages).
@item M-x guix-search-by-name @item M-x guix-search-by-name
Display package(s) with the specified name. Display package(s) with the specified name.
@ -98,29 +105,33 @@ Search for packages by a specified regexp. By default ``name'',
``synopsis'' and ``description'' of the packages will be searched. This ``synopsis'' and ``description'' of the packages will be searched. This
can be changed by modifying @code{guix-search-params} variable. can be changed by modifying @code{guix-search-params} variable.
@item M-x guix-generations
List generations for the current profile. With numeric prefix, show so
many last generations.
@item M-x guix-generations-by-time
List generations matching time period. You'll be prompted for the
period using Org mode time prompt based on Emacs calendar (@pxref{The
date/time prompt,,, org, Org Mode Manual}).
@end table @end table
By default commands for displaying packages display each output on a By default, these commands display each output on a separate line. If
separate line. If you prefer to see a list of packages---i.e., a list you prefer to see a list of packages---i.e., a list with a package per
with a package per line, use the following setting: line, use the following setting:
@example @example
(setq guix-package-list-type 'package) (setq guix-package-list-type 'package)
@end example @end example
It is possible to change the currently used profile with Commands for displaying generations:
@kbd{M-x@tie{}guix-set-current-profile}. This has the same effect as
specifying @code{--profile} option for @command{guix package} @table @kbd
(@pxref{Invoking guix package}).
@item M-x guix-generations
List all the generations.
@item M-x guix-last-generations
List the @var{N} last generations. You will be prompted for the number
of generations.
@item M-x guix-generations-by-time
List generations matching time period. You will be prompted for the
period using Org mode time prompt based on Emacs calendar (@pxref{The
date/time prompt,,, org, Org Mode Manual}).
@end table
@node Emacs General info @node Emacs General info
@subsubsection General information @subsubsection General information
@ -304,10 +315,13 @@ changed with the following variables:
@item guix-generation-info-buffer-name @item guix-generation-info-buffer-name
@item guix-repl-buffer-name @item guix-repl-buffer-name
@item guix-internal-repl-buffer-name @item guix-internal-repl-buffer-name
@item guix-temp-buffer-name
@end table @end table
For example if you want to display all types of results in a single By default, the name of a profile is also displayed in a ``list'' or
``info'' buffer name. To change this behavior, use
@code{guix-buffer-name-function} variable.
For example, if you want to display all types of results in a single
buffer (in such case you will probably use a history (@kbd{l}/@kbd{r}) buffer (in such case you will probably use a history (@kbd{l}/@kbd{r})
extensively), you may do it like this: extensively), you may do it like this:
@ -319,7 +333,8 @@ extensively), you may do it like this:
guix-generation-list-buffer-name name guix-generation-list-buffer-name name
guix-package-info-buffer-name name guix-package-info-buffer-name name
guix-output-info-buffer-name name guix-output-info-buffer-name name
guix-generation-info-buffer-name name)) guix-generation-info-buffer-name name
guix-buffer-name-function #'guix-buffer-name-simple))
@end example @end example
@node Emacs Keymaps @node Emacs Keymaps

View File

@ -48,6 +48,18 @@
(defvar guix-current-profile guix-default-profile (defvar guix-current-profile guix-default-profile
"Current profile.") "Current profile.")
(defun guix-profile-prompt (&optional default)
"Prompt for profile and return it.
Use DEFAULT as a start directory. If it is nil, use
`guix-current-profile'."
(let* ((path (read-file-name "Profile: "
(file-name-directory
(or default guix-current-profile))))
(path (directory-file-name (expand-file-name path))))
(if (string= path guix-user-profile)
guix-default-profile
path)))
(defun guix-set-current-profile (path) (defun guix-set-current-profile (path)
"Set `guix-current-profile' to PATH. "Set `guix-current-profile' to PATH.
Interactively, prompt for PATH. With prefix, use Interactively, prompt for PATH. With prefix, use
@ -55,15 +67,10 @@ Interactively, prompt for PATH. With prefix, use
(interactive (interactive
(list (if current-prefix-arg (list (if current-prefix-arg
guix-default-profile guix-default-profile
(read-file-name "Set profile: " (guix-profile-prompt))))
(file-name-directory guix-current-profile))))) (setq guix-current-profile path)
(let ((path (directory-file-name (expand-file-name path))))
(setq guix-current-profile
(if (string= path guix-user-profile)
guix-default-profile
path))
(message "Current profile has been set to '%s'." (message "Current profile has been set to '%s'."
guix-current-profile))) guix-current-profile))
;;; Parameters of the entries ;;; Parameters of the entries
@ -209,6 +216,56 @@ If `all', update all Guix buffers (not recommended)."
(const :tag "Update all Guix buffers" all)) (const :tag "Update all Guix buffers" all))
:group 'guix) :group 'guix)
(defcustom guix-buffer-name-function #'guix-buffer-name-default
"Function used to define name of a buffer for displaying information.
The function is called with 4 arguments: PROFILE, BUFFER-TYPE,
ENTRY-TYPE, SEARCH-TYPE. See `guix-get-entries' for the meaning
of the arguments."
:type '(choice (function-item guix-buffer-name-default)
(function-item guix-buffer-name-simple)
(function :tag "Other function"))
:group 'guix)
(defun guix-buffer-name-simple (_profile buffer-type entry-type
&optional _search-type)
"Return name of a buffer used for displaying information.
The name is defined by `guix-ENTRY-TYPE-BUFFER-TYPE-buffer-name'
variable."
(symbol-value
(guix-get-symbol "buffer-name" buffer-type entry-type)))
(defun guix-buffer-name-default (profile buffer-type entry-type
&optional _search-type)
"Return name of a buffer used for displaying information.
The name is almost the same as the one defined by
`guix-buffer-name-simple' except the PROFILE name is added to it."
(let ((simple-name (guix-buffer-name-simple
profile buffer-type entry-type))
(profile-name (file-name-base (directory-file-name profile)))
(re (rx string-start
(group (? "*"))
(group (*? any))
(group (? "*"))
string-end)))
(or (string-match re simple-name)
(error "Unexpected error in defining guix buffer name"))
(let ((first* (match-string 1 simple-name))
(name-body (match-string 2 simple-name))
(last* (match-string 3 simple-name)))
;; Handle the case when buffer name is wrapped by '*'.
(if (and (string= "*" first*)
(string= "*" last*))
(concat "*" name-body ": " profile-name "*")
(concat simple-name ": " profile-name)))))
(defun guix-buffer-name (profile buffer-type entry-type search-type)
"Return name of a buffer used for displaying information.
See `guix-buffer-name-function' for details."
(let ((fun (if (functionp guix-buffer-name-function)
guix-buffer-name-function
#'guix-buffer-name-default)))
(funcall fun profile buffer-type entry-type search-type)))
(defun guix-switch-to-buffer (buffer) (defun guix-switch-to-buffer (buffer)
"Switch to a 'list' or 'info' BUFFER." "Switch to a 'list' or 'info' BUFFER."
(pop-to-buffer buffer (pop-to-buffer buffer
@ -246,6 +303,10 @@ See `guix-update-after-operation' for details."
;;; Common definitions for buffer types ;;; Common definitions for buffer types
(defvar-local guix-profile nil
"Profile used for the current buffer.")
(put 'guix-profile 'permanent-local t)
(defvar-local guix-entries nil (defvar-local guix-entries nil
"List of the currently displayed entries. "List of the currently displayed entries.
Each element of the list is alist with entry info of the Each element of the list is alist with entry info of the
@ -273,9 +334,12 @@ VAL is a value of this parameter.")
"Values of the current search.") "Values of the current search.")
(put 'guix-search-vals 'permanent-local t) (put 'guix-search-vals 'permanent-local t)
(defsubst guix-set-vars (entries buffer-type entry-type (defsubst guix-set-vars (profile entries buffer-type entry-type
search-type search-vals) search-type search-vals)
(setq guix-entries entries "Set local variables for the current Guix buffer."
(setq default-directory profile
guix-profile profile
guix-entries entries
guix-buffer-type buffer-type guix-buffer-type buffer-type
guix-entry-type entry-type guix-entry-type entry-type
guix-search-type search-type guix-search-type search-type
@ -416,7 +480,7 @@ information)."
(const :tag "Display outputs" output)) (const :tag "Display outputs" output))
:group 'guix) :group 'guix)
(defun guix-get-entries (entry-type search-type search-vals (defun guix-get-entries (profile entry-type search-type search-vals
&optional params) &optional params)
"Search for entries of ENTRY-TYPE. "Search for entries of ENTRY-TYPE.
@ -432,26 +496,25 @@ SEARCH-TYPE may be one of the following symbols:
`all-available', `newest-available', `installed', `obsolete', `all-available', `newest-available', `installed', `obsolete',
`generation'. `generation'.
- If ENTRY-TYPE is `generation': `id', `last', `all'. - If ENTRY-TYPE is `generation': `id', `last', `all', `time'.
PARAMS is a list of parameters for receiving. If nil, get PARAMS is a list of parameters for receiving. If nil, get
information with all available parameters." information with all available parameters."
(guix-eval-read (guix-make-guile-expression (guix-eval-read (guix-make-guile-expression
'entries 'entries
guix-current-profile params profile params entry-type search-type search-vals)))
entry-type search-type search-vals)))
(defun guix-get-show-entries (buffer-type entry-type search-type (defun guix-get-show-entries (profile buffer-type entry-type search-type
&rest search-vals) &rest search-vals)
"Search for ENTRY-TYPE entries and show results in BUFFER-TYPE buffer. "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." See `guix-get-entries' for the meaning of SEARCH-TYPE and SEARCH-VALS."
(let ((entries (guix-get-entries entry-type search-type search-vals (let ((entries (guix-get-entries profile entry-type search-type search-vals
(guix-get-params-for-receiving (guix-get-params-for-receiving
buffer-type entry-type)))) buffer-type entry-type))))
(guix-set-buffer entries buffer-type entry-type (guix-set-buffer profile entries buffer-type entry-type
search-type search-vals))) search-type search-vals)))
(defun guix-set-buffer (entries buffer-type entry-type search-type (defun guix-set-buffer (profile entries buffer-type entry-type search-type
search-vals &optional history-replace no-display) search-vals &optional history-replace no-display)
"Set up BUFFER-TYPE buffer for displaying ENTRY-TYPE ENTRIES. "Set up BUFFER-TYPE buffer for displaying ENTRY-TYPE ENTRIES.
@ -465,16 +528,16 @@ otherwise add the new one.
If NO-DISPLAY is non-nil, do not switch to the buffer." If NO-DISPLAY is non-nil, do not switch to the buffer."
(when entries (when entries
(let ((buf (if (eq major-mode (guix-get-symbol (let ((buf (if (and (eq major-mode
"mode" buffer-type entry-type)) (guix-get-symbol "mode" buffer-type entry-type))
(equal guix-profile profile))
(current-buffer) (current-buffer)
(get-buffer-create (get-buffer-create
(symbol-value (guix-buffer-name profile buffer-type
(guix-get-symbol "buffer-name" entry-type search-type)))))
buffer-type entry-type))))))
(with-current-buffer buf (with-current-buffer buf
(guix-show-entries entries buffer-type entry-type) (guix-show-entries entries buffer-type entry-type)
(guix-set-vars entries buffer-type entry-type (guix-set-vars profile entries buffer-type entry-type
search-type search-vals) search-type search-vals)
(funcall (if history-replace (funcall (if history-replace
#'guix-history-replace #'guix-history-replace
@ -494,18 +557,18 @@ If NO-DISPLAY is non-nil, do not switch to the buffer."
entries entry-type) entries entry-type)
(goto-char (point-min)))) (goto-char (point-min))))
(defun guix-history-call (entries buffer-type entry-type (defun guix-history-call (profile entries buffer-type entry-type
search-type search-vals) search-type search-vals)
"Function called for moving by history." "Function called for moving by history."
(guix-show-entries entries buffer-type entry-type) (guix-show-entries entries buffer-type entry-type)
(guix-set-vars entries buffer-type entry-type (guix-set-vars profile entries buffer-type entry-type
search-type search-vals) search-type search-vals)
(guix-result-message entries entry-type search-type search-vals)) (guix-result-message entries entry-type search-type search-vals))
(defun guix-make-history-item () (defun guix-make-history-item ()
"Make and return a history item for the current buffer." "Make and return a history item for the current buffer."
(list #'guix-history-call (list #'guix-history-call
guix-entries guix-buffer-type guix-entry-type guix-profile guix-entries guix-buffer-type guix-entry-type
guix-search-type guix-search-vals)) guix-search-type guix-search-vals))
(defun guix-get-params-for-receiving (buffer-type entry-type) (defun guix-get-params-for-receiving (buffer-type entry-type)
@ -529,10 +592,11 @@ See `revert-buffer' for the meaning of NOCONFIRM."
guix-buffer-type guix-entry-type)) guix-buffer-type guix-entry-type))
(y-or-n-p "Update current information? ")) (y-or-n-p "Update current information? "))
(let ((entries (guix-get-entries (let ((entries (guix-get-entries
guix-entry-type guix-search-type guix-search-vals guix-profile guix-entry-type
guix-search-type guix-search-vals
(guix-get-params-for-receiving guix-buffer-type (guix-get-params-for-receiving guix-buffer-type
guix-entry-type)))) guix-entry-type))))
(guix-set-buffer entries guix-buffer-type guix-entry-type (guix-set-buffer guix-profile entries guix-buffer-type guix-entry-type
guix-search-type guix-search-vals t t)))) guix-search-type guix-search-vals t t))))
(defun guix-redisplay-buffer () (defun guix-redisplay-buffer ()
@ -719,8 +783,9 @@ VARIABLE is a name of an option variable.")
guix-operation-option-true-string guix-operation-option-true-string
guix-operation-option-false-string)) guix-operation-option-false-string))
(defun guix-process-package-actions (actions &optional operation-buffer) (defun guix-process-package-actions (profile actions
"Process package ACTIONS. &optional operation-buffer)
"Process package ACTIONS on PROFILE.
Each action is a list of the form: Each action is a list of the form:
(ACTION-TYPE PACKAGE-SPEC ...) (ACTION-TYPE PACKAGE-SPEC ...)
@ -738,23 +803,25 @@ PACKAGE-SPEC should have the following form: (ID [OUTPUT] ...)."
((remove delete) (setq remove (append remove specs)))))) ((remove delete) (setq remove (append remove specs))))))
actions) actions)
(when (guix-continue-package-operation-p (when (guix-continue-package-operation-p
profile
:install install :upgrade upgrade :remove remove) :install install :upgrade upgrade :remove remove)
(guix-eval-in-repl (guix-eval-in-repl
(guix-make-guile-expression (guix-make-guile-expression
'process-package-actions guix-current-profile 'process-package-actions profile
:install install :upgrade upgrade :remove remove :install install :upgrade upgrade :remove remove
:use-substitutes? (or guix-use-substitutes 'f) :use-substitutes? (or guix-use-substitutes 'f)
:dry-run? (or guix-dry-run 'f)) :dry-run? (or guix-dry-run 'f))
(and (not guix-dry-run) operation-buffer))))) (and (not guix-dry-run) operation-buffer)))))
(cl-defun guix-continue-package-operation-p (&key install upgrade remove) (cl-defun guix-continue-package-operation-p (profile
&key install upgrade remove)
"Return non-nil if a package operation should be continued. "Return non-nil if a package operation should be continued.
Ask a user if needed (see `guix-operation-confirm'). Ask a user if needed (see `guix-operation-confirm').
INSTALL, UPGRADE, REMOVE are 'package action specifications'. INSTALL, UPGRADE, REMOVE are 'package action specifications'.
See `guix-process-package-actions' for details." See `guix-process-package-actions' for details."
(or (null guix-operation-confirm) (or (null guix-operation-confirm)
(let* ((entries (guix-get-entries (let* ((entries (guix-get-entries
'package 'id profile 'package 'id
(append (mapcar #'car install) (append (mapcar #'car install)
(mapcar #'car upgrade) (mapcar #'car upgrade)
(mapcar #'car remove)) (mapcar #'car remove))
@ -768,6 +835,7 @@ See `guix-process-package-actions' for details."
(setq-local cursor-type nil) (setq-local cursor-type nil)
(setq buffer-read-only nil) (setq buffer-read-only nil)
(erase-buffer) (erase-buffer)
(insert "Profile: " profile "\n\n")
(guix-insert-package-strings install-strings "install") (guix-insert-package-strings install-strings "install")
(guix-insert-package-strings upgrade-strings "upgrade") (guix-insert-package-strings upgrade-strings "upgrade")
(guix-insert-package-strings remove-strings "remove") (guix-insert-package-strings remove-strings "remove")
@ -861,29 +929,32 @@ Return non-nil, if the operation should be continued; nil otherwise."
guix-operation-option-separator))) guix-operation-option-separator)))
(force-mode-line-update)) (force-mode-line-update))
(defun guix-delete-generations (generations &optional operation-buffer) (defun guix-delete-generations (profile generations
"Delete GENERATIONS. &optional operation-buffer)
"Delete GENERATIONS from PROFILE.
Each element from GENERATIONS is a generation number." Each element from GENERATIONS is a generation number."
(when (or (not guix-operation-confirm) (when (or (not guix-operation-confirm)
(y-or-n-p (y-or-n-p
(let ((count (length generations))) (let ((count (length generations)))
(if (> count 1) (if (> count 1)
(format "Delete %d generations? " count) (format "Delete %d generations from profile '%s'? "
(format "Delete generation number %d? " count profile)
(car generations)))))) (format "Delete generation %d from profile '%s'? "
(car generations) profile)))))
(guix-eval-in-repl (guix-eval-in-repl
(guix-make-guile-expression (guix-make-guile-expression
'delete-generations* guix-current-profile generations) 'delete-generations* profile generations)
operation-buffer))) operation-buffer)))
(defun guix-switch-to-generation (generation &optional operation-buffer) (defun guix-switch-to-generation (profile generation
"Switch `guix-current-profile' to GENERATION number." &optional operation-buffer)
"Switch PROFILE to GENERATION."
(when (or (not guix-operation-confirm) (when (or (not guix-operation-confirm)
(y-or-n-p (format "Switch current profile to generation %d? " (y-or-n-p (format "Switch profile '%s' to generation %d? "
generation))) profile generation)))
(guix-eval-in-repl (guix-eval-in-repl
(guix-make-guile-expression (guix-make-guile-expression
'switch-to-generation guix-current-profile generation) 'switch-to-generation profile generation)
operation-buffer))) operation-buffer)))
(provide 'guix-base) (provide 'guix-base)

View File

@ -334,8 +334,8 @@ VAL is a list, call the function on each element of this list."
'face 'guix-package-info-name-button 'face 'guix-package-info-name-button
'help-echo "Describe this package" 'help-echo "Describe this package"
'action (lambda (btn) 'action (lambda (btn)
(guix-get-show-entries 'info guix-package-info-type 'name (guix-get-show-entries guix-profile 'info guix-package-info-type
(button-label btn)))) 'name (button-label btn))))
(defun guix-info-insert-action-button (label action &optional message (defun guix-info-insert-action-button (label action &optional message
&rest properties) &rest properties)
@ -558,6 +558,7 @@ ENTRY is an alist with package info."
type-str type-str
(lambda (btn) (lambda (btn)
(guix-process-package-actions (guix-process-package-actions
guix-profile
`((,(button-get btn 'action-type) (,(button-get btn 'id) `((,(button-get btn 'action-type) (,(button-get btn 'id)
,(button-get btn 'output)))) ,(button-get btn 'output))))
(current-buffer))) (current-buffer)))
@ -631,15 +632,15 @@ ENTRY is an alist with package info."
(guix-info-insert-action-button (guix-info-insert-action-button
"Packages" "Packages"
(lambda (btn) (lambda (btn)
(guix-get-show-entries 'list guix-package-list-type 'generation (guix-get-show-entries guix-profile 'list guix-package-list-type
(button-get btn 'number))) 'generation (button-get btn 'number)))
"Show installed packages for this generation" "Show installed packages for this generation"
'number number) 'number number)
(guix-info-insert-indent) (guix-info-insert-indent)
(guix-info-insert-action-button (guix-info-insert-action-button
"Delete" "Delete"
(lambda (btn) (lambda (btn)
(guix-delete-generations (list (button-get btn 'number)) (guix-delete-generations guix-profile (list (button-get btn 'number))
(current-buffer))) (current-buffer)))
"Delete this generation" "Delete this generation"
'number number)) 'number number))
@ -653,7 +654,7 @@ ENTRY is an alist with package info."
(guix-info-insert-action-button (guix-info-insert-action-button
"Switch" "Switch"
(lambda (btn) (lambda (btn)
(guix-switch-to-generation (button-get btn 'number) (guix-switch-to-generation guix-profile (button-get btn 'number)
(current-buffer))) (current-buffer)))
"Switch to this generation (make it the current one)" "Switch to this generation (make it the current one)"
'number (guix-get-key-val entry 'number)))) 'number (guix-get-key-val entry 'number))))

View File

@ -441,7 +441,8 @@ This macro defines the following functions:
(when (or (<= count guix-list-describe-warning-count) (when (or (<= count guix-list-describe-warning-count)
(y-or-n-p (format "Do you really want to describe %d entries? " (y-or-n-p (format "Do you really want to describe %d entries? "
count))) count)))
(apply #'guix-get-show-entries 'info entry-type 'id ids)))) (apply #'guix-get-show-entries
guix-profile 'info entry-type 'id ids))))
(defun guix-list-describe (&optional arg) (defun guix-list-describe (&optional arg)
"Describe entries marked with a general mark. "Describe entries marked with a general mark.
@ -617,7 +618,8 @@ FUN should accept action-type as argument."
(let ((actions (delq nil (let ((actions (delq nil
(mapcar fun '(install delete upgrade))))) (mapcar fun '(install delete upgrade)))))
(if actions (if actions
(guix-process-package-actions actions (current-buffer)) (guix-process-package-actions
guix-profile actions (current-buffer))
(user-error "No operations specified")))) (user-error "No operations specified"))))
(defun guix-package-list-execute () (defun guix-package-list-execute ()
@ -751,13 +753,13 @@ VAL is a boolean value."
(number (guix-get-key-val entry 'number))) (number (guix-get-key-val entry 'number)))
(if current (if current
(user-error "This generation is already the current one") (user-error "This generation is already the current one")
(guix-switch-to-generation number (current-buffer))))) (guix-switch-to-generation guix-profile number (current-buffer)))))
(defun guix-generation-list-show-packages () (defun guix-generation-list-show-packages ()
"List installed packages for the generation at point." "List installed packages for the generation at point."
(interactive) (interactive)
(guix-get-show-entries 'list guix-package-list-type 'generation (guix-get-show-entries guix-profile 'list guix-package-list-type
(guix-list-current-id))) 'generation (guix-list-current-id)))
(defun guix-generation-list-mark-delete (&optional arg) (defun guix-generation-list-mark-delete (&optional arg)
"Mark the current generation for deletion and move to the next line. "Mark the current generation for deletion and move to the next line.
@ -773,7 +775,7 @@ With ARG, mark all generations for deletion."
(let ((marked (guix-list-get-marked-id-list 'delete))) (let ((marked (guix-list-get-marked-id-list 'delete)))
(or marked (or marked
(user-error "No generations marked for deletion")) (user-error "No generations marked for deletion"))
(guix-delete-generations marked (current-buffer)))) (guix-delete-generations guix-profile marked (current-buffer))))
(provide 'guix-list) (provide 'guix-list)

View File

@ -50,99 +50,146 @@ If nil, show a single package in the info buffer."
(defvar guix-search-history nil (defvar guix-search-history nil
"A history of minibuffer prompts.") "A history of minibuffer prompts.")
(defun guix-get-show-packages (search-type &rest search-vals) (defun guix-get-show-packages (profile search-type &rest search-vals)
"Search for packages and show results. "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 See `guix-get-entries' for the meaning of SEARCH-TYPE and
SEARCH-VALS. SEARCH-VALS.
Results are displayed in the list buffer, unless a single package Results are displayed in the list buffer, unless a single package
is found and `guix-list-single-package' is nil." is found and `guix-list-single-package' is nil."
(let ((packages (guix-get-entries guix-package-list-type (or profile (setq profile guix-current-profile))
(let ((packages (guix-get-entries profile guix-package-list-type
search-type search-vals search-type search-vals
(guix-get-params-for-receiving (guix-get-params-for-receiving
'list guix-package-list-type)))) 'list guix-package-list-type))))
(if (or guix-list-single-package (if (or guix-list-single-package
(cdr packages)) (cdr packages))
(guix-set-buffer packages 'list guix-package-list-type (guix-set-buffer profile packages 'list guix-package-list-type
search-type search-vals) search-type search-vals)
(let ((packages (guix-get-entries guix-package-info-type (let ((packages (guix-get-entries profile guix-package-info-type
search-type search-vals search-type search-vals
(guix-get-params-for-receiving (guix-get-params-for-receiving
'info guix-package-info-type)))) 'info guix-package-info-type))))
(guix-set-buffer packages 'info guix-package-info-type (guix-set-buffer profile packages 'info guix-package-info-type
search-type search-vals))))) search-type search-vals)))))
(defun guix-get-show-generations (search-type &rest search-vals) (defun guix-get-show-generations (profile search-type &rest search-vals)
"Search for generations and show results." "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 (apply #'guix-get-show-entries
(or profile guix-current-profile)
'list 'generation search-type search-vals)) 'list 'generation search-type search-vals))
;;;###autoload ;;;###autoload
(defun guix-search-by-name (name) (defun guix-search-by-name (name &optional profile)
"Search for Guix packages by NAME. "Search for Guix packages by NAME.
NAME is a string with name specification. It may optionally contain NAME is a string with name specification. It may optionally contain
a version number. Examples: \"guile\", \"guile-2.0.11\"." a version number. Examples: \"guile\", \"guile-2.0.11\".
If PROFILE is nil, use `guix-current-profile'.
Interactively with prefix, prompt for PROFILE."
(interactive (interactive
(list (read-string "Package name: " nil 'guix-search-history))) (list (read-string "Package name: " nil 'guix-search-history)
(guix-get-show-packages 'name name)) (and current-prefix-arg
(guix-profile-prompt))))
(guix-get-show-packages profile 'name name))
;;;###autoload ;;;###autoload
(defun guix-search-by-regexp (regexp &rest params) (defun guix-search-by-regexp (regexp &optional params profile)
"Search for Guix packages by REGEXP. "Search for Guix packages by REGEXP.
PARAMS are package parameters that should be searched. PARAMS are package parameters that should be searched.
If PARAMS are not specified, use `guix-search-params'." If PARAMS are not specified, use `guix-search-params'.
If PROFILE is nil, use `guix-current-profile'.
Interactively with prefix, prompt for PROFILE."
(interactive (interactive
(list (read-string "Regexp: " nil 'guix-search-history))) (list (read-regexp "Regexp: " nil 'guix-search-history)
(or params (setq params guix-search-params)) nil
(guix-get-show-packages 'regexp regexp params)) (and current-prefix-arg
(guix-profile-prompt))))
(guix-get-show-packages profile 'regexp regexp
(or params guix-search-params)))
;;;###autoload ;;;###autoload
(defun guix-installed-packages () (defun guix-installed-packages (&optional profile)
"Display information about installed Guix packages." "Display information about installed Guix packages.
(interactive) If PROFILE is nil, use `guix-current-profile'.
(guix-get-show-packages 'installed)) Interactively with prefix, prompt for PROFILE."
(interactive
(list (and current-prefix-arg
(guix-profile-prompt))))
(guix-get-show-packages profile 'installed))
;;;###autoload ;;;###autoload
(defun guix-obsolete-packages () (defun guix-obsolete-packages (&optional profile)
"Display information about obsolete Guix packages." "Display information about obsolete Guix packages.
(interactive) If PROFILE is nil, use `guix-current-profile'.
(guix-get-show-packages 'obsolete)) Interactively with prefix, prompt for PROFILE."
(interactive
(list (and current-prefix-arg
(guix-profile-prompt))))
(guix-get-show-packages profile 'obsolete))
;;;###autoload ;;;###autoload
(defun guix-all-available-packages () (defun guix-all-available-packages (&optional profile)
"Display information about all available Guix packages." "Display information about all available Guix packages.
(interactive) If PROFILE is nil, use `guix-current-profile'.
(guix-get-show-packages 'all-available)) Interactively with prefix, prompt for PROFILE."
(interactive
(list (and current-prefix-arg
(guix-profile-prompt))))
(guix-get-show-packages profile 'all-available))
;;;###autoload ;;;###autoload
(defun guix-newest-available-packages () (defun guix-newest-available-packages (&optional profile)
"Display information about the newest available Guix packages." "Display information about the newest available Guix packages.
(interactive) If PROFILE is nil, use `guix-current-profile'.
(guix-get-show-packages 'newest-available)) Interactively with prefix, prompt for PROFILE."
(interactive
(list (and current-prefix-arg
(guix-profile-prompt))))
(guix-get-show-packages profile 'newest-available))
;;;###autoload ;;;###autoload
(defun guix-generations (&optional number) (defun guix-generations (&optional profile)
"Display information about all generations.
If PROFILE is nil, use `guix-current-profile'.
Interactively with prefix, prompt for PROFILE."
(interactive
(list (and current-prefix-arg
(guix-profile-prompt))))
(guix-get-show-generations profile 'all))
;;;###autoload
(defun guix-last-generations (number &optional profile)
"Display information about last NUMBER generations. "Display information about last NUMBER generations.
If NUMBER is nil, display all generations. If PROFILE is nil, use `guix-current-profile'.
Interactively with prefix, prompt for PROFILE."
Generations can be displayed in a list or info buffers depending (interactive
on `guix-show-generations-function'. (list (read-number "The number of last generations: ")
(and current-prefix-arg
Interactively, NUMBER is defined by a numeric prefix." (guix-profile-prompt))))
(interactive "P") (guix-get-show-generations profile 'last number))
(if (numberp number)
(guix-get-show-generations 'last number)
(guix-get-show-generations 'all)))
;;;###autoload ;;;###autoload
(defun guix-generations-by-time (from to) (defun guix-generations-by-time (from to &optional profile)
"Display information about generations created between FROM and TO. "Display information about generations created between FROM and TO.
FROM and TO should be time values." FROM and TO should be time values.
If PROFILE is nil, use `guix-current-profile'.
Interactively with prefix, prompt for PROFILE."
(interactive (interactive
(list (guix-read-date "Find generations (from): ") (list (guix-read-date "Find generations (from): ")
(guix-read-date "Find generations (to): "))) (guix-read-date "Find generations (to): ")
(guix-get-show-generations 'time (and current-prefix-arg
(guix-profile-prompt))))
(guix-get-show-generations profile 'time
(float-time from) (float-time from)
(float-time to))) (float-time to)))