6

I have discovered the noweb syntax, and in particular how it can be used in org source blocks, very recently, and I have grown quite fond of it.

But inserting the references (is there a better term?) seems to be unnecessarily painful: it seems that I have to either remember the name of the source block I want to link to.

My current workflow for long references is to insert a space after << and use dabbrev-expand (which requires that I choose unique-enough prefixes).

I could certainly scrap together a completion feature automating this, or add a completion source scanning #+name and #+srcname. However, I do not like duplicating work (yes I am very lazy), and with all the completion features offered by org and 3rd-party packages, it strikes me as odd that nothing seems to provide completion for noweb references.

Are there any way of inserting noweb references with completion? And if not, is there a good reason for that?


MWE.org:

#+srcname: snippet-with-an-annoyingly-long-name
#+begin_src emacs-lisp
(message "Hello")
#+end_src

#+begin_src emacs-lisp
;; I would like to be able to insert the line below with the help of completion
<<snippet-with-an-annoyingly-long-name>> 
#+end_src

2 Answers 2

3

I think there is already a parser for src block names in org-babel-src-block-names returning a list. The following provides programmed completion for that list:

(defun org-src-block-names--completion-function (str pred action)
  (let ((tbl (org-babel-src-block-names)))
    (pcase action
      (`nil (try-completion   str tbl pred))
      (`t   (all-completions  str tbl pred))
      (`metadata
       '(metadata (annotation-function . org-src-block-names--get-lang))))))

(defun org-src-block-names--get-lang (lang)
  (concat " " (car-safe (org-babel-lob--src-info lang))))

(defun org-src-block-names-completion-at-point-function ()
  (when (and (looking-back "<<\\([-a-z]+\\)")
             (eq (org-element-type (org-element-at-point)) 'src-block))
    (list
     (match-beginning 1)
     (point)
     'org-src-block-names--completion-function
     :exclusive 'no
     :annotation-function 'org-src-block-names--get-lang)))

The :annotation-function property in the completion function is an extra property that the company-capf backend for company-mode uses to add some additional information (the src block's language in this case).

To actually use it in your org buffer with the completion-at-point command, you have to add the completion function to a special hook:

(add-hook 'completion-at-point-functions
          'org-src-block-names-completion-at-point-function)
2

This is only a partial solution, but the dabbrev-expand method can be greatly improved by modifying the syntax table so that < and > are treated as delimiters:

(modify-syntax-entry ?< "(>" org-mode-syntax-table)
(modify-syntax-entry ?> ")<" org-mode-syntax-table)

This means that you don't have to go back and insert a space before using M-/, although you do still need to manually type the closing >>. And of course the completion candidates are not specifically restricted to noweb references.

I should also mention that I haven't checked if hacking the syntax table in this way doesn't produce subtle breakage in other org-mode features, so use it at your own risk!

Your Answer

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

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