0

Lately I have been writing a lot of literate sysadmining, writing down my thoughts as I explore systems by executing commands on them. This means that I end up writing the following boilerplate over and over again:

#+begin_src bash :dir /ssh:<some-remote-machine>:/

#+end_src

I usually just copy this snippet and bring it back from the kill ring whenever needed, but it grows tiresome if you mix this with other operations that populate the kill ring.

It would be handy if I could bring this back using some keybinding or snippet. The shell of a yasnippet doing this would look like:

#+begin_src ${1: `(some (code (finding-the-last-used-header-args)))`

#+end_src

But for my specific purposes perhaps having only the hostname being picked up would be better, like:

#+begin_src bash :dir /ssh:${1: `(code-finding-the-hostname)`:/

#+end_src

The result of invoking either one of these snippets in the same buffer as the first code example but below it would result in the exact same text being produced again.

I hope this explains what I'm looking for well enough.

2 Answers 2

4

You can set header arguments in Org mode properties (see (org) Using Header Arguments) to avoid repeating, for example, all code blocks in this org file will have :dir /tmp

#+PROPERTY: header-args :dir /tmp

#+BEGIN_SRC sh
pwd
#+END_SRC

#+RESULTS:
: /private/tmp

I also have the following command in my init file, it duplicates the last src block's header, it shows you can use Org Mode's API to access src block's header arguments

(defun chunyang-org-babel-copy-previous-src-block ()
  "Copy previous src block excluding the content."
  (interactive)
  (let (result)
    (save-excursion
      (org-babel-previous-src-block)
      (let ((element (org-element-at-point)))
        (when (eq (car element) 'src-block)
          (let* ((pl (cadr element))
                 (lang (plist-get pl :language))
                 (switches (plist-get pl :switches))
                 (parms (plist-get pl :parameters)))
            (setq result
                  (format
                   (concat "#+begin_src %s\n"
                           "\n"
                           "#+end_src\n")
                   (mapconcat #'identity
                              (delq nil (list lang switches parms))
                              " ")))))))
    (and result (insert result))
    (previous-line 2)))
0

I want to begin by thanking you xuchunyang so much for your answer. In order to understand how the code worked I broke it down into some smaller functions.

(defun org-previous-source-block-headers ()
  "Returns the previous source block's headers."
  (save-excursion
    (org-babel-previous-src-block)
    (let ((element (org-element-at-point)))
      (when (eq (car element) 'src-block)
        (let* ((content  (cadr element))
               (lang     (plist-get content :language))
               (switches (plist-get content :switches))
               (parms    (plist-get content :parameters)))
          (delq nil (list lang switches parms)))))))

(defun org-previous-source-block-headers-string ()
  "Returns the previous source block's headers as a string."
  (mapconcat #'identity
             (org-previous-source-block-headers)
              " "))

(defun org-previous-source-block-without-content ()
  "Returns the previous source block, except its contents."
  (format
   (concat "#+begin_src %s\n"
           "\n"
           "#+end_src\n")
   (org-previous-source-block-headers-string)))

(defun org-repeat-previous-source-block-without-content ()
  "Inserts the previous source block, except the actual code in
the block, into the buffer."
  (interactive)
    (when-let (result (org-previous-source-block-without-content))
      (insert result)
      (previous-line 2)))

What drove this breakdown was me trying to create a yasnippet from it. I ended up with the following.

# -*- mode: snippet -*-
# name: Repeat last source block without content
# key: <r
# --
#+begin_src `(org-previous-source-block-headers-string)`
$1
#+end_src

This snippet does exactly what chunyang-org-babel-copy-previous-src-block does, but is invoked by typing <r and pressing TAB instead of some other keybinding.

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.