简体   繁体   中英

How to create hyperlinks for noweb references in org-mode

I'm wondering if there is a way to add hyperlinks to noweb references, ie, in the following org-mode snippet:

#+name: list-all
#+begin_src sh
ls -a
#+end_src

and we come here

#+begin_src sh :noweb no-export :tangle myscript.sh
echo "Hello world"

<<list-all>>
#+end_src

When exporting to html or latex, I would like to have the <<list-all>> to be a link to the code block being referenced by it. I have noticed that this is the case in some noweb implementations other than org-modes' one. I've checked the documentation and I don't seem to find anything about this. This would be an invaluable feature to have.

I'm not able to put the links within the src block (for that you probably need to add a filter to org-export-filter-src-block-functions : the filter, however, needs to work with the exported format).

However, I am happy with this solution I implemented after having read this reddit post .

Example

Let's say you have this org file:

#+name: first-fragment
#+begin_src python
  x=1
#+end_src

Some text.

#+name: second-fragment
#+begin_src python
  y=2
#+end_src

Some text.

#+name: to-be-tangled
#+begin_src python :noweb no-export :tangle program.py
  <<first-fragment>>
  <<second-fragment>>
  print(f'{x} and {y}')
#+end_src

Then I can export it to html with this elisp code:

(require 'ox-html)
(load (concat default-directory "htmlize.el"))
(require 'htmlize)

(setq make-backup-files nil
      org-html-doctype "html5"
      org-html-html5-fancy t
      org-html-style-default ""
      org-html-htmlize-output-type 'css
      org-html-validation-link nil
      org-html-postamble t
      org-html-postamble-format '(("en" "")))

(defun first-group-match (regex string)
  "Return the substring matching the first group in REGEX,
   together with the ending point in STRING.

   The result is a cons cell (MATCH . POSITION).
   "
  (save-match-data
    (if (string-match regex string)
        (cons (substring string (match-beginning 1) (match-end 1)) (match-end 1))
      nil)
    )

  )

(defun all-string-matches (regex string)
  "Return a list of all group matches."
  (if (< (length string) 5)
      nil
    (let* ((match (first-group-match regex string))
           (name (car match))
           (end-name (if name (cdr match) -1))
           (next (all-string-matches regex
                                     (substring string end-name))))
      (if name
          (cons name next)
        next))))

(defun get-noweb-links (block)
  "Get all the <<>> references as a list."
  (cl-loop for name in
           (all-string-matches "<<\\([^<>\n]+\\)>>" (org-element-property :value block))
           collect
           (format "[[%s][%s]]" name name)))

(defun append-refs (block refs)
  "Append to BLOCK a line with REFS."
  (let ((begin (org-element-property :begin block))
        (end (org-element-property :end block))
        (string (format "\n/This code refers to: %s/\n\n" refs)))
    (goto-char (+ added-characters (org-element-property :end block)))
    (insert string)
    (setq added-characters (+ added-characters (length string)))))


(defun add-references (_)
  "Add a line with referenced blocks to all src blocks that contains noweb links."
  (let ((src-blocks (org-element-map (org-element-parse-buffer) 'src-block
                      (lambda (b) b))))
    (cl-loop for b in src-blocks do
             (when (string-match "<<[^<>\n]+>>" (org-element-property :value b))
               (append-refs b (string-join (get-noweb-links b) ", "))))))


(setq added-characters 0)
(add-hook 'org-export-before-parsing-functions 'add-references)

(dolist (file command-line-args-left)
  (with-current-buffer
      (find-file-literally file)
    (org-html-export-to-html)))

Resulting in this:

<!DOCTYPE html>
<html lang="en">
<head>
<!-- 2022-12-10 sab 10:32 -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>&lrm;</title>
<meta name="author" content="eMMe" />
<meta name="generator" content="Org Mode" />
</head>
<body>
<div id="content" class="content">
<div class="org-src-container">
<pre class="src src-python" id="org121b865"><span class="org-variable-name">x</span><span class="org-operator">=</span>1
</pre>
</div>

<p>
Some text.
</p>

<div class="org-src-container">
<pre class="src src-python" id="orga7322c4"><span class="org-variable-name">y</span><span class="org-operator">=</span>2
</pre>
</div>

<p>
Some text.
</p>

<div class="org-src-container">
<pre class="src src-python" id="orgcde0461"><span class="org-operator">&lt;&lt;</span>first<span class="org-operator">-</span>fragment<span class="org-operator">&gt;&gt;</span>
<span class="org-operator">&lt;&lt;</span>second<span class="org-operator">-</span>fragment<span class="org-operator">&gt;&gt;</span>
<span class="org-builtin">print</span>(f<span class="org-string">'</span>{x}<span class="org-string"> and </span>{y}<span class="org-string">'</span>)
</pre>
</div>

<p>
<i>This code refers to: <a href="#org121b865">first-fragment</a>, <a href="#orga7322c4">second-fragment</a></i>
</p>
</div>
</body>
</html>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM