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
					
				
					 5 changed files with 272 additions and 136 deletions
				
			
		|  | @ -76,19 +76,26 @@ can be displayed in a ``list'' or ``info'' buffer. | |||
| @node Emacs 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 | ||||
| 
 | ||||
| @item M-x guix-all-available-packages | ||||
| @itemx M-x guix-newest-available-packages | ||||
| Display all/newest available 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 | ||||
| Display obsolete packages (the packages that are installed in the | ||||
| current profile but cannot be found among available packages). | ||||
| Display obsolete packages (the packages that are installed in a profile | ||||
| but cannot be found among available packages). | ||||
| 
 | ||||
| @item M-x guix-search-by-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 | ||||
| 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 | ||||
| 
 | ||||
| By default commands for displaying packages display each output on a | ||||
| separate line.  If you prefer to see a list of packages---i.e., a list | ||||
| with a package per line, use the following setting: | ||||
| By default, these commands display each output on a separate line.  If | ||||
| you prefer to see a list of packages---i.e., a list with a package per | ||||
| line, use the following setting: | ||||
| 
 | ||||
| @example | ||||
| (setq guix-package-list-type 'package) | ||||
| @end example | ||||
| 
 | ||||
| It is possible to change the currently used profile with | ||||
| @kbd{M-x@tie{}guix-set-current-profile}.  This has the same effect as | ||||
| specifying @code{--profile} option for @command{guix package} | ||||
| (@pxref{Invoking guix package}). | ||||
| Commands for displaying generations: | ||||
| 
 | ||||
| @table @kbd | ||||
| 
 | ||||
| @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 | ||||
| @subsubsection General information | ||||
|  | @ -304,10 +315,13 @@ changed with the following variables: | |||
| @item guix-generation-info-buffer-name | ||||
| @item guix-repl-buffer-name | ||||
| @item guix-internal-repl-buffer-name | ||||
| @item guix-temp-buffer-name | ||||
| @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}) | ||||
| 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-package-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 | ||||
| 
 | ||||
| @node Emacs Keymaps | ||||
|  |  | |||
|  | @ -48,6 +48,18 @@ | |||
| (defvar guix-current-profile guix-default-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) | ||||
|   "Set `guix-current-profile' to PATH. | ||||
| Interactively, prompt for PATH.  With prefix, use | ||||
|  | @ -55,15 +67,10 @@ Interactively, prompt for PATH.  With prefix, use | |||
|   (interactive | ||||
|    (list (if current-prefix-arg | ||||
|              guix-default-profile | ||||
|            (read-file-name "Set profile: " | ||||
|                            (file-name-directory guix-current-profile))))) | ||||
|   (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'." | ||||
|              guix-current-profile))) | ||||
|            (guix-profile-prompt)))) | ||||
|   (setq guix-current-profile path) | ||||
|   (message "Current profile has been set to '%s'." | ||||
|            guix-current-profile)) | ||||
| 
 | ||||
|  | ||||
| ;;; Parameters of the entries | ||||
|  | @ -209,6 +216,56 @@ If `all', update all Guix buffers (not recommended)." | |||
|                  (const :tag "Update all Guix buffers" all)) | ||||
|   :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) | ||||
|   "Switch to a 'list' or 'info' BUFFER." | ||||
|   (pop-to-buffer buffer | ||||
|  | @ -246,6 +303,10 @@ See `guix-update-after-operation' for details." | |||
|  | ||||
| ;;; 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 | ||||
|   "List of the currently displayed entries. | ||||
| Each element of the list is alist with entry info of the | ||||
|  | @ -273,13 +334,16 @@ VAL is a value of this parameter.") | |||
|   "Values of the current search.") | ||||
| (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) | ||||
|   (setq guix-entries     entries | ||||
|         guix-buffer-type buffer-type | ||||
|         guix-entry-type  entry-type | ||||
|         guix-search-type search-type | ||||
|         guix-search-vals 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-" | ||||
|  | @ -416,7 +480,7 @@ information)." | |||
|                  (const :tag "Display outputs" output)) | ||||
|   :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) | ||||
|   "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', | ||||
|   `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 | ||||
| information with all available parameters." | ||||
|   (guix-eval-read (guix-make-guile-expression | ||||
|                    'entries | ||||
|                    guix-current-profile params | ||||
|                    entry-type search-type search-vals))) | ||||
|                    profile params entry-type search-type search-vals))) | ||||
| 
 | ||||
| (defun guix-get-show-entries (buffer-type entry-type search-type | ||||
|                                           &rest 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 entry-type search-type 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 entries buffer-type entry-type | ||||
|     (guix-set-buffer profile entries buffer-type entry-type | ||||
|                      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) | ||||
|   "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." | ||||
|   (when entries | ||||
|     (let ((buf (if (eq major-mode (guix-get-symbol | ||||
|                                    "mode" buffer-type entry-type)) | ||||
|     (let ((buf (if (and (eq major-mode | ||||
|                             (guix-get-symbol "mode" buffer-type entry-type)) | ||||
|                         (equal guix-profile profile)) | ||||
|                    (current-buffer) | ||||
|                  (get-buffer-create | ||||
|                   (symbol-value | ||||
|                    (guix-get-symbol "buffer-name" | ||||
|                                     buffer-type entry-type)))))) | ||||
|                   (guix-buffer-name profile buffer-type | ||||
|                                     entry-type search-type))))) | ||||
|       (with-current-buffer buf | ||||
|         (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) | ||||
|         (funcall (if history-replace | ||||
|                      #'guix-history-replace | ||||
|  | @ -494,18 +557,18 @@ If NO-DISPLAY is non-nil, do not switch to the buffer." | |||
|              entries entry-type) | ||||
|     (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) | ||||
|   "Function called for moving by history." | ||||
|   (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) | ||||
|   (guix-result-message 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-entries guix-buffer-type guix-entry-type | ||||
|         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) | ||||
|  | @ -529,10 +592,11 @@ See `revert-buffer' for the meaning of NOCONFIRM." | |||
|                               guix-buffer-type guix-entry-type)) | ||||
|             (y-or-n-p "Update current information? ")) | ||||
|     (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-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)))) | ||||
| 
 | ||||
| (defun guix-redisplay-buffer () | ||||
|  | @ -719,8 +783,9 @@ VARIABLE is a name of an option variable.") | |||
|       guix-operation-option-true-string | ||||
|     guix-operation-option-false-string)) | ||||
| 
 | ||||
| (defun guix-process-package-actions (actions &optional operation-buffer) | ||||
|   "Process package ACTIONS. | ||||
| (defun guix-process-package-actions (profile actions | ||||
|                                      &optional operation-buffer) | ||||
|   "Process package ACTIONS on PROFILE. | ||||
| Each action is a list of the form: | ||||
| 
 | ||||
|   (ACTION-TYPE PACKAGE-SPEC ...) | ||||
|  | @ -738,23 +803,25 @@ PACKAGE-SPEC should have the following form: (ID [OUTPUT] ...)." | |||
|                 ((remove delete) (setq remove (append remove specs)))))) | ||||
|           actions) | ||||
|     (when (guix-continue-package-operation-p | ||||
|            profile | ||||
|            :install install :upgrade upgrade :remove remove) | ||||
|       (guix-eval-in-repl | ||||
|        (guix-make-guile-expression | ||||
|         'process-package-actions guix-current-profile | ||||
|         'process-package-actions profile | ||||
|         :install install :upgrade upgrade :remove remove | ||||
|         :use-substitutes? (or guix-use-substitutes 'f) | ||||
|         :dry-run? (or guix-dry-run 'f)) | ||||
|        (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. | ||||
| 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 | ||||
|                        'package 'id | ||||
|                        profile 'package 'id | ||||
|                        (append (mapcar #'car install) | ||||
|                                (mapcar #'car upgrade) | ||||
|                                (mapcar #'car remove)) | ||||
|  | @ -768,6 +835,7 @@ See `guix-process-package-actions' for details." | |||
|                 (setq-local cursor-type nil) | ||||
|                 (setq buffer-read-only nil) | ||||
|                 (erase-buffer) | ||||
|                 (insert "Profile: " profile "\n\n") | ||||
|                 (guix-insert-package-strings install-strings "install") | ||||
|                 (guix-insert-package-strings upgrade-strings "upgrade") | ||||
|                 (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))) | ||||
|   (force-mode-line-update)) | ||||
| 
 | ||||
| (defun guix-delete-generations (generations &optional operation-buffer) | ||||
|   "Delete GENERATIONS. | ||||
| (defun guix-delete-generations (profile generations | ||||
|                                 &optional operation-buffer) | ||||
|   "Delete GENERATIONS from PROFILE. | ||||
| Each element from GENERATIONS is a generation number." | ||||
|   (when (or (not guix-operation-confirm) | ||||
|               (y-or-n-p | ||||
|                (let ((count (length generations))) | ||||
|                  (if (> count 1) | ||||
|                      (format "Delete %d generations? " count) | ||||
|                    (format "Delete generation number %d? " | ||||
|                            (car generations)))))) | ||||
|             (y-or-n-p | ||||
|              (let ((count (length generations))) | ||||
|                (if (> count 1) | ||||
|                    (format "Delete %d generations from profile '%s'? " | ||||
|                            count profile) | ||||
|                  (format "Delete generation %d from profile '%s'? " | ||||
|                          (car generations) profile))))) | ||||
|     (guix-eval-in-repl | ||||
|      (guix-make-guile-expression | ||||
|       'delete-generations* guix-current-profile generations) | ||||
|       'delete-generations* profile generations) | ||||
|      operation-buffer))) | ||||
| 
 | ||||
| (defun guix-switch-to-generation (generation &optional operation-buffer) | ||||
|   "Switch `guix-current-profile' to GENERATION number." | ||||
| (defun guix-switch-to-generation (profile generation | ||||
|                                   &optional operation-buffer) | ||||
|   "Switch PROFILE to GENERATION." | ||||
|   (when (or (not guix-operation-confirm) | ||||
|             (y-or-n-p (format "Switch current profile to generation %d? " | ||||
|                               generation))) | ||||
|             (y-or-n-p (format "Switch profile '%s' to generation %d? " | ||||
|                               profile generation))) | ||||
|     (guix-eval-in-repl | ||||
|      (guix-make-guile-expression | ||||
|       'switch-to-generation guix-current-profile generation) | ||||
|       'switch-to-generation profile generation) | ||||
|      operation-buffer))) | ||||
| 
 | ||||
| (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 | ||||
|   'help-echo "Describe this package" | ||||
|   'action (lambda (btn) | ||||
|             (guix-get-show-entries 'info guix-package-info-type 'name | ||||
|                                    (button-label btn)))) | ||||
|             (guix-get-show-entries guix-profile 'info guix-package-info-type | ||||
|                                    'name (button-label btn)))) | ||||
| 
 | ||||
| (defun guix-info-insert-action-button (label action &optional message | ||||
|                                              &rest properties) | ||||
|  | @ -558,6 +558,7 @@ ENTRY is an alist with package info." | |||
|      type-str | ||||
|      (lambda (btn) | ||||
|        (guix-process-package-actions | ||||
|         guix-profile | ||||
|         `((,(button-get btn 'action-type) (,(button-get btn 'id) | ||||
|                                            ,(button-get btn 'output)))) | ||||
|         (current-buffer))) | ||||
|  | @ -631,15 +632,15 @@ ENTRY is an alist with package info." | |||
|   (guix-info-insert-action-button | ||||
|    "Packages" | ||||
|    (lambda (btn) | ||||
|      (guix-get-show-entries 'list guix-package-list-type 'generation | ||||
|                             (button-get btn 'number))) | ||||
|      (guix-get-show-entries guix-profile 'list guix-package-list-type | ||||
|                             'generation (button-get btn 'number))) | ||||
|    "Show installed packages for this generation" | ||||
|    'number number) | ||||
|   (guix-info-insert-indent) | ||||
|   (guix-info-insert-action-button | ||||
|    "Delete" | ||||
|    (lambda (btn) | ||||
|      (guix-delete-generations (list (button-get btn 'number)) | ||||
|      (guix-delete-generations guix-profile (list (button-get btn 'number)) | ||||
|                               (current-buffer))) | ||||
|    "Delete this generation" | ||||
|    'number number)) | ||||
|  | @ -653,7 +654,7 @@ ENTRY is an alist with package info." | |||
|     (guix-info-insert-action-button | ||||
|      "Switch" | ||||
|      (lambda (btn) | ||||
|        (guix-switch-to-generation (button-get btn 'number) | ||||
|        (guix-switch-to-generation guix-profile (button-get btn 'number) | ||||
|                                   (current-buffer))) | ||||
|      "Switch to this generation (make it the current one)" | ||||
|      '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) | ||||
|               (y-or-n-p (format "Do you really want to describe %d entries? " | ||||
|                                 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) | ||||
|   "Describe entries marked with a general mark. | ||||
|  | @ -617,7 +618,8 @@ FUN should accept action-type as argument." | |||
|   (let ((actions (delq nil | ||||
|                        (mapcar fun '(install delete upgrade))))) | ||||
|     (if actions | ||||
|         (guix-process-package-actions actions (current-buffer)) | ||||
|         (guix-process-package-actions | ||||
|          guix-profile actions (current-buffer)) | ||||
|       (user-error "No operations specified")))) | ||||
| 
 | ||||
| (defun guix-package-list-execute () | ||||
|  | @ -751,13 +753,13 @@ VAL is a boolean value." | |||
|          (number  (guix-get-key-val entry 'number))) | ||||
|     (if current | ||||
|         (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 () | ||||
|   "List installed packages for the generation at point." | ||||
|   (interactive) | ||||
|   (guix-get-show-entries 'list guix-package-list-type 'generation | ||||
|                          (guix-list-current-id))) | ||||
|   (guix-get-show-entries guix-profile 'list guix-package-list-type | ||||
|                          'generation (guix-list-current-id))) | ||||
| 
 | ||||
| (defun guix-generation-list-mark-delete (&optional arg) | ||||
|   "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))) | ||||
|     (or marked | ||||
|         (user-error "No generations marked for deletion")) | ||||
|     (guix-delete-generations marked (current-buffer)))) | ||||
|     (guix-delete-generations guix-profile marked (current-buffer)))) | ||||
| 
 | ||||
| (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 | ||||
|   "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. | ||||
| 
 | ||||
| If PROFILE is nil, use `guix-current-profile'. | ||||
| 
 | ||||
| See `guix-get-entries' for the meaning of SEARCH-TYPE and | ||||
| SEARCH-VALS. | ||||
| 
 | ||||
| Results are displayed in the list buffer, unless a single package | ||||
| 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 | ||||
|                                     (guix-get-params-for-receiving | ||||
|                                      'list guix-package-list-type)))) | ||||
|     (if (or guix-list-single-package | ||||
|             (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) | ||||
|       (let ((packages (guix-get-entries guix-package-info-type | ||||
|       (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 packages 'info guix-package-info-type | ||||
|         (guix-set-buffer profile packages 'info guix-package-info-type | ||||
|                          search-type search-vals))))) | ||||
| 
 | ||||
| (defun guix-get-show-generations (search-type &rest search-vals) | ||||
|   "Search for generations and show results." | ||||
| (defun guix-get-show-generations (profile search-type &rest search-vals) | ||||
|   "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)) | ||||
| 
 | ||||
| ;;;###autoload | ||||
| (defun guix-search-by-name (name) | ||||
| (defun guix-search-by-name (name &optional profile) | ||||
|   "Search for Guix packages by NAME. | ||||
| 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 | ||||
|    (list (read-string "Package name: " nil 'guix-search-history))) | ||||
|   (guix-get-show-packages 'name name)) | ||||
|    (list (read-string "Package name: " nil 'guix-search-history) | ||||
|          (and current-prefix-arg | ||||
|               (guix-profile-prompt)))) | ||||
|   (guix-get-show-packages profile 'name name)) | ||||
| 
 | ||||
| ;;;###autoload | ||||
| (defun guix-search-by-regexp (regexp &rest params) | ||||
| (defun guix-search-by-regexp (regexp &optional params profile) | ||||
|   "Search for Guix packages by REGEXP. | ||||
| 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 | ||||
|    (list (read-string "Regexp: " nil 'guix-search-history))) | ||||
|   (or params (setq params guix-search-params)) | ||||
|   (guix-get-show-packages 'regexp regexp params)) | ||||
|    (list (read-regexp "Regexp: " nil 'guix-search-history) | ||||
|          nil | ||||
|          (and current-prefix-arg | ||||
|               (guix-profile-prompt)))) | ||||
|   (guix-get-show-packages profile 'regexp regexp | ||||
|                           (or params guix-search-params))) | ||||
| 
 | ||||
| ;;;###autoload | ||||
| (defun guix-installed-packages () | ||||
|   "Display information about installed Guix packages." | ||||
|   (interactive) | ||||
|   (guix-get-show-packages 'installed)) | ||||
| (defun guix-installed-packages (&optional profile) | ||||
|   "Display information about installed Guix packages. | ||||
| 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-packages profile 'installed)) | ||||
| 
 | ||||
| ;;;###autoload | ||||
| (defun guix-obsolete-packages () | ||||
|   "Display information about obsolete Guix packages." | ||||
|   (interactive) | ||||
|   (guix-get-show-packages 'obsolete)) | ||||
| (defun guix-obsolete-packages (&optional profile) | ||||
|   "Display information about obsolete Guix packages. | ||||
| 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-packages profile 'obsolete)) | ||||
| 
 | ||||
| ;;;###autoload | ||||
| (defun guix-all-available-packages () | ||||
|   "Display information about all available Guix packages." | ||||
|   (interactive) | ||||
|   (guix-get-show-packages 'all-available)) | ||||
| (defun guix-all-available-packages (&optional profile) | ||||
|   "Display information about all available Guix packages. | ||||
| 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-packages profile 'all-available)) | ||||
| 
 | ||||
| ;;;###autoload | ||||
| (defun guix-newest-available-packages () | ||||
|   "Display information about the newest available Guix packages." | ||||
|   (interactive) | ||||
|   (guix-get-show-packages 'newest-available)) | ||||
| (defun guix-newest-available-packages (&optional profile) | ||||
|   "Display information about the newest available Guix packages. | ||||
| 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-packages profile 'newest-available)) | ||||
| 
 | ||||
| ;;;###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. | ||||
| If NUMBER is nil, display all generations. | ||||
| 
 | ||||
| Generations can be displayed in a list or info buffers depending | ||||
| on `guix-show-generations-function'. | ||||
| 
 | ||||
| Interactively, NUMBER is defined by a numeric prefix." | ||||
|   (interactive "P") | ||||
|   (if (numberp number) | ||||
|       (guix-get-show-generations 'last number) | ||||
|     (guix-get-show-generations 'all))) | ||||
| If PROFILE is nil, use `guix-current-profile'. | ||||
| Interactively with prefix, prompt for PROFILE." | ||||
|   (interactive | ||||
|    (list (read-number "The number of last generations: ") | ||||
|          (and current-prefix-arg | ||||
|               (guix-profile-prompt)))) | ||||
|   (guix-get-show-generations profile 'last number)) | ||||
| 
 | ||||
| ;;;###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. | ||||
| 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 | ||||
|    (list (guix-read-date "Find generations (from): ") | ||||
|          (guix-read-date "Find generations (to): "))) | ||||
|   (guix-get-show-generations 'time | ||||
|          (guix-read-date "Find generations (to): ") | ||||
|          (and current-prefix-arg | ||||
|               (guix-profile-prompt)))) | ||||
|   (guix-get-show-generations profile 'time | ||||
|                              (float-time from) | ||||
|                              (float-time to))) | ||||
| 
 | ||||
|  |  | |||
		Reference in a new issue