emacs: Support auto-updating after performing REPL operation.
* emacs/guix-backend.el (guix-operation-buffer): New variable. (guix-eval-in-repl): Use it. Add optional 'operation-buffer' argument. * emacs/guix-base.el (guix-update-after-operation): New variable. (guix-switch-to-buffer, guix-list-or-info-buffer-p, guix-buffers, guix-update-buffers-maybe): New procedures. (guix-set-buffer): Use 'guix-switch-to-buffer'. Add optional 'no-display' argument. (guix-process-package-actions, guix-delete-generations, guix-switch-to-generation): Add optional 'operation-buffer' argument. * emacs/guix-info.el (guix-package-info-insert-action-button, guix-generation-info-insert-number, guix-generation-info-insert-current): Adjust for using operation buffer. * emacs/guix-list.el (guix-list-execute-package-actions, guix-generation-list-switch, guix-generation-list-execute): Likewise.master
parent
063b60be7b
commit
49d758d212
|
@ -234,6 +234,7 @@ This is a replacement for `geiser-repl--output-filter'."
|
||||||
(setq guix-repl-operation-p nil)
|
(setq guix-repl-operation-p nil)
|
||||||
(run-hooks 'guix-after-repl-operation-hook)))
|
(run-hooks 'guix-after-repl-operation-hook)))
|
||||||
((string-match geiser-guile--debugger-prompt-regexp str)
|
((string-match geiser-guile--debugger-prompt-regexp str)
|
||||||
|
(setq guix-repl-operation-p nil)
|
||||||
(geiser-con--connection-set-debugging geiser-repl--connection
|
(geiser-con--connection-set-debugging geiser-repl--connection
|
||||||
(match-beginning 0))
|
(match-beginning 0))
|
||||||
(geiser-autodoc--disinhibit-autodoc))))
|
(geiser-autodoc--disinhibit-autodoc))))
|
||||||
|
@ -272,6 +273,9 @@ additional internal REPL if it exists."
|
||||||
|
|
||||||
;;; Evaluating expressions
|
;;; Evaluating expressions
|
||||||
|
|
||||||
|
(defvar guix-operation-buffer nil
|
||||||
|
"Buffer from which the latest Guix operation was performed.")
|
||||||
|
|
||||||
(defun guix-make-guile-expression (fun &rest args)
|
(defun guix-make-guile-expression (fun &rest args)
|
||||||
"Return string containing a guile expression for calling FUN with ARGS."
|
"Return string containing a guile expression for calling FUN with ARGS."
|
||||||
(format "(%S %s)" fun
|
(format "(%S %s)" fun
|
||||||
|
@ -313,10 +317,13 @@ Return elisp expression of the first result value of evaluation."
|
||||||
(replace-regexp-in-string
|
(replace-regexp-in-string
|
||||||
"#t" "t" (car (guix-eval str wrap))))))
|
"#t" "t" (car (guix-eval str wrap))))))
|
||||||
|
|
||||||
(defun guix-eval-in-repl (str)
|
(defun guix-eval-in-repl (str &optional operation-buffer)
|
||||||
"Switch to Guix REPL and evaluate STR with guile expression there."
|
"Switch to Guix REPL and evaluate STR with guile expression there.
|
||||||
|
If OPERATION-BUFFER is non-nil, it should be a buffer from which
|
||||||
|
the current operation was performed."
|
||||||
(run-hooks 'guix-before-repl-operation-hook)
|
(run-hooks 'guix-before-repl-operation-hook)
|
||||||
(setq guix-repl-operation-p t)
|
(setq guix-repl-operation-p t
|
||||||
|
guix-operation-buffer operation-buffer)
|
||||||
(let ((repl (guix-get-repl-buffer)))
|
(let ((repl (guix-get-repl-buffer)))
|
||||||
(with-current-buffer repl
|
(with-current-buffer repl
|
||||||
(delete-region (geiser-repl--last-prompt-end) (point-max))
|
(delete-region (geiser-repl--last-prompt-end) (point-max))
|
||||||
|
|
|
@ -190,6 +190,59 @@ If PATH is relative, it is considered to be relative to
|
||||||
(move-to-column col)
|
(move-to-column col)
|
||||||
(recenter 1))))
|
(recenter 1))))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Buffers and auto updating.
|
||||||
|
|
||||||
|
(defcustom guix-update-after-operation 'current
|
||||||
|
"Define what information to update after executing an operation.
|
||||||
|
|
||||||
|
After successful executing an operation in the Guix REPL (for
|
||||||
|
example after installing a package), information in Guix buffers
|
||||||
|
will or will not be automatically updated depending on a value of
|
||||||
|
this variable.
|
||||||
|
|
||||||
|
If nil, update nothing (do not revert any buffer).
|
||||||
|
If `current', update the buffer from which an operation was performed.
|
||||||
|
If `all', update all Guix buffers (not recommended)."
|
||||||
|
:type '(choice (const :tag "Do nothing" nil)
|
||||||
|
(const :tag "Update operation buffer" current)
|
||||||
|
(const :tag "Update all Guix buffers" all))
|
||||||
|
:group 'guix)
|
||||||
|
|
||||||
|
(defun guix-switch-to-buffer (buffer)
|
||||||
|
"Switch to a 'list' or 'info' BUFFER."
|
||||||
|
(pop-to-buffer buffer
|
||||||
|
'((display-buffer-reuse-window
|
||||||
|
display-buffer-same-window))))
|
||||||
|
|
||||||
|
(defun guix-list-or-info-buffer-p (&optional buffer)
|
||||||
|
"Return non-nil if BUFFER is a Guix 'list' or 'info' buffer.
|
||||||
|
If BUFFER is nil, check current buffer."
|
||||||
|
(with-current-buffer (or buffer (current-buffer))
|
||||||
|
(derived-mode-p 'guix-list-mode 'guix-info-mode)))
|
||||||
|
|
||||||
|
(defun guix-buffers ()
|
||||||
|
"Return list of all Guix 'list' and 'info' buffers."
|
||||||
|
(cl-remove-if-not #'guix-list-or-info-buffer-p
|
||||||
|
(buffer-list)))
|
||||||
|
|
||||||
|
(defun guix-update-buffers-maybe ()
|
||||||
|
"Update buffers after Guix operation if needed.
|
||||||
|
See `guix-update-after-operation' for details."
|
||||||
|
(let ((to-update (and guix-operation-buffer
|
||||||
|
(cl-case guix-update-after-operation
|
||||||
|
(current (list guix-operation-buffer))
|
||||||
|
(all (guix-buffers))))))
|
||||||
|
(setq guix-operation-buffer nil)
|
||||||
|
(mapc (lambda (buf)
|
||||||
|
(and (buffer-live-p buf)
|
||||||
|
(guix-list-or-info-buffer-p buf)
|
||||||
|
(with-current-buffer buf
|
||||||
|
(guix-revert-buffer nil t))))
|
||||||
|
to-update)))
|
||||||
|
|
||||||
|
(add-hook 'guix-after-repl-operation-hook 'guix-update-buffers-maybe)
|
||||||
|
|
||||||
|
|
||||||
;;; Common definitions for buffer types
|
;;; Common definitions for buffer types
|
||||||
|
|
||||||
|
@ -399,16 +452,18 @@ See `guix-get-entries' for the meaning of SEARCH-TYPE and SEARCH-VALS."
|
||||||
search-type search-vals)))
|
search-type search-vals)))
|
||||||
|
|
||||||
(defun guix-set-buffer (entries buffer-type entry-type search-type
|
(defun guix-set-buffer (entries buffer-type entry-type search-type
|
||||||
search-vals &optional history-replace)
|
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.
|
||||||
|
|
||||||
Display ENTRIES, set variables and make history item.
|
Insert ENTRIES in buffer, set variables and make history item.
|
||||||
ENTRIES should have a form of `guix-entries'.
|
ENTRIES should have a form of `guix-entries'.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
If HISTORY-REPLACE is non-nil, replace current history item,
|
If HISTORY-REPLACE is non-nil, replace current history item,
|
||||||
otherwise add the new one."
|
otherwise add the new one.
|
||||||
|
|
||||||
|
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 (eq major-mode (guix-get-symbol
|
||||||
"mode" buffer-type entry-type))
|
"mode" buffer-type entry-type))
|
||||||
|
@ -425,9 +480,8 @@ otherwise add the new one."
|
||||||
#'guix-history-replace
|
#'guix-history-replace
|
||||||
#'guix-history-add)
|
#'guix-history-add)
|
||||||
(guix-make-history-item)))
|
(guix-make-history-item)))
|
||||||
(pop-to-buffer buf
|
(or no-display
|
||||||
'((display-buffer-reuse-window
|
(guix-switch-to-buffer buf))))
|
||||||
display-buffer-same-window)))))
|
|
||||||
(guix-result-message entries entry-type search-type search-vals))
|
(guix-result-message entries entry-type search-type search-vals))
|
||||||
|
|
||||||
(defun guix-show-entries (entries buffer-type entry-type)
|
(defun guix-show-entries (entries buffer-type entry-type)
|
||||||
|
@ -479,7 +533,7 @@ See `revert-buffer' for the meaning of NOCONFIRM."
|
||||||
(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 entries guix-buffer-type guix-entry-type
|
||||||
guix-search-type guix-search-vals t))))
|
guix-search-type guix-search-vals t t))))
|
||||||
|
|
||||||
(defun guix-redisplay-buffer ()
|
(defun guix-redisplay-buffer ()
|
||||||
"Redisplay current information.
|
"Redisplay current information.
|
||||||
|
@ -661,7 +715,7 @@ 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 (&rest actions)
|
(defun guix-process-package-actions (actions &optional operation-buffer)
|
||||||
"Process package ACTIONS.
|
"Process package ACTIONS.
|
||||||
Each action is a list of the form:
|
Each action is a list of the form:
|
||||||
|
|
||||||
|
@ -686,7 +740,8 @@ PACKAGE-SPEC should have the following form: (ID [OUTPUT] ...)."
|
||||||
'process-package-actions guix-current-profile
|
'process-package-actions guix-current-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)))))
|
||||||
|
|
||||||
(cl-defun guix-continue-package-operation-p (&key install upgrade remove)
|
(cl-defun guix-continue-package-operation-p (&key install upgrade remove)
|
||||||
"Return non-nil if a package operation should be continued.
|
"Return non-nil if a package operation should be continued.
|
||||||
|
@ -802,7 +857,7 @@ 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 (&rest generations)
|
(defun guix-delete-generations (generations &optional operation-buffer)
|
||||||
"Delete GENERATIONS.
|
"Delete GENERATIONS.
|
||||||
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)
|
||||||
|
@ -814,16 +869,18 @@ Each element from GENERATIONS is a generation number."
|
||||||
(car generations))))))
|
(car generations))))))
|
||||||
(guix-eval-in-repl
|
(guix-eval-in-repl
|
||||||
(guix-make-guile-expression
|
(guix-make-guile-expression
|
||||||
'delete-generations* guix-current-profile generations))))
|
'delete-generations* guix-current-profile generations)
|
||||||
|
operation-buffer)))
|
||||||
|
|
||||||
(defun guix-switch-to-generation (generation)
|
(defun guix-switch-to-generation (generation &optional operation-buffer)
|
||||||
"Switch `guix-current-profile' to GENERATION number."
|
"Switch `guix-current-profile' to GENERATION number."
|
||||||
(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 current profile to generation %d? "
|
||||||
generation)))
|
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 guix-current-profile generation)
|
||||||
|
operation-buffer)))
|
||||||
|
|
||||||
(provide 'guix-base)
|
(provide 'guix-base)
|
||||||
|
|
||||||
|
|
|
@ -558,9 +558,9 @@ ENTRY is an alist with package info."
|
||||||
type-str
|
type-str
|
||||||
(lambda (btn)
|
(lambda (btn)
|
||||||
(guix-process-package-actions
|
(guix-process-package-actions
|
||||||
(list (button-get btn 'action-type)
|
`((,(button-get btn 'action-type) (,(button-get btn 'id)
|
||||||
(list (button-get btn 'id)
|
,(button-get btn 'output))))
|
||||||
(button-get btn 'output)))))
|
(current-buffer)))
|
||||||
(concat type-str " '" full-name "'")
|
(concat type-str " '" full-name "'")
|
||||||
'action-type type
|
'action-type type
|
||||||
'id (or (guix-get-key-val entry 'package-id)
|
'id (or (guix-get-key-val entry 'package-id)
|
||||||
|
@ -639,7 +639,8 @@ ENTRY is an alist with package info."
|
||||||
(guix-info-insert-action-button
|
(guix-info-insert-action-button
|
||||||
"Delete"
|
"Delete"
|
||||||
(lambda (btn)
|
(lambda (btn)
|
||||||
(guix-delete-generations (button-get btn 'number)))
|
(guix-delete-generations (list (button-get btn 'number))
|
||||||
|
(current-buffer)))
|
||||||
"Delete this generation"
|
"Delete this generation"
|
||||||
'number number))
|
'number number))
|
||||||
|
|
||||||
|
@ -652,7 +653,8 @@ 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 (button-get btn 'number)
|
||||||
|
(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))))
|
||||||
|
|
||||||
|
|
|
@ -617,7 +617,7 @@ 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
|
||||||
(apply #'guix-process-package-actions actions)
|
(guix-process-package-actions actions (current-buffer))
|
||||||
(user-error "No operations specified"))))
|
(user-error "No operations specified"))))
|
||||||
|
|
||||||
(defun guix-package-list-execute ()
|
(defun guix-package-list-execute ()
|
||||||
|
@ -751,7 +751,7 @@ 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))))
|
(guix-switch-to-generation 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."
|
||||||
|
@ -773,7 +773,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"))
|
||||||
(apply #'guix-delete-generations marked)))
|
(guix-delete-generations marked (current-buffer))))
|
||||||
|
|
||||||
(provide 'guix-list)
|
(provide 'guix-list)
|
||||||
|
|
||||||
|
|
Reference in New Issue