I'm wondering if there is a way to add hyperlinks to noweb references,
i.e., 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></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"><<</span>first<span class="org-operator">-</span>fragment<span class="org-operator">>></span>
<span class="org-operator"><<</span>second<span class="org-operator">-</span>fragment<span class="org-operator">>></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: first-fragment, second-fragment</i>
</p>
</div>
</body>
</html>
Related
I use Emacs' org-mode to take notes in class, which I then export in latex. I found org-mode's default markers for bold and italic (* and / respectively) quite useful, but I had to stop using them to avoid confusing the org exporter. I would like to have a function to italicize a word selection. In other words, the function should append \textit{ and } respectively to the beginning and to the end of a selection.
Org has a function, defined in org.el, that does this, called org-emphasize (the code is posted below), but it is constructed to work only with the org markers. Unfortunately, I am not very proficient in elisp to modify it to do what I want.
Any suggestions on how to go about building my desired function, would be greatly appreciated. Thank you, all!
(defun org-emphasize (&optional char)
"Insert or change an emphasis, i.e. a font like bold or italic.
If there is an active region, change that region to a new emphasis.
If there is no region, just insert the marker characters and position
the cursor between them.
CHAR should be the marker character. If it is a space, it means to
remove the emphasis of the selected region.
If CHAR is not given (for example in an interactive call) it will be
prompted for."
(interactive)
(let ((erc org-emphasis-regexp-components)
(string "") beg end move s)
(if (org-region-active-p)
(setq beg (region-beginning)
end (region-end)
string (buffer-substring beg end))
(setq move t))
(unless char
(message "Emphasis marker or tag: [%s]"
(mapconcat #'car org-emphasis-alist ""))
(setq char (read-char-exclusive)))
(if (equal char ?\s)
(setq s ""
move nil)
(unless (assoc (char-to-string char) org-emphasis-alist)
(user-error "No such emphasis marker: \"%c\"" char))
(setq s (char-to-string char)))
(while (and (> (length string) 1)
(equal (substring string 0 1) (substring string -1))
(assoc (substring string 0 1) org-emphasis-alist))
(setq string (substring string 1 -1)))
(setq string (concat s string s))
(when beg (delete-region beg end))
(unless (or (bolp)
(string-match (concat "[" (nth 0 erc) "\n]")
(char-to-string (char-before (point)))))
(insert " "))
(unless (or (eobp)
(string-match (concat "[" (nth 1 erc) "\n]")
(char-to-string (char-after (point)))))
(insert " ") (backward-char 1))
(insert string)
(and move (backward-char 1))))
I do not know if it worth defining a new lisp function. This is mainly a LaTeX problem as described here: https://tex.stackexchange.com/questions/258394/make-block-of-text-italicized
You can transpose this solution to Org as follow. First, observe how Org special blocks:
#+BEGIN_mySpecialBlock
...
#+END_mySpecialBlock
are exported to LaTeX
\begin{mySpecialBlock}
...
\end{mySpecialBlock}
(see Org doc Special-blocks-in-LaTeX-export for further details)
Then define new LaTeX environments as:
#+LATEX_HEADER: \newenvironment{itquote} {\begin{quote}\itshape} {\end{quote}\ignorespacesafterend}
#+LATEX_HEADER: \newenvironment{itpars} {\par\itshape} {\par}
#+LATEX_HEADER: \newenvironment{bfquote} {\begin{quote}\bfseries} {\end{quote}\ignorespacesafterend}
#+LATEX_HEADER: \newenvironment{bfpars} {\par\bfseries} {\par}
The lipsum LaTeX package is used to generate some dummy text.
#+LATEX_HEADER: \usepackage{lipsum}
You can test the approach with this Org document
#+LATEX: \lipsum[66]
#+BEGIN_bfquote
#+LATEX: \lipsum[66]
#+END_bfquote
#+BEGIN_bfpars
#+LATEX: \lipsum[66]
#+END_bfpars
#+BEGIN_itquote
#+LATEX: \lipsum[66]
#+END_itquote
#+BEGIN_itpars
#+LATEX: \lipsum[66]
#+END_itpars
After LaTeX export, C-c C-e l o, you will get something like:
For a better clarity here is the complete Org document. For a real document remove all references to lipsum which is only the text generator.
#+LATEX_HEADER: \newenvironment{itquote} {\begin{quote}\itshape} {\end{quote}\ignorespacesafterend}
#+LATEX_HEADER: \newenvironment{itpars} {\par\itshape} {\par}
#+LATEX_HEADER: \newenvironment{bfquote} {\begin{quote}\bfseries} {\end{quote}\ignorespacesafterend}
#+LATEX_HEADER: \newenvironment{bfpars} {\par\bfseries} {\par}
#+LATEX_HEADER: \usepackage{lipsum}
#+TITLE: My Title
* My section
#+LATEX: \lipsum[66]
#+BEGIN_bfquote
#+LATEX: \lipsum[66]
#+END_bfquote
#+BEGIN_bfpars
#+LATEX: \lipsum[66]
#+END_bfpars
#+BEGIN_itquote
#+LATEX: \lipsum[66]
#+END_itquote
#+BEGIN_itpars
#+LATEX: \lipsum[66]
#+END_itpars
In Sublime Text one can select a block of code based on indentation:
(Selection -> Expand Selection to Indentation)
For example in the following block of code and cursor at position being
marked here:
<header>
<nav>
<ul>
<li id='link-main'><a href='#'>Main site</a></li>
<li class='stupid'><a href='#'>About Us</a></li>
<li class='stupid'>History</li>
<CURSOR_HERE>
<div>
<div>
</div>
</div>
<li>Contact</li>
</ul>
</nav>
</header>
This will result in this selection (marked by <SELECTION> and </SELECTION>)
<header>
<nav>
<ul>
<SELECTION><li id='link-main'><a href='#'>Main site</a></li>
<li class='stupid'><a href='#'>About Us</a></li>
<li class='stupid'>History</li>
<div>
<div>
</div>
</div>
<li>Contact</li></SELECTION>
</ul>
</nav>
</header>
How can I achieve the same thing using emacs?
If you use Evil, here's an evil plugin evil-indent-textobject can select (or yank/delete) a block based of indentation.
I don't know about indentation-based selection, but expand region does semantic expansion:
Expand region increases the selected region by semantic units. Just keep pressing the key until it selects what you want.
Expand region is available on MELPA.
(defun ar-backward-indent ()
"Go backward same or deeper levels of indentation. "
(interactive)
(let ((orig (point))
(indent (progn (back-to-indentation) (current-column)))
(last (point)))
(while (and (not (bobp))(forward-line -1) (progn (back-to-indentation) (<= indent (current-indentation))))
(setq last (point)))
(goto-char last)))
(defun ar-forward-indent ()
"Go backward same or deeper levels of indentation. "
(interactive)
(let ((indent (progn (back-to-indentation) (current-column)))
last)
(while
(and (not (eobp)) (forward-line 1) (progn (back-to-indentation) (<= indent (current-indentation))))
(setq last (line-end-position)))
(goto-char last)))
(defun ar-mark-indent-level ()
"Mark lines around point where indentation is equal or deeper. "
(interactive)
(let ((orig (point)))
(ar-backward-indent)
(push-mark (point) t)
(goto-char orig)
(ar-forward-indent)))
Source: https://github.com/andreas-roehler/subroutines
First we have to check if point is on a line with 0 indentation, if it is select whole buffer.
If point is on a line with some indentation, select all lines which have same or less indentation.
(defun expand-to-indentation ()
"Select surrounding lines with current indentation."
(interactive)
(let ((indentation (current-indentation)))
(if (= indentation 0)
(mark-whole-buffer)
(while (<= indentation (current-indentation))
(forward-line -1))
(forward-line 1)
(push-mark (point) nil t)
(while (<= indentation (current-indentation))
(forward-line 1))
(backward-char))))
You can call this function interactively or you can bind it to any key.
Based on #ChillarAnand 's answer, I'm using below for myself:
(defun mark-current-indentation (&optional ARG)
"Select surrounding lines with current indentation.
if ARG is 'C-u', mark forward; if ARG is 'C-u C-u', mark backward."
(interactive "P")
(let ((is-forward (not (equal ARG '(16))))
(is-backward (not (equal ARG '(4))))
(indentation (if (not (current-line-empty-p))
(current-indentation)
(skip-chars-forward "\s\t\n")
(current-indentation))))
(if (= indentation 0)
(mark-whole-buffer)
(if (not is-forward) (push-mark (point) nil t))
(while (and (not (bobp)) is-backward
(or (current-line-empty-p) (<= indentation (current-indentation))))
(forward-line -1))
(if is-backward (forward-line 1) (move-beginning-of-line nil))
(if (not (use-region-p)) (push-mark (point) nil t))
(while (and (not (eobp)) is-forward
(or (current-line-empty-p) (<= indentation (current-indentation))))
(forward-line 1))
(if is-forward (backward-char)))))
I'm using org-mode for organizing myself (very useful so far!). However, it is kind of annoying writting
#+begin_comment
...
#+end_comment
each time I'd like to insert an environment.
Question
Is there a shortcut to insert the #+begin_ and #+end_ for a given environment?
In the same way C-c C-o comment RET would insert
\begin{comment}
\end{comment}
in latex-mode.
Org has a facility called "Easy templates": http://orgmode.org/manual/Easy-Templates.html
A template for comment is missing but you can add it with:
(add-to-list 'org-structure-template-alist '("C" "#+begin_comment\n?\n#+end_comment"))
And use it by typing <C followed by TAB.
Alternatively, you could use yasnippet.
Now the corresponding template section is called Structure Template and the insertion sequence is invoked by C-c C-,. I didn't (require 'org-tempo) which is described to support insertion keys like <s TAB.
The comment environment is already defined in org-structure-template-alist. So the comment would be inserted by
C-c C-, C
It's still possible to add a user defined sequence by, for example,
C-c C-, [TAB|RET|SPC] src python :results output :session
delivering
#+begin_src python :results output :session
#+end_src
(emacs 25.2.2, org-mode 9.2)
You could have a look at "org-auctex-keys.el", a minor mode which I created to offer AUCTeX key bindings within Org documents.
In this case, you'd use C-c C-e to insert an environment (prompt to enter the environment name), as what AUCTeX does.
If you're interested, check it out at https://github.com/fniessen/org-auctex-key-bindings.
Not as elegant as the answer of Michael Markert but maybe more expandable.
1) You can select a region and put the block around it or you can just put the block at point.
2) Keyword expansion and history.
3) Keystrokes: C-c b
The command could be further expanded. E.g., for the src block the various switches like -n -r and export to files could be supported.
(defun list-major-modes ()
"Returns list of potential major mode names (without the final -mode).
Note, that this is guess work."
(interactive)
(let (l)
(mapatoms #'(lambda (f) (and
(commandp f)
(string-match "-mode$" (symbol-name f))
;; auto-loaded
(or (and (autoloadp (symbol-function f))
(let ((doc (documentation f)))
(when doc
(and
(let ((docSplit (help-split-fundoc doc f)))
(and docSplit ;; car is argument list
(null (cdr (read (car docSplit)))))) ;; major mode starters have no arguments
(if (string-match "[mM]inor" doc) ;; If the doc contains "minor"...
(string-match "[mM]ajor" doc) ;; it should also contain "major".
t) ;; else we cannot decide therefrom
))))
(null (help-function-arglist f)))
(setq l (cons (substring (symbol-name f) 0 -5) l)))))
(when (called-interactively-p 'any)
(with-current-buffer (get-buffer-create "*Major Modes*")
(clear-buffer-delete)
(let ((standard-output (current-buffer)))
(display-completion-list l)
(display-buffer (current-buffer)))))
l))
(defvar org-insert-block-hist nil
"History for command `org-insert-block'")
(defvar org-insert-block-hist/src:major nil
"History for major mode in org src blocks.")
(defvar org-insert-block-list (append org-protecting-blocks
'("comment" ""))
"List of block types offered as completion for command `org-insert-block'")
;; block_src switches: -n () -r (references) -l "((%s))" (label format) -k (keep labels)
(defvar org-insert-block-list-specials
"Assoc list of Commands for reading additional specification of org-blocks.")
(setq org-insert-block-list-specials
'(("src" . (concat " " (completing-read "Major mode:"
(list-major-modes)
nil nil
(car org-insert-block-hist/src:major)
'(org-insert-block-hist/src:major . 1)
)))))
(defun org-insert-block (bl &optional b e attributes)
"Put region between b and e into org-block of kind bl.
If b or e is nil then put org-block limiters around point.
The string attributes is inserted behind the string #+begin_... "
(interactive
(let ((usereg (use-region-p))
(blKind (completing-read "Input block kind (tab: completion, uparrow: history):"
org-insert-block-list nil nil (car org-insert-block-hist) '(org-insert-block-hist . 1))))
(list
blKind
(when usereg (region-beginning))
(when usereg (region-end))
(let ((spec (assoc blKind org-insert-block-list-specials)))
(when spec (eval (cdr spec)))
))))
(let ((begBlock (concat "\n#+begin_" bl attributes "\n"))
(endBlock (concat "\n#+end_" bl "\n")))
(if (and b e)
(save-restriction
(narrow-to-region b e)
(goto-char (point-min))
(insert begBlock)
(goto-char (point-max))
(insert endBlock)
(indent-region (point-min) (point-max)))
(let ((p (point)))
(insert endBlock)
(goto-char p)
(insert begBlock))
)))
(add-hook 'org-mode-hook '(lambda ()
(local-set-key (kbd "C-c b") 'org-insert-block)))
There are Tags as in #+AUTHOR or #+LATEX in org-mode - are they called tags? I'd like to define my own tag which calls a function to preprocess the data and then outputs it - if the export target is LaTeX.
My solution was defining an own language, qtree, for SRC blocks.
#+BEGIN_SRC qtree
[.CP [.TP [.NP [] [.N' [.N Syntax] []]] [.VP [] [.V' [.V sucks] []]]]]
#+END_SRC
And process it accordingly. I even added a qtree-mode with paredit.
And a landscape parameter if the trees grow big. https://github.com/Tass/emacs-starter-kit/blob/master/vendor/assorted/org-babel-qtree.el
(require 'org)
(defun org-babel-execute:qtree (body params)
"Reformat a block of lisp-edited tree to one tikz-qtree likes."
(let (( tree
(concat "\\begin{tikzpicture}
\\tikzset{every tree node/.style={align=center, anchor=north}}
\\Tree "
(replace-regexp-in-string
" \\_<\\w+\\_>" (lambda (x) (concat "\\\\\\\\" (substring x 1)))
(replace-regexp-in-string
(regexp-quote "]") " ]" ; qtree needs a space
; before every closing
; bracket.
(replace-regexp-in-string
(regexp-quote "[]") "[.{}]" body)) ; empty leaf
; nodes, see
; http://tex.stackexchange.com/questions/75915
) ; For
; http://tex.stackexchange.com/questions/75217
"\n\\end{tikzpicture}"
)))
(if (assoc :landscape params)
(concat "\\begin{landscape}\n" tree "\n\\end{landscape}")
tree)))
(setq org-babel-default-header-args:qtree '((:results . "latex") (:exports . "results")))
(add-to-list 'org-src-lang-modes '("qtree" . qtree))
(define-generic-mode
'qtree-mode ;; name of the mode to create
'("%") ;; comments start with '%'
'() ;; no keywords
'(("[." . 'font-lock-operator) ;; some operators
("]" . 'font-lock-operator))
'() ;; files for which to activate this mode
'(paredit-mode) ;; other functions to call
"A mode for qtree edits" ;; doc string for this mode
)
They seem to be called keywords for in-buffer settings no more. Whatever they're called, they don't seem to be user-definable.
What you want to do is extremely related to a common way of handling whereas to export with xelatex or pdflatex as described on Worg.
The relevant part would be :
;; Originally taken from Bruno Tavernier: http://thread.gmane.org/gmane.emacs.orgmode/31150/focus=31432
(defun my-auto-tex-cmd ()
(if (string-match "YOUR_TAG: value1" (buffer-string))
(do something))
(if (string-match "YOUR_TAG: value2" (buffer-string))
(do something else))
(add-hook 'org-export-latex-after-initial-vars-hook 'my-auto-tex-cmd)
I'm trying to generate the following html code using cl-who:
<html>
<body>
<div id="cnt_1"></div>
<div id="cnt_2"></div>
<div id="cnt_3"></div>
</body>
</html>
And here's the code that I thought would work:
(with-html-output-to-string (*standard-output* nil)
(:html
(:body
(do ((cnt 1 (+ cnt 1)))
((> cnt 3))
(htm (:div :id (format t "cnt_~A" cnt)))))))
But instead I get the following output:
<html><body><divcnt_1></div><divcnt_2></div><divcnt_3></div></body></html>
Seems like :id does not work with function calls. Does it mean that I can't use format in cl-who? What should I use instead?
That's because you don't want to write directly in the stream.
CL-USER> (with-html-output-to-string (s) (:div :id "test"))
"<div id='test'></div>"
CL-USER> (with-html-output-to-string (s)
(:html
(:body
(do ((cnt 1 (+ cnt 1)))
((> cnt 3))
(htm (:div :id (format nil "cnt_~A" cnt)))))))
"<html><body><div id='cnt_1'></div><div id='cnt_2'></div><div id='cnt_3'></div></body></html>"
By the way, if you want to write directly in the stream use CL-WHO:FMT.