]> git.eshelyaron.com Git - emacs.git/commitdiff
Allow editing variable values in *Help* buffers
authorLars Ingebrigtsen <larsi@gnus.org>
Sun, 17 Apr 2022 16:59:59 +0000 (18:59 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Sun, 17 Apr 2022 16:59:59 +0000 (18:59 +0200)
* lisp/help-fns.el (help-enable-variable-value-editing): New user
option.
(describe-variable): Tag values for editing.
(help-fns--editable-variable, help-fns-edit-variable): New
functions (bug#36826).
(help-fns--edit-value-mode-map, help-fns--edit-value-mode)
(help-fns-edit-mode-done): New mode and commands.

etc/NEWS
lisp/help-fns.el
lisp/help-mode.el

index 3821dac17989df73ebc85c8f29bc404779951c7d..a59c9691b2288e8540a9d0ef5e9f0898f0f36d0a 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -405,6 +405,12 @@ command also works for non-Emoji characters.)
 
 ** Help
 
+---
+*** New user option 'help-enable-variable-value-editing'.
+If enabled, 'e' on a value in *Help* will pop you to a new buffer
+where you can edit the value.  This is not enabled by default, because
+it's easy to make an edit that yields an invalid result.
+
 ---
 *** 'C-h b' uses outlining by default.
 Set 'describe-bindings-outline' to nil to get the old behavior.
index 309cf0b85a3fead1475e1aa00e7fc9f615d3fda7..72d773403fd625c7d5e40c4ad487a0bb7914053a 100644 (file)
@@ -133,6 +133,14 @@ with the current prefix.  The files are chosen according to
   :group 'help
   :version "26.3")
 
+(defcustom help-enable-variable-value-editing nil
+  "If non-nil, allow editing values in *Help* buffers.
+Values that aren't readable by the Emacs Lisp reader can't be
+edited even if this option is enabled."
+  :type 'boolean
+  :group 'help
+  :version "29.1")
+
 (defcustom help-enable-symbol-autoload nil
   "Perform autoload if docs are missing from autoload objects."
   :type 'boolean
@@ -1167,10 +1175,11 @@ it is displayed along with the global value."
                       (let ((rep
                              (let ((print-quoted t)
                                     (print-circle t))
-                               (cl-prin1-to-string val))))
-                        (if (and (symbolp val) (not (booleanp val)))
+                                (cl-prin1-to-string val))))
+                         (if (and (symbolp val) (not (booleanp val)))
                             (format-message "`%s'" rep)
-                          rep))))
+                          rep)))
+                      (start (point)))
                  (if (< (+ (length print-rep) (point) (- line-beg)) 68)
                      (insert " " print-rep)
                    (terpri)
@@ -1185,6 +1194,8 @@ it is displayed along with the global value."
                             (insert-buffer-substring pp-buffer)))))
                     ;; Remove trailing newline.
                     (and (= (char-before) ?\n) (delete-char -1)))
+                  (help-fns--editable-variable start (point)
+                                               variable val buffer)
                  (let* ((sv (get variable 'standard-value))
                         (origval (and (consp sv)
                                       (condition-case nil
@@ -1204,6 +1215,8 @@ it is displayed along with the global value."
                       (save-restriction
                         (narrow-to-region from (point))
                         (save-excursion (pp-buffer)))
+                      (help-fns--editable-variable from (point)
+                                                   variable origval buffer)
                      (if (< (point) (+ from 20))
                          (delete-region (1- from) from)))))))
            (terpri)
@@ -1236,7 +1249,9 @@ it is displayed along with the global value."
                        ;; See previous comment for this function.
                        ;; (help-xref-on-pp from (point))
                        (if (< (point) (+ from 20))
-                           (delete-region (1- from) from)))))))
+                           (delete-region (1- from) from))
+                        (help-fns--editable-variable
+                         from (point) variable global-val buffer))))))
               (terpri))
 
            ;; If the value is large, move it to the end.
@@ -1286,6 +1301,62 @@ it is displayed along with the global value."
              ;; Return the text we displayed.
              (buffer-string))))))))
 
+(defun help-fns--editable-variable (start end variable value buffer)
+  (when (and (readablep value) help-enable-variable-value-editing)
+    (add-text-properties
+     start end
+     (list 'help-echo "`e' to edit the value"
+           'help-fns--edit-variable (list variable value buffer
+                                          (current-buffer))
+           'keymap (define-keymap
+                     "e" #'help-fns-edit-variable)))))
+
+(defvar help-fns--edit-variable)
+
+(put 'help-fns-edit-variable 'disabled t)
+(defun help-fns-edit-variable ()
+  "Edit the variable under point."
+  (interactive)
+  (declare (completion ignore))
+  (let ((var (get-text-property (point) 'help-fns--edit-variable)))
+    (unless var
+      (error "No variable under point"))
+    (pop-to-buffer-same-window (format "*edit %s*" (nth 0 var)))
+    (prin1 (nth 1 var) (current-buffer))
+    (pp-buffer)
+    (goto-char (point-min))
+    (insert (format ";; Edit the `%s' variable.\n" (nth 0 var))
+            ";; C-c C-c to update the value and exit.\n\n")
+    (help-fns--edit-value-mode)
+    (setq-local help-fns--edit-variable var)))
+
+(defvar-keymap help-fns--edit-value-mode-map
+  "C-c C-c" #'help-fns-edit-mode-done)
+
+(define-derived-mode help-fns--edit-value-mode emacs-lisp-mode "Elisp"
+  :interactive nil)
+
+(defun help-fns-edit-mode-done (&optional kill)
+  "Update the value of the variable and kill the buffer.
+If KILL (the prefix), don't update the value, but just kill the
+current buffer."
+  (interactive "P" help-fns--edit-value-mode)
+  (unless help-fns--edit-variable
+    (error "Invalid buffer"))
+  (goto-char (point-min))
+  (cl-destructuring-bind (variable _ buffer help-buffer)
+      help-fns--edit-variable
+    (unless (buffer-live-p buffer)
+      (error "Original buffer is gone; can't update"))
+    (unless kill
+      (let ((value (read (current-buffer))))
+        (with-current-buffer buffer
+          (set variable value))))
+    (kill-buffer (current-buffer))
+    (when (buffer-live-p help-buffer)
+      (with-current-buffer help-buffer
+        (revert-buffer)))))
+
 (defun help-fns--run-describe-functions (functions &rest args)
   (with-current-buffer standard-output
     (unless (bolp)
index d1b9357f3c9e0296ce0e4045fa178cc6d1bc45b6..cb87035281adbb1e98a9e7e32a4ef87776798894 100644 (file)
@@ -393,7 +393,8 @@ The format is (FUNCTION ARGS...).")
 ;;;###autoload
 (define-derived-mode help-mode special-mode "Help"
   "Major mode for viewing help text and navigating references in it.
-Entry to this mode runs the normal hook `help-mode-hook'.
+Also see the `help-enable-editing' variable.
+
 Commands:
 \\{help-mode-map}"
   (setq-local revert-buffer-function