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.

NickD
  • 27,023
  • 3
  • 23
  • 42
crocefisso
  • 1,141
  • 7
  • 15
  • 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 '21 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 '21 at 18:53
  • 1
    https://emacs.stackexchange.com/tags/elisp/info – Drew Dec 19 '21 at 23:11

2 Answers2

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))))))))
c_48
  • 351
  • 1
  • 4
  • 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 '21 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 '21 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 '21 at 01:49
  • 1
    As for a list of completion candidates, I think you'll find something that works with `completing-read`. See if this answer https://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 '21 at 02:30
  • Perfect! Thank you! – crocefisso Dec 21 '21 at 07: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))))))))
crocefisso
  • 1,141
  • 7
  • 15