0

I have an org file containing reference cards on keyboard shortcuts that I continuously edit. Each ref card is a table belonging to a headline.

Here are the first headlines of the file, as an example:

* Emacs
** Help
   #+name: e-help
   |------------------------------------+---------+------------------------------------------------------|
   | Keybinding                         | Command | Description                                          |
   |------------------------------------+---------+------------------------------------------------------|
   | =describe-key-briefly=             | =C-h c= | Display the command name run by a given key sequence |
   | =describe-bindings=                | =C-h b= | Display all key bindings                             |
   | =view-echo-area-messages=          | =C-h e= | Go to the Messages buffer                            |
   | =describe-key=                     | =C-h k= | Display the full documentation for the key sequence. |
   | =Info-goto-emacs-key-command-node= | =C-h K= | Show manual’s section for the command bound to KEYS. |
   | =view-lossage=                     | =C-h l= | Show last 300 input keystrokes                       |
   | =describe-symbol=                  | =C-h o= | Show given function or var’s documentation & value.  |
   | =where-is=                         | =C-h w= | Display which keystrokes invoke the given command    |
   |------------------------------------+---------+------------------------------------------------------|

** Windows
   #+name: e-windows
   |---------------+---------------------------------------+----------------------------------|
   | Keybinding    | Command                               | Description                      |
   |---------------+---------------------------------------+----------------------------------|
   | =Esc Esc Esc= | =keyboard-escape-quit=                | Exit current "mode               |
   | =C-M △=       | =mda/prior-window=                    | Cycle prior window               |
   | =C-M ▽=       | =other-window=                        | Cycle next window                |
   | =M △=         | =scroll-other-window-down=            | Scroll next window downward      |
   | =M ▽=         | =scroll-other-window=                 | Scroll next window upward        |
   | =C-x 0=       | =delete-window=                       | Delete the selected window       |
   | =C-x 1=       | =delete-other-windows=                | only one window                  |
   | =C-x +=       | =balance-windows=                     | Make all windows the same height |
   | =C-x 2=       | =split-window-below=                  | split horizontal                 |
   | =C-x 3=       | =split-window-right=                  | split vertical                   |
   | =C-x -=       | =shrink-window-if-larger-than-buffer= | Shrink current window optimally  |
   |---------------+---------------------------------------+----------------------------------|

** Buffers
   #+name: e-buffers
   |---------------+------------------------------+--------------------------------------------|
   | Keybinding    | Command                      | Description                                |
   |---------------+------------------------------+--------------------------------------------|
   | =C △=         | =bs-cycle-previous=          | Cycle prior user buffer                    |
   | =C ▽=         | =bs-cycle-next=              | Cycle next user buffer                     |
   | =C-x b=       | =switch-to-buffer=           | Select any open buffer                     |
   | =C-x C-s=     | =save-buffer=                | Save buffer                                |
   | =C-x C-w=     | =write-file=                 | Save buffer as                             |
   | =C w=         | =kill-this-buffer=           | Close current buffer                       |
   | =C-x s=       | =save-some-buffers=          | Save all buffers                           |
   |---------------+------------------------------+--------------------------------------------|
   | =C-x C-b=     | =list-buffers=               | Shows the file paths of all opened buffers |
   | =C-u M-! pwd= |                              | Pastes the current file path in the buffer |
   | =C-x C-d=     | =list-directory=             | Display path of the current file           |
   |---------------+------------------------------+--------------------------------------------|
   | =C-x C-c=     | =save-buffers-kill-terminal= | quit emacs                                 |
   |---------------+------------------------------+--------------------------------------------|

I'm trying to build a function that would open a buffer, in a new horizontal window, containing a given ref card (table). But Unfortunately I'm very far from the goal.

3
  • Are the two buffers supposed to be independent, so that the second buffer contains the state of the table at the time the buffer was created? Or are they supposed to be linked so that when you make a change in one, the change appears in the other?
    – NickD
    Dec 19, 2021 at 18:14
  • Yes, they are supposed to be independent. The new buffer is supposed to be a refcard that I would call when I need to remember a keybinding, a function, or anything. This new memo buffer doesn't have to be editable it's just a reminder. I'd edit the ref cards normally by opening the org file that contains them.
    – crocefisso
    Dec 19, 2021 at 18:53
  • 1
    emacs.stackexchange.com/tags/elisp/info
    – Drew
    Dec 19, 2021 at 23:11

2 Answers 2

1

You could use a combination of org-element-parse-buffer and org-element-map to parse the contents of your org file, and select the table whose :name property matches a string argument.

The following should be a fully functional base, from which you can build on and customize:

(defun display-custom-help-buffer (help-type)
  "Display custom help table named HELP-TYPE from /path/to/custom-help.org"
  (with-temp-buffer
    (insert-file-contents "/path/to/custom-help.org")
    (org-element-map (org-element-parse-buffer) 'table
      (lambda (table)
        (when (string-equal (org-element-property :name table) help-type)
          (with-current-buffer (get-buffer-create "*custom-help*")
            (erase-buffer)
            (display-buffer "*custom-help*")
            (insert (org-element-interpret-data table))))))))

Output of (display-custom-help-buffer "e-help") in separate buffer:

#+name: e-help
|------------------------------------+---------+------------------------------------------------------|
| Keybinding                         | Command | Description                                          |
|------------------------------------+---------+------------------------------------------------------|
| =describe-key-briefly=             | =C-h c= | Display the command name run by a given key sequence |
| =describe-bindings=                | =C-h b= | Display all key bindings                             |
| =view-echo-area-messages=          | =C-h e= | Go to the Messages buffer                            |
| =describe-key=                     | =C-h k= | Display the full documentation for the key sequence. |
| =Info-goto-emacs-key-command-node= | =C-h K= | Show manual’s section for the command bound to KEYS. |
| =view-lossage=                     | =C-h l= | Show last 300 input keystrokes                       |
| =describe-symbol=                  | =C-h o= | Show given function or var’s documentation & value.  |
| =where-is=                         | =C-h w= | Display which keystrokes invoke the given command    |
|------------------------------------+---------+------------------------------------------------------|

As an interactive function with a prompt for table name:

(defun display-custom-help-buffer (help-type)
  "Display custom help table named HELP-TYPE from /path/to/custom-help.org"  
  (interactive "sHelp table to display: ")
  (with-temp-buffer
    (insert-file-contents "/path/to/custom-help.org")
    (org-element-map (org-element-parse-buffer) 'table
      (lambda (table)
        (when (string-equal (org-element-property :name table) help-type)
          (with-current-buffer (get-buffer-create "*custom-help*")
            (erase-buffer)
            (display-buffer "*custom-help*")
            (insert (org-element-interpret-data table))))))))
5
  • Thank you @c_48, your function did the trick. I managed to customize display-buffer in order to have the new window on top instead of right. However, I am not able to make the function appear with M-x
    – crocefisso
    Dec 20, 2021 at 23:51
  • Would it be possible to have a command prompting for table name (with table list available through TAB) and opening the window once table name is inserted?
    – crocefisso
    Dec 20, 2021 at 23:55
  • 1
    To make the function appear with M-x display-custom-help-buffer, you'll need to add (interactive) on the line above (with-temp-buffer ... To prompt for a table name to display, include something like (interactive "sHelp table to display: "). The input will then become the help-type variable.
    – c_48
    Dec 21, 2021 at 1:49
  • 1
    As for a list of completion candidates, I think you'll find something that works with completing-read. See if this answer emacs.stackexchange.com/a/32251 or reading through M-x describe-function RET completing-read gets you in the right direction.
    – c_48
    Dec 21, 2021 at 2:30
  • Perfect! Thank you!
    – crocefisso
    Dec 21, 2021 at 7:32
0

Here is my implementation of c_48 solution. Say the org file where the tables are is called cardref.org, located in ~/.

The following code will automatically retrieve tables names so that they will appear with TAB when the mda/refcard function is executed.

(setq refnames (with-temp-buffer
                 (insert-file-contents "~/cardref.org")
                 (org-element-map (org-element-parse-buffer) 'table (lambda (element) (org-element-property :name  element)))))
(defun mda/refcard (refcard)
  (interactive
   (let ((completion-ignore-case  t))
     (list (completing-read "Press TAB and arrows to select refcard: " refnames nil t))))
  "Display custom help table named refcard from cardref.org"
  (with-temp-buffer
    (insert-file-contents "~/cardref.org")
    (while (re-search-forward "=" nil t)
      (replace-match ""))
    (org-element-map (org-element-parse-buffer) 'table
      (lambda (table)
        (when (string-equal (org-element-property :name table) refcard)
          (with-current-buffer (get-buffer-create "*Reference Card*")
            (erase-buffer)
            (display-buffer "*Reference Card*"
                            '(display-buffer-in-direction
                              (direction . top)
                              (window-height . fit-frame-to-buffer)))
            (insert (org-element-interpret-data table))))))))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.