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:
parent
7c3c0374de
commit
23459fa59b
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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))))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
141
emacs/guix.el
141
emacs/guix.el
|
@ -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)))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue