Over the weekend I thought about this issue of configuring `org-speed-commands' more easily, and I believe I have come up with a simpler solution that I have provided in the attached patch.
This patch creates a new function `org-speed-command-add' that can be used to add new speed command shortcuts to `org-speed-commands', as well as modify existing shortcuts. This function takes as argument an alist in the same format as `org-speed-commands'. For each command for which the shortcut key is already present in `org-speed-commands', the old command is replaced with the new command at the same position. Commands with brand new shortcut keys are added to the user section of `org-speed-commands'. I believe this patch strikes a balance between power users, who can still directly customize `org-speed-commands', and non-experts, who may want to add/modify some speed commands without having to understand the structure and organization of `org-speed-commands'. Shankar On Wed, Nov 24, 2021 at 10:36 AM Shankar Rao <shankar....@gmail.com> wrote: > > Hello all, > > I discovered that upgrading to 9.5 broke my configuration because the > variable `org-speed-commands-user' was removed. I read the thread > (https://list.orgmode.org/87v9hzzhrn....@gmail.com/) where this change > was proposed and I completely agree that exposing the whole set of > `org-speeds-commands' to the user for customization is an improvement > over the previous state of affairs. However, I believe there were some > unintended consequences of this change that can make it difficult to > customize `org-speed-commands' for users that are not elisp gurus. > > The main problem is that `org-speed-commands' serves two purposes > simultaneously: > > 1.) It contains all the mappings between speed keys and commands > 2.) It contains headlines for command categories. > > Because of this second purpose, both the contents and order of entries > in `org-speed-commands' are important. For example, suppose I want to > replace the usual "n" command with my own. According to the usual > conventions for alists > (https://www.gnu.org/software/emacs/manual/html_node/elisp/Association-Lists.html), > new associations such as this are added to the front of the list. But > if I do so, by doing something like: > > (setq org-speed-commands (cons '("n" . #'my-org-next-heading) > org-speed-commands)) > > Then the speed key "n" will show up twice when > `org-speed-command-help' is invoked. I could first delete the old > association by replacing `org-speed-commands' in the above with > `(assoc-delete-all "n" org-speed-commands)', but then my modified > command will no longer appear in the "Outline Navigation" section of > the speed command help. Alternatively, I could replace the association > for "n" using `alist-get': > > (setf (alist-get "n" org-speed-commands nil nil #'equal) > #'my-org-next-heading) > > However, this solution won't work for new speed commands (e.g., if I > want to bind `my-org-next-heading' to "N" instead), because in that > case `alist-get' will return `nil'. > > Below is the relevant portion of my config file where I customize > `org-speed-commands': > ----- > (defun alist-set (key value alist-symbol &optional testfn) > "Set KEY to VALUE in alist referenced by ALIST-SYMBOL. > > If KEY is not present in the alist, then add (KEY. VALUE) to the > front of the alist. Compare keys with TESTFN. Defaults to equal." > (if-let ((keyval (assoc key (eval alist-symbol) testfn))) > (setf (cdr keyval) value) > (set alist-symbol (cons (cons key value) (eval alist-symbol))))) > > > (defvar sbr-org-speed-commands-user '(("User Custom Speed Commands") > ("N" . > ded-org-show-next-heading-tidily) > ("P" . > ded-org-show-previous-heading-tidily) > ("h" . > sbr-org-speed-insert-subheading) > ("u" . org-up-heading-or-item) > ("b" . org-backward-heading-or-item) > ("f" . org-forward-heading-or-item) > ("p" . org-prev-heading-or-item) > ("n" . org-next-heading-or-item)) > "My custom Org speed commands") > > (dolist (keyval (reverse sbr-org-speed-commands-user)) > (alist-set (car keyval) (cdr keyval) 'org-speed-commands)) > ----- > > As you can see, I defined my own function `alist-set', which modifies > an association in an alist if the key is already present, or adds the > new association to the front of the list otherwise. In my opinion, > functionality like `alist-set' should be built into Emacs itself. My > code then constructs my own list of custom speed commands with its own > section header and uses `alist-set' to add/modify speed commands. > While this code works, it's a bit unsatisfying because > > 1.) It relies on my custom `alist-set' function > 2.) It relies on knowledge of the structure of `org-speed-commands' > > More specifically, it requires that my new speed commands need to be > inserted in reverse order into `org-speed-commands' in order to be > displayed properly in `org-speed-commands-help'. > > I don't know what is the best solution to enable Org users to add > and/or modify speed commands while also keeping the display of > `org-speed-commands-help' organized. Here is what I propose: > > 1.) Keep the whole set of `org-speed-commands' exposed to user > customization for power users > 2.) Bring back `org-speed-commands-user', but instead of just > appending it to `org-speed-commands' as was done prior to Org 9.5, use > something like my `alist-set' above to add/modify speed command > associations as needed while preserving the display order in > `org-speed-commands-help'. > > With my proposal, Org users wouldn't have to concern themselves with > the section headers in `org-speed-commands', but they would still be > able to add/modify/remove commands as they wish. > > Let me know if anyone has a simpler alternative to achieve these > goals. If there is sufficient interest in my proposal, I would be > happy to provide a patch. > > Thanks, > Shankar
From 90684137340f3c60ed6a31815a1063a90079441e Mon Sep 17 00:00:00 2001 From: Shankar Rao <shankar.rao@gmail.com> Date: Tue, 30 Nov 2021 14:30:51 +0100 Subject: [PATCH] Add function org-speed-command-add to add/modify speed commands org-keys.el: Add function org-speed-command-add to add/modify speed commands * lisp/org-keys.el (org-speed-command-add): Create a function that adds new speed commands or modifies existing speed commands in `org-speed-commands'. Speed commands whose shortcut key is already present in `org-speed-commands' are replaced at the same position, while speed commands with brand new shortcut keys are added to the user section of `org-speed-commands'. --- doc/org-manual.org | 7 ++++--- etc/ORG-NEWS | 9 ++++++++- lisp/org-keys.el | 22 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 19f42fc77..f8b13973d 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -18941,9 +18941,10 @@ headline, before any of the stars. #+vindex: org-speed-commands #+findex: org-speed-command-help Org comes with a pre-defined list of Speed Keys. To add or modify -Speed Keys, customize the option ~org-speed-commands~. For more -details, see the variable's docstring. With Speed Keys activated, -{{{kbd(M-x org-speed-command-help)}}}, or {{{kbd(?)}}} when point is at the +Speed Keys, one can either use the function ~org-speed-command-add~ or +directly customize the option ~org-speed-commands~. For more details, +see the variable's docstring. With Speed Keys activated, {{{kbd(M-x +org-speed-command-help)}}}, or {{{kbd(?)}}} when point is at the beginning of an Org headline, shows currently active Speed Keys, including the user-defined ones. diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index e618feb9a..c39af5226 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -94,7 +94,14 @@ argument. ~org-get-tags~ now accepts Org element or buffer position as first argument. - +*** New function ~org-speed-command-add~ to add/modify Org speed commands + +This function takes an alist of speed commands in the same format as +~org-speed-commands~ and adds these speed commands to +~org-speed-commands~. If the letter for a speed command is already +present in ~org-speed-commands~, then the new speed command overwrites +the previous command at the same position. Otherwise, the new command +is added to the user section of ~org-speed-commands~. ** Miscellaneous *** New =transparent-image-converter= property for =dvipng= diff --git a/lisp/org-keys.el b/lisp/org-keys.el index 103456526..f5d69701b 100644 --- a/lisp/org-keys.el +++ b/lisp/org-keys.el @@ -819,6 +819,28 @@ command." (with-current-buffer "*Help*" (setq truncate-lines t))) +(defun org-speed-command-add (command-list) + "Add speed commands in COMMAND-LIST to ``org-speed-commands''. + +COMMAND-LIST is an alist of speed commands with the same format +as ``org-speed-commands''. If a command in COMMAND-LIST is +already present in ``org-speed-commands'', then the new command +replaces the old command at the same position. Otherwise, the new +command is added to the user section of +``org-speed-commands''." + (let* ((title "User Speed Commands") + (has-user-section (assoc title org-speed-commands)) + (new-commands nil)) + (dolist (command command-list) + (if-let ((keyval (assoc (car command) org-speed-commands))) + (setf (cdr keyval) (cdr command)) + (push command new-commands))) + (when new-commands + (setq org-speed-commands (append (unless has-user-section + (list (list title))) + (nreverse new-commands) + org-speed-commands))))) + (defun org-speed-move-safe (cmd) "Execute CMD, but make sure that the cursor always ends up in a headline. If not, return to the original position and throw an error." -- 2.25.1