unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Mauro Aranda <maurooaranda@gmail.com>
To: Lars Ingebrigtsen <larsi@gnus.org>
Cc: 139@debbugs.gnu.org, jidanni@jidanni.org
Subject: bug#139: describe-key vs. widget red tape
Date: Sat, 5 Oct 2019 11:06:24 -0300	[thread overview]
Message-ID: <CABczVwcCP=5rKzGSY5DVjyFSaL5eTpy2E-S5zznRCO-Rf-5evQ@mail.gmail.com> (raw)
In-Reply-To: <874l0s8x8s.fsf@gnus.org>


[-- Attachment #1.1: Type: text/plain, Size: 1235 bytes --]

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Mauro Aranda <maurooaranda@gmail.com> writes:
>
>>> Could this also be extended to button.el buttons?
>>
>> I think so.  I'll think how to put it all together and come back with a
>> patch.  (Will be busy the next few days, but perhaps by the weekend I'll
>> be able to send it)
>
> Great!

Find in the attached patch my idea to implement this.

I wrote a command, describe-actions, so the user does not have to care
if the element to describe is either a button, a widget, or whatever.
And then, the libraries that define this kind of elements should add
themselves to `describe-actions-functions'.

Then I implemented the functions for the button.el buttons and the
widgets.

There are some things I would like to ask:
- I would like to put an initial value of nil to
`describe-actions-functions', and let each library add the function to
this list.  Is it OK to use `with-eval-after-load' here? Is there
another way?

- I put an autoload cookie in `seq-find', in order to use it in
`describe-actions'.  Is it OK?

Please review the patch and send any suggestions for improvement.  If
accepted, I'll write the documentation needed for the NEWS file and the
manual.

Best regards,
Mauro.

[-- Attachment #1.2: Type: text/html, Size: 1557 bytes --]

[-- Attachment #2: 0001-New-command-describe-actions-Bug-139.patch --]
[-- Type: text/x-patch, Size: 9454 bytes --]

From 314ad932333f6c34143d7e388809003c7b424316 Mon Sep 17 00:00:00 2001
From: Mauro Aranda <maurooaranda@gmail.com>
Date: Fri, 4 Oct 2019 13:58:11 -0300
Subject: [PATCH] New command describe-actions (Bug#139)

* lisp/help-fns.el (describe-actions-functions): New variable, to use
in describe-actions.
(describe-actions): New command, to describe the actions of an
element, like a button or widget.
* lisp/emacs-lisp/seq.el (seq-find): Add autoload cookie, so
describe-actions can use it.
* lisp/button.el (button-describe-actions): New command, to describe
the actions of a button.
(button--describe-actions-internal): Helper function for
button-describe-action.
* lisp/wid-edit.el (widget-describe-actions): New command, to describe
the actions of a widget.
(widget-resolve-parent-action): Helper function, to allow
widget-describe-actions show more useful information.
---
 lisp/button.el         | 58 +++++++++++++++++++++++++++++++++++++++++++++
 lisp/emacs-lisp/seq.el |  1 +
 lisp/help-fns.el       | 42 +++++++++++++++++++++++++++++++++
 lisp/wid-edit.el       | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 165 insertions(+)

diff --git a/lisp/button.el b/lisp/button.el
index 04e77ca..66bc12f 100644
--- a/lisp/button.el
+++ b/lisp/button.el
@@ -538,6 +538,64 @@ backward-button
   (interactive "p\nd\nd")
   (forward-button (- n) wrap display-message no-error))
 
+(defun button--describe-actions-internal (type action mouse-down-action)
+  "Describe a button's TYPE, ACTION and MOUSE-DOWN-ACTION in a *Help* buffer.
+This is a helper function for `button-describe-actions', in order to be possible
+to use `help-setup-xref'."
+  (with-help-window (help-buffer)
+    (with-current-buffer (help-buffer)
+      (insert "This button's type is ")
+      (princ type)
+      (insert "\n\n")
+      (when (functionp action)
+	(insert (propertize "Action" 'face 'bold))
+	(insert "\nThe action of this button is ")
+	(if (symbolp action)
+	    (progn
+	      (princ action)
+	      (insert ",\nwhich is ")
+	      (describe-function-1 action))
+	  (insert "\n")
+	  (princ action)))
+      (when (functionp mouse-down-action)
+	(insert (propertize "Mouse-down-action" 'face 'bold))
+	(insert "\nThe mouse-down-action of this button is ")
+	(if (symbolp mouse-down-action)
+	    (progn
+	      (princ mouse-down-action)
+	      (insert ",\nwhich is ")
+	      (describe-function-1 mouse-down-action))
+	  (insert "\n")
+	  (princ mouse-down-action))))))
+
+(defun button-describe-actions (&optional button-or-pos)
+  "Describe the actions associated to the button at point.
+Displays a *Help* buffer with a description of the actions.
+
+When called from Lisp, pass BUTTON-OR-POS as the button to describe, or a
+buffer position where a button is present.  If BUTTON-OR-POS is nil, the
+button at point is the button to describe."
+  (interactive "d")
+  (let ((button (cond ((numberp button-or-pos)
+		       (button-at button-or-pos))
+		      ((markerp button-or-pos)
+		       (with-current-buffer (marker-buffer button-or-pos)
+			 (button-at button-or-pos)))
+		      ((null button-or-pos)
+		       (button-at (point)))
+		      (t
+		       button-or-pos)))
+	action mouse-down-action type)
+    (when button
+      (setq type (button-type button)
+            action (button-get button 'action)
+	    mouse-down-action (button-get button 'mouse-down-action))
+      (help-setup-xref
+       (list #'button--describe-actions-internal type action mouse-down-action)
+       (called-interactively-p 'interactive))
+      (button--describe-actions-internal type action mouse-down-action)
+      t)))
+
 (provide 'button)
 
 ;;; button.el ends here
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index 3413cd1..f001dce 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -334,6 +334,7 @@ seq-sort-by
           (throw 'seq--break result))))
     nil))
 
+;;;###autoload
 (cl-defgeneric seq-find (pred sequence &optional default)
   "Return the first element for which (PRED element) is non-nil in SEQUENCE.
 If no element is found, return DEFAULT.
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index e9e2818d..e9d2139 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -1530,6 +1530,48 @@ describe-categories
 	(while (setq table (char-table-parent table))
 	  (insert "\nThe parent category table is:")
 	  (describe-vector table 'help-describe-category-set))))))
+\f
+;; Actions.
+
+(defvar describe-actions-functions '(button-describe-actions
+                                     widget-describe-actions)
+  "A list of functions for `describe-actions' to call.
+Each function should take one argument, a position in the buffer, and return
+non-nil if it described the actions of an element at that position.
+The argument passed might be nil, which indicates to describe the actions of
+the element at point.")
+
+;;;###autoload
+(defun describe-actions (&optional pos)
+  "Describe the actions associated to an element at a buffer position POS.
+Actions are functions that get executed when the user activates the element,
+by clicking on it, or pressing a key.  Typically, actions are associated to
+a button (e.g., links in a *Help* buffer) or a widget (e.g., buttons, links,
+editable fields, etc., of the customization buffers).
+
+Interactively, click on an element to describe its actions, or hit RET
+to describe the actions of the element at point.
+
+When called from Lisp, POS may be a buffer position, or nil, to describe the
+actions of the element at point.
+
+Traverses the list `describe-action-functions', until one of the functions
+returns non-nil."
+  (interactive
+   (list
+    (let ((key
+           (read-key
+	    "Click an element, or hit RET to describe the element at point")))
+      (cond ((eq key ?\C-m) nil)
+            ((and (mouse-event-p key)
+                  (eq (event-basic-type key) 'mouse-1)
+                  (equal (event-modifiers key) '(click)))
+             (posn-point (event-end key)))
+            ((eq key ?\C-g) (signal 'quit nil))
+            (t (user-error "You didn't specify an element"))))))
+  (unless (seq-find (lambda (fun) (when (fboundp fun) (funcall fun pos)))
+		    describe-actions-functions)
+    (message "No actions here")))
 
 \f
 ;;; Replacements for old lib-src/ programs.  Don't seem especially useful.
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index 916d41a..f8f485a 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -586,6 +586,70 @@ widget-map-buttons
       (if (and widget (funcall function widget maparg))
 	  (setq overlays nil)))))
 
+(defun widget-describe-actions (&optional widget-or-pos)
+  "Describe the actions associated to the widget at point.
+Displays a buffer with a description of the actions, as well as a link to
+browse all the properties of the widget.
+This command resolves the indirection of widgets running the action of its
+parents, so the real action executed can be known.
+
+When called from Lisp, pass WIDGET-OR-POS as the widget to describe,
+or a buffer position where a widget is present.  If WIDGET-OR-POS is nil,
+the widget at point is the widget to describe."
+  (interactive "d")
+  (require 'wid-browse)
+  (let ((widget (if (widgetp widget-or-pos)
+		    widget-or-pos
+		  (widget-at (or widget-or-pos (point)))))
+	(inhibit-read-only t) ; For erasing the contents of the buffer.
+	action mouse-down-action)
+    (when widget
+      (setq action (widget-resolve-parent-action widget)
+	    mouse-down-action (widget-get widget :mouse-down-action))
+      (help-setup-xref (list #'widget-describe-actions widget)
+		       (called-interactively-p 'interactive))
+      (with-help-window (help-buffer)
+	(with-current-buffer (help-buffer)
+	  (widget-insert "This widget's type is ")
+	  (widget-create 'widget-browse :format "%[%v%]\n%d"
+			 :doc (get (car widget) 'widget-documentation)
+			 :help-echo "Browse this widget's properties"
+			 widget)
+	  (widget-insert "\n")
+	  (when (functionp action)
+	    (widget-insert (propertize "Action" 'face 'bold))
+	    (widget-insert "\nThe action of this widget is ")
+	    (if (symbolp action)
+		(widget-create 'function-link :value action
+                               :button-prefix ""
+                               :button-suffix ""
+			       :help-echo "Describe this function")
+	      (widget-insert "\n")
+	      (princ action))
+	    (widget-insert "\n\n"))
+	  (when (functionp mouse-down-action)
+	    (widget-insert (propertize "Mouse-down-action" 'face 'bold))
+	    (widget-insert "\nThe mouse-down-action of this widget is ")
+	    (if (symbolp mouse-down-action)
+		(widget-create 'function-link :value mouse-down-action
+                               :button-prefix ""
+                               :button-suffix ""
+			       :help-echo "Describe this function")
+	      (widget-insert "\n")
+	      (princ mouse-down-action))
+	    (widget-insert "\n"))
+	  (widget-setup)
+	  (goto-char (point-min)))))))
+
+(defun widget-resolve-parent-action (widget)
+  "If action of WIDGET is `widget-parent-action', find out what would that be."
+  (let ((action (widget-get widget :action))
+	(parent (widget-get widget :parent)))
+    (while (and (eq action 'widget-parent-action)
+		(setq parent (widget-get parent :parent)))
+      (setq action (widget-get parent :action)))
+    action))
+
 ;;; Images.
 
 (defcustom widget-image-directory (file-name-as-directory
-- 
2.7.4


  reply	other threads:[~2019-10-05 14:06 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-04-14 19:25 describe-key vs. widget red tape jidanni
2019-09-30  5:56 ` bug#139: " Lars Ingebrigtsen
2019-09-30  7:31   ` Eli Zaretskii
2019-09-30  7:40     ` Lars Ingebrigtsen
2019-09-30  8:25       ` Eli Zaretskii
2019-09-30 10:54         ` Mauro Aranda
2019-09-30 10:55           ` Mauro Aranda
2019-09-30 14:57           ` Lars Ingebrigtsen
2019-09-30 20:06             ` Mauro Aranda
2019-10-01 12:29               ` Lars Ingebrigtsen
2019-10-05 14:06                 ` Mauro Aranda [this message]
2019-10-06  0:39                   ` Basil L. Contovounesios
2019-10-07  1:55                     ` Lars Ingebrigtsen
2019-10-08 13:04                     ` Mauro Aranda
2019-10-11 14:38                       ` Mauro Aranda
2019-10-11 15:23                         ` Drew Adams
2019-10-11 18:57                         ` Lars Ingebrigtsen
2020-08-07 11:16                           ` Lars Ingebrigtsen
2020-08-07 11:38                             ` Lars Ingebrigtsen
2020-10-31  1:32 ` bug#139: Still can't figure out what the command I used is called 積丹尼 Dan Jacobson
2020-10-31  2:55   ` Thien-Thi Nguyen
2020-10-31 10:33     ` 積丹尼 Dan Jacobson
2021-01-19 18:30   ` bug#139: describe-key vs. widget red tape Lars Ingebrigtsen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CABczVwcCP=5rKzGSY5DVjyFSaL5eTpy2E-S5zznRCO-Rf-5evQ@mail.gmail.com' \
    --to=maurooaranda@gmail.com \
    --cc=139@debbugs.gnu.org \
    --cc=jidanni@jidanni.org \
    --cc=larsi@gnus.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).