diff --git a/libraries/prompter/prompter-source.lisp b/libraries/prompter/prompter-source.lisp index e48857d671a..10d49c90415 100644 --- a/libraries/prompter/prompter-source.lisp +++ b/libraries/prompter/prompter-source.lisp @@ -330,6 +330,9 @@ call.")) (alex:when-let ((action (first (marks-actions source)))) (run-thread "Prompter mark action thread" (funcall action (marks source))))) +(defmethod default-selection-action ((source prompter:source)) + (first (slot-value source 'selection-actions))) + (export-always 'object-attributes) (defgeneric object-attributes (object source) (:method ((object t) (source prompter:source)) diff --git a/libraries/prompter/prompter.lisp b/libraries/prompter/prompter.lisp index baa93fc0ab4..47c8444b31c 100644 --- a/libraries/prompter/prompter.lisp +++ b/libraries/prompter/prompter.lisp @@ -167,13 +167,25 @@ compution is not finished."))) (defmethod (setf selection) (value (prompter prompter)) (setf (slot-value prompter 'selection) value) - (let ((source (selected-source prompter))) - (when (selection-actions-enabled-p source) - (if (< 0 (selection-actions-delay source)) + (call-selection-action prompter)) + +(export-always 'call-selection-action) +(defmethod call-selection-action ((prompter prompter)) + (sera:and-let* ((source (selected-source prompter)) + (_ (selection-actions-enabled-p source)) + (action (default-selection-action source)) + (suggestion (selected-suggestion prompter))) + (let ((delay (selection-actions-delay source))) + (if (plusp delay) (run-thread "Prompter selection action thread" - (sleep (selection-actions-delay source)) - (call-selection-action prompter)) - (call-selection-action prompter))))) + (sleep delay) + (funcall action (value suggestion))) + (funcall action (value suggestion)))))) + +(export-always 'set-selection-action) +(defmethod set-selection-action (value (prompter prompter)) + (setf (selection-actions (selected-source prompter)) + (cons value (delete value (selection-actions (selected-source prompter)))))) (export-always 'input) (defmethod (setf input) (text (prompter prompter)) @@ -199,12 +211,6 @@ Signal destruction by sending a value to PROMPTER's `interrupt-channel'." (calispel:! (sync-interrupt-channel (sync-queue prompter)) t) (calispel:! (interrupt-channel prompter) t)) -(export-always 'call-selection-action) -(defun call-selection-action (prompter) - (sera:and-let* ((action (first (selection-actions (selected-source prompter)))) - (suggestion (selected-suggestion prompter))) - (funcall action (value suggestion)))) - (defun select (prompter steps &key wrap-over-p) "Select `suggestion' by jumping STEPS forward. If STEPS is 0, do nothing. diff --git a/source/changelog.lisp b/source/changelog.lisp index d3de1828e6a..c71cb03d0f4 100644 --- a/source/changelog.lisp +++ b/source/changelog.lisp @@ -485,7 +485,12 @@ to open a file, save it, switch buffer or delete current buffer.") (:li (:nxref :command 'nyxt/document-mode:paste-from-clipboard-ring) " is now conveniently bound to " (:code "M-y") " in Emacs scheme of " (:nxref :class-name 'nyxt/document-mode:document-mode) ".") - (:li "Prompt-buffer now has familiar bindings for text cutting.")) + (:li "Prompt-buffer now has familiar bindings for text cutting.") + (:li "Add " (:nxref :command 'nyxt/prompt-buffer-mode:set-selection-action) + ", bound to " (:code "C-c C-j") "by default.") + (:li (:code "return-selection-over-action") " renamed to " + (:nxref :command 'nyxt/prompt-buffer-mode:return-marks-action) + ". The default keybinding is the same.")) (:h3 "Programming interface") (:ul diff --git a/source/mode/prompt-buffer.lisp b/source/mode/prompt-buffer.lisp index 6634a0ed954..3951ff36ef7 100644 --- a/source/mode/prompt-buffer.lisp +++ b/source/mode/prompt-buffer.lisp @@ -44,8 +44,9 @@ default)." "f1 b" 'run-prompt-buffer-command "f1 m" 'describe-prompt-buffer "return" 'return-selection - "M-return" 'return-selection-over-action + "M-return" 'return-marks-action "C-return" 'run-selection-action + "C-c C-j" 'set-selection-action "tab" 'insert-selection ; TODO: This is the Emacs Helm binding. Better? "C-c C-f" 'toggle-selection-actions-enabled @@ -305,6 +306,10 @@ current unmarked selection." (sera:and-let* ((first-prompt-buffer (first (nyxt::active-prompt-buffers window)))) (prompter:return-actions first-prompt-buffer))) +(defun prompt-buffer-selection-actions (&optional (window (current-window))) + (sera:and-let* ((first-prompt-buffer (first (nyxt::active-prompt-buffers window)))) + (prompter:selection-actions (prompter:selected-source first-prompt-buffer)))) + ;; TODO: Should return-actions be commands? For now, they can be either ;; commands or symbols. (defun make-action-suggestion (action &optional source input) @@ -323,25 +328,35 @@ current unmarked selection." (t (documentation action 'function))))) ""))))) -(define-class action-source (prompter:source) +(define-class return-action-source (prompter:source) ((prompter:name "List of return-actions") (prompter:constructor (prompt-buffer-return-actions)) (prompter:suggestion-maker 'make-action-suggestion))) -(define-command-prompt return-selection-over-action (prompt-buffer) - "Prompt for an action to run over PROMPT-BUFFER selection." +(define-class selection-action-source (prompter:source) + ((prompter:name "List of selection-actions") + (prompter:constructor (prompt-buffer-selection-actions)) + (prompter:suggestion-maker 'make-action-suggestion))) + +(define-command-prompt return-marks-action (prompt-buffer) + "Prompt for an action to run over PROMPT-BUFFER `prompter:marks'." (if (equal (mapcar #'type-of (prompter:sources (current-prompt-buffer))) - '(action-source)) + '(return-action-source)) (echo "Already displaying return-actions of previous prompt buffer.") - (let ((action (prompt1 :prompt "Action to run on selection" - :sources 'action-source))) - (when action - (prompter:return-selection prompt-buffer action))))) + (alex:when-let ((action (prompt1 :prompt "Action to run on selection" + :sources 'return-action-source))) + (prompter:return-selection prompt-buffer action)))) (define-command-prompt run-selection-action (prompt-buffer) - "Run one of `prompter:selection-actions' without closing PROMPT-BUFFER." + "Run `prompter::default-selection-action' without closing PROMPT-BUFFER." (prompter:call-selection-action prompt-buffer)) +(define-command-prompt set-selection-action (prompt-buffer) + "Set `prompter:selection-actions' without closing PROMPT-BUFFER." + (alex:when-let ((action (prompt1 :prompt "Set selection action" + :sources 'selection-action-source))) + (prompter:set-selection-action action prompt-buffer))) + (define-command-prompt cancel-input (prompt-buffer) ; TODO: Rename. "Close the PROMPT-BUFFER without further action." (prompter:destroy prompt-buffer)) diff --git a/source/tutorial.lisp b/source/tutorial.lisp index 35ad1889dd8..0678deb66d1 100644 --- a/source/tutorial.lisp +++ b/source/tutorial.lisp @@ -63,9 +63,9 @@ matching your input as you type.") :modes (list (make-instance 'nyxt/prompt-buffer-mode:prompt-buffer-mode))) ": Validate the selected suggestion(s) or the current input if there is no suggestion.") - (:li (command-markup 'nyxt/prompt-buffer-mode:return-selection-over-action + (:li (command-markup 'nyxt/prompt-buffer-mode:return-marks-action :modes (list (make-instance 'nyxt/prompt-buffer-mode:prompt-buffer-mode))) - ": Query the user for an action to run over the selected suggestion(s).")) + ": Query the user for an action to run over the marked suggestion(s).")) (:p " Some commands support multiple selections, for instance " (:code "delete-buffer") " can delete all selected buffers at once. When the input is changed and the suggestions are re-filtered, the selection is