Adding Mail-Abbrev Expansion to Org-MIME

Adding Mail-Abbrev Expansion to Org-MIME

As has been already mentioned, I overcome the temptation to use one of Emacs’ mail-clients. Yet still, I frequently use message-send-mail from within Emacs with a message-body composed with org-mime-subtree. You will find org-mime in the /contrib directory of your org-mode installation. Since manually filling the mail-header is redundant especially for buffers frequently (re)used, I set related properties to the current subtree that org-mime-send-subtree will parse before creating the email buffer. Unfortunately there is no built-in completion for addresses, which is why I use the following code. Apparently it’s wise to set alias_file in Mutt and mail-personal-alias-file in Emacs to the same file. It’s probably worth pointing out that I remove the commas introduced by define-mail-alias that separate the address from the definition in an alias.

(defvar org-mime-properties '("MAIL_TO" "MAIL_CC" "MAIL_BCC")
  "Properties `org-mime-send-subtree' parses.")

(setq mail-aliases-only
      ;; first build `mail-aliases', then create a string for `org-set-property'.
      (mapconcat 'car (build-mail-aliases) " "))

;; hook to replace the alias in the property field with name and email
(defun bp/mail-property-changed (property value)
  (let ((el (cdr (assoc value mail-aliases))))
    (when (and el (member property org-mime-properties))
      (org-set-property
       property
       (replace-regexp-in-string "," "" el)))))

(nconc org-default-properties org-mime-properties)
(nconc org-global-properties
       `(("MAIL_TO_ALL"         . ,mail-aliases-only)
         ("MAIL_BCC_ALL"        . ,mail-aliases-only)
         ("MAIL_CC_ALL"         . ,mail-aliases-only)))
(add-to-list 'org-property-changed-functions
             'bp/mail-property-changed)

Custom File Order for Projectile

Custom File Order for Projectile

Recently I decided to write the occasional post in English. Obviously there are several reasons to do so as a non-native English blogger, probably the most common one being extending the audience. Since – the frequent visitor may have noticed (is there any?) – this blog lacks tracking tools and logfiles, I don’t really care about the reader (yes, talking about you). Hell, you cannot even leave comments, let alone „like“ it! Moving from Octopress to Pelican and having the removal of Mathjax and Datatables in my considerations, the blog strives not only to be puristic and elegant in appearance but also behind the scenes. Speaking of which, one year ago I put my hands on a copy of Thomas & Turner’s Clear and simple as the truth.1 Applying these writing instructions to this blog not only fits into the overall goal here, but it also serves my main purpose of writing posts in English: Write clear and simple to improve expressiveness (not only in English) and thought.

That being said, today’s post looks into one of my favorite Elisp libraries. Projectile is still my first choice when it comes to project management (though there is the standard library project.el coming up on the horizon, for now providing a project-find-regexp). I use it without the caching that is meant to adress indexing issues on Windows systems. The projectile-sort-order allows to settle on one of the sorting mechanisms provided by projectile-sort-files. For quite some time I used modification-time that almost met my expectations. Striving for a consistent development environment, I decided to apply the ido-file-extensions-order to projectile-find-file, eventually coming to know that ido-file-extension-lessp sorts by filename and extension:

(let ((ido-file-extensions-order '(".py" ".org" ".el")))
  (sort '("a.el" "b.py" "c.org") 'ido-file-extension-lessp))
("a.el" "b.py" "c.org")

So I decided to run my own thing. The following code requires seq.el, apparently I’m running emacs-major-version 25.

(defun projectile-sort-files (files)
  (pcase projectile-sort-order
    (`default files)
    (`recentf (projectile-sort-by-recentf-first files))
    (`recently-active (projectile-sort-by-recently-active-first files))
    (`modification-time (projectile-sort-by-modification-time files))
    (`access-time (projectile-sort-by-access-time files))
    (`ido-file-extensions-order
     (bp/projectile-ido-file-extensions-order files))))

(setq projectile-sort-order 'ido-file-extensions-order)

(defun bp/projectile-ido-file-extensions-order (files)
  "Sort FILES by `ido-file-extensions-order'."
  (let* ((ord
          (mapcar (lambda (s) (string-remove-prefix "." s))
                  (delq t ido-file-extensions-order)))
         (sorted (sort
                  (seq-filter
                   (lambda (f) (member (file-name-extension f) ord)) files)
                  (lambda (a b)
                    (< (seq-position ord (file-name-extension a))
                       (seq-position ord (file-name-extension b)))))))
    (append sorted (seq-difference files sorted))))

isearch-delete-word

isearch-delete-word

Mit den Worten von Steve Yegge: „Emacs Wizards try to avoid hitting the backspace key“. Ab einer gewissen Schreibgeschwindingkeit ist backward-kill-word wesentlich ökonomischer. Paradoxerweise bietet die built-in Suche Isearch nur ein isearch-delete-char. Da Isearch die Echo Area verwendet, im Minibuffer also nur eine isearch-message ausgegeben wird, ist die Umsetzung eines isearch-delete-word nicht so banal, wie man annehmen möchte. Die nachstehende Version macht Gebrauch von s.el, das Splitting berücksichtigt damit auch den Camelcase.

(defun isearch--remove-nonword-suffixes (str el)
  (if (s-ends-with? el str)
      str
    (isearch--remove-nonword-suffixes
     (substring str 0 (1- (string-width str)))
     el)))
(defun isearch--push-states-of-string (str len)
  (cl-loop
   for iter from 0 to (1- len) do
   (let* ((i (s-left iter str))
          (isearch-string i)
          (isearch-message i))
     (save-excursion
       (setf (point) (+ isearch-other-end iter))
       (push (isearch--get-state) isearch-cmds)))))
(defun bp/isearch-delete-word ()
  "Delete word in the `isearch-string'.
Split strings by whitespace, dashes, underscores and camelcase.

Push the current isearch-string to the `isearch-cmds' stack of
search status elements to allow for a subsequent
`isearch-delete-char' to further manipulate the string at hand."
  (interactive)
  ;; keep isearch prompt when string is empty
  (if (equal isearch-string "")
      (isearch-update)
    (let* ((str isearch-string)
           (lst (s-split-words str))
           (el (car (last lst)))
           (nosuf (isearch--remove-nonword-suffixes str el))
           (res (s-chop-suffix el nosuf))
           (len (string-width res)))
      (setq isearch-string res
            isearch-message res)
      (isearch--push-states-of-string str len)
      (isearch-search-and-update))))

Literate Programming mit Org-babel

Literate Programming mit Org-babel

Auf der diesjährigen EmacsConf widmete sich die Präsentation Literate DevOps dem Literate Programming aus Sicht eines Systemadministrators. Da die Verwendung der UNIX Filterfunktionen zwecks simplen Data Munging von mehreren Seiten empfohlen wird, war mein Interesse geweckt. Die Filter bilden mithilfe des Pipe Operators eine Pipeline, durch die der STDIN als Textstream ganz der UNIX Philosopie1 entsprechend geschleust wird.

Dem Konzept des Literate Programming habe ich mich zwar von der entgegengesetzten Seite, dem Reproducible Research, genähert, das Ziel ist dabei dasselbe: Nämlich ausführliche Beschreibung mit den dazugehörigen Codesnippets zu „verweben“. Was bei Literate DevOps eine engere Bindung von Dokumentation und Code zur Folge hat, sichert beim Reproducible Research die Nachvollziehbarkeit der Schlussfolgerungen. Org-mode bietet mit org-babel nicht nur die Möglichkeit, den Code unterschiedlicher Sprachen direkt im Dokument auszuführen, sondern zudem mehrere Varianten, das Resultat darzustellen. Im Gegenzug können Org-tables wiederum durch org-table-to-lisp als List dem nächsten Code Block ungeachtet dessen Sprache übergeben werden.

Im Folgenden zeige ich, wie die Syntax eines Org-Buffers für gewöhnlich aussieht. Eine ausführlichere Beschreibung des Literate Programming Modells in Org-mode findet sich in diesem Blogpost.

# -*- org-confirm-babel-evaluate: nil -*-

* Literate Programming mit org-babel
:PROPERTIES:
:var:      TSVFILE=(substitute-in-file-name "$HOME/tmp/gh-repos.tsv")
:var:      JSONFILE=(substitute-in-file-name "$HOME/tmp/gh-forks-count.json")
:cache:    yes
:END:

#+begin_src shell :results silent :exports none
curl -X GET https://api.github.com/users/KrauseFx/repos \
    | grep -P '\"(?:name|stargazers_count|language)\"' \
    | sed -e ':a;N; $!ba; s/[,:\n]//g; s/\"name\"/\n/g' \
    | sed -e 's/\"\(stargazers\_count\|language\)\"//g' \
    | tail -n+2 > $TSVFILE
#+end_src

#+name: gh-stars
#+begin_src shell :results table :exports none
cat $TSVFILE
#+end_src

(Statt der beiden sed Befehle hätte es jq auch getan bzw. hätte wohl zur Lesbarkeit beigetragen.)

Aus Sicherheitsgründen ist das Ausführen eines jeden Code Blocks zu bestätigen. Das wird insbesondere beim Exportieren des Dokuments mühsam, weshalb es sich empfiehlt, in der ersten Zeile des Buffers die dieses Verhalten beeinflussende Variable lokal auf nil zu setzen.

Durch das Festlegen der :var im PROPERTIES Ordner lässt sich die Verwendung von Environment-Variablen in Shell Blocks simulieren. Das dort ebenso gesetzte Caching garantiert, dass Code Blocks, die durch nachfolgenden Code aufgerufen werden, nur ausgeführt werden, wenn sich am Resultat etwas ändern würde. Das beugt jedenfalls diversen Redundanzen vor. Insbesondere für http Requests empfiehlt sich das Caching schon aus dem Grund, dass Github ein Limit vorgibt. In diesem Fall schreibe ich den STDOUT jedoch in eine temporäre Datei.

Der Output liefert Namen, Stars und die jeweilige Sprache der Packages des Github-Users KrauseFx. Dieser Account gehört dem jüngsten österreichischen Neuzugang bei Twitter. Aus gegebenem Anlass interessiert mich, welche Repositories einen 21-Jährigen zu einem Angestellten bei Twitter machen.

Wie eingangs erwähnt, die Daten werden als List weitergegeben. Insofern bietet es sich an, diese in Emacs Lisp zu sortieren.

(require 'dash)

(let ((table ()))
  (mapcar (lambda (x)
            (push `(,(car x)
                    ,(number-to-string (cadr x))
                    ,(caddr x))
                  table))
          (--sort (> (cadr it) (cadr other)) gh-stars))
  (append
   '(("Paketname" "Stars" "Sprache"))
   '(hline)
   (nreverse table)))
Tabelle 1 Packages von KrauseFx auf Github
Paketname Stars Sprache
TSMessages 3954 Objective-C
what-terminal-is-felix-using 101 null
danger 78 Ruby
fastrockets 15 Ruby
evaluation_report 12 null
xcode-install 3 Ruby
cocoapods-stats 1 Ruby
commander 1 Ruby
DevCenter.me 1 CSS
gitignore 1 null
gwg 1 CSS
license_checker 1 Ruby
resume 1 null
bandit-the-cat-ios-fastlane-example 0 Ruby
xcpretty 0 Ruby

Das Package, das die meisten Stars auf sich vereinen kann, ist in Objective-C geschrieben. Ruby scheint aber die am häufigsten eingesetzte Sprache zu sein. Die Tabelle lässt sich auch nach Sprachen gruppieren. Dazu gebe ich hier die Anzahl der Pakete in der jeweiligen Sprache aus:

(append
 '(("Sprache" "N"))
 '(hline)
 (--sort
  (> (cadr it) (cadr other))
  (-uniq
   (-flatten-n
    1
    (let ((res ())
          (agg
           (-group-by
            #'identity
            (--remove (string= "null" it)
                      (mapcar #'caddr table)))))
      (mapcar
       (lambda (x) (push
               `(,(car x) ,(length (cdr x)))
               res))
       agg))))))
Tabelle 2 Sortiert nach Häufigkeit der Sprache
Sprache N
Ruby 8
CSS 2
Objective-C 1

Anhand der überwiegend in Ruby geschriebenen Tools lässt sich schon erahnen, in welcher Sprache KrauseFx fastlane, womit er den Fuß in die Tür Twitters bekommen hat, verfasst hat. Bin ich nur an einer Spalte der Ausgangstabelle interessiert, kann ich das im Code Block Header spezifizieren, wie es das folgende Beispiel zeigt. Da die Ausgangstabelle durch ein #+name: gh-stars ein Label erhalten hat (zu einem benannten Code Block lässt es sich komfortabel mit C-c C-v g navigieren), lassen sich die gewünschten Daten mit dem Spaltenindex2 einer Variable zuweisen:

#+name: cblist
#+header: :var col=gh-stars[,2]
#+begin_src elisp :results value list raw :exports none
(mapcar (lambda (x) (princ (format "[ ] %s" x)))
        (-uniq col))
#+end_src

Das liefert mir die folgende Checkbox Liste, von der ich in Org-mode unmittelbar Gebrauch machen kann. Im diesem Fall streiche ich CSS manuell von der Liste:

#+RESULTS[a3a7064f37f541fde3d90eb59fb31810764adc18]: cblist
- [ ] Ruby
- [X] CSS
- [ ] null
- [ ] Objective-C

Diese Informationen kann ich wiederum in eine Tabelle einspeisen. Da :noweb idR deaktiviert ist, ändere ich den Wert im Header. Damit lässt sich mit der <<reference>> Syntax ein bestehender Code Block, der das entsprechende Label besitzt, vor Evaluieren des Code Blocks an der Stelle der Referenz expanieren (den expandierten Code kann man mit C-c C-v v begutachten). Da die Expansion vor dem Evaluieren vonstatten geht, ist im nachstehenden Code keine for Schleife einzusetzen(!):

1: echo "<<cblist()[0]>>" (zero-based)
2: echo "<<cblist()[1]>>"
3: echo "<<cblist()[2]>>"
4: echo "<<cblist()[3]>>"
Checkbox Item
[CBOFF] Ruby
[CBON] CSS
[CBOFF] null
[CBOFF] Objective-C

In einem org-src-edit-buffer besteht die Möglichkeit, einzelnen Zeilen mit C-c c bzw. C-c l ein Label zu verpassen. In der Folge kann ich auf dieses referenzieren, um beispielsweise darauf hinzuweisen, dass der Index des Code Block Labels cblist in Zeile 1 Null ist. Der Header des vorangegangenen Blocks hat ein non-nil :noweb Argument um cblist expandieren zu können, zudem ein -n für Zeilennummern:

#+begin_src shell -n :results table :noweb no-export :exports both

Mit einem -r Argument ließe sich das Label zero-based vom Source Code entfernen, ein -l legt ein spezifisches org-coderef-label-format für den Block fest 3. Nutzt man den HTML Export, so besitzt die Referenz auch ein onmouseover Event und hebt die entsprechende Zeile im Code Block hervor.

Mit dem :post Argument kann ich den Code Block mit einen „post-hook“ versehen, der zB eine vorab definierte Form ausführt, um die List nach dem Checkbox-Status zu gruppieren:

#+name: grpby
#+begin_src elisp :results value :var data="" :exports none
(-group-by (lambda (x) (string-suffix-p "N]" (car x))) data)
#+end_src

Das ohne Wert definierte data Argument wird der Form in dem Code Block überreicht, der sich den „post-hook“ zunutze macht. Im nachstehenden Beispiel nutze ich wiederum den Index – [0,] gilt der ersten Zeile – um die noch ausstehenden Checkbox-Items zu filtern:

#+begin_src elisp :results table :var tbl=cbstatus :post grpby(data=*this*)[0,]
(princ tbl)
#+end_src
Tabelle 3 Liste der ausstehenden Items
Status Sprache
[CBOFF] Ruby
[CBOFF] null
[CBOFF] Objective-C

Ist die definierte Form derart nützlich, dass ich sie für weitere Checkbox-Listen in anderen Dateien einsetzen möchte, dann steht mir die Möglichkeit offen, sie mit C-c C-v i der org-babel-library-of-babel List anzufügen und global verfügbar zu machen. Das gilt nur für die aktuelle Session, die Funktion muss Emacs bereits bekannt sein. Unter /doc/library-of-babel.org finden sich einige interessante Funktionen wie write, womit sich das Resultat eines Code Blocks direkt in eine .csv oder .tsv einspeisen lässt, oder transpose, deren Name selbsterklärend ist. Um die Blocks bestimmter Dateien grundsätzlich verfügbar zu haben, bietet sich Folgendes an:

(mapc #'org-babel-lob-ingest '("~/src/org-mode/doc/library-of-babel.org"))

Aus dem vorliegenden Buffer wäre evtl. die obige Funktion zur Aggregation der Werte in der ersten Spalte nützlich. Man könnte sie als aggregrate generalisieren, mit dem col Argument die Spalte bestimmen und mit by entweder ein Predicate oder eine Form überreichen:

#+name: aggregate
#+begin_src elisp :results table :var table='() col="" by='() :exports none
(--sort
 (> (cadr it) (cadr other))
 (-uniq
  (-flatten-n
   1
   (let ((res ())
         (agg
          (-group-by
           (if (stringp by) (read by) by)
           (mapcar (lambda (x) (nth col x)) table))))
     (mapcar
      (lambda (x) (push
              `(,(car x) ,(length (cdr x)))
              res))
      agg)))))
#+end_src

Org-babel besitzt ein eigenes Backend für HTTP Requests namens ob-http. Im Hintergrund agiert es über curl. Ich nutze es, um den forks_count jedes Pakets ausfindigzumachen und im .json Format zu speichern:

#+begin_src http :pretty json :file ~/tmp/gh-forks-count.json :exports none
GET https://api.github.com/users/KrauseFx/repos
User-Agent: ob-http
#+end_src
cat $JSONFILE | head -n 4

Diesmal mache ich Gebrauch von jq um Paketnamen und die Anzahl der Forks zu filtern. Daraufhin nutze ich die vorhin definierte aggregate Funktion:

#+name: response
#+begin_src shell :results silent
cat $JSONFILE | jq '.[] | {forks_count: .forks_count, name: .name}[]'
#+end_src
#+header: :post aggregate(table=*this*, col=1, by="identity")
#+begin_src elisp :results table :var forksc=response :exports results
(-partition 2 (-flatten forksc))
#+end_src
forks_count N
0 11
3 1
2 1
600 1
1 1

Zu guter Letzt sei auch das Integrieren des Codes in den Fließtext erwähnt: In der Version 9.0 ist org-babel dazu imstande, Resultate zu ersetzen. In der Vorgängerversion war dies nicht der Fall. Die Syntax sieht folgendermaßen aus:

...Version src_elisp[:results value]{(org-version)} {{{results(=8.3beta=)}}} ist...

Um den Wiedererkennungswert zu steigern, füge ich den Inline Code Block sowie den Inline Call Block den font-lock-keywords hinzu:

(defvar org-block #'org-block)
(defvar bp/org-babel-inline-call-block-regexp
  (concat "\\(?:^\\|[^-[:alnum:]]?\\)\\(call_\\([^ \f\t\n\r\v(]+\\)"
          "\\(\\|([ \t]*\\(.*?\\)\\))"
          "\\[\\([^\f\n\r\v\\[]+?\\)\\]\\)"))
(font-lock-add-keywords
 #'org-mode
 `((,org-babel-inline-src-block-regexp . org-block)
   (,bp/org-babel-inline-call-block-regexp . org-block)))

Auch der Inline Source Code kann mit C-c ' im org-src-edit-buffer in der jeweiligen Sprache bearbeitet werden. Inline Source Blocks bestehen derzeit völlig unabhängig von ihrem Resultat, „they are only expected to be evaluated during export“ 4. In der aktuellen Version scheint das für mich nicht der Fall zu sein. Wenn ich das in org-babel-default-inline-header-args definierte Argument für :exports auf both setze, enthält das exportierte Dokument dennoch bloß den (zwar dank htmlize mit Syntax Highlighting versehenen) Code, nicht jedoch das Resultat. Da die Resultate der Inline Blocks aber unabhängig von Source Code bestehen, kann ich diese vor dem Exportieren auch manuell im gesamten Buffer erneuern:

(org-babel-map-inline-src-blocks (buffer-file-name) (org-babel-execute-src-block))

Die hier gezeigten Beispiele sind nur ein Auszug aus den Möglichkeiten, die sich mit Org-babel eröffnen. Auf das Tangling bzw. Call Blocks bin ich beispielsweise nicht eingegangen. Das Literate Programming System in Org-mode kann zu völlig unterschiedlichen Zwecken eingesetzt werden. Hauptsächlich verwende ich es, um mithilfe von org-mime HTML Mails für monatliche Reports aufzusetzen. Darüber hinaus lässt es sich im akademischen Bereich hervorragend für Arbeiten und Präsentationen einsetzen. Und natürlich bietet es sich an, damit Blogposts in der Art des hier an ein Ende gelangenden zu schreiben. Abschließend sei zwecks Inspiration auf die Org babel reference card verwiesen.

Addenda

Da dieser Blogpost auch mir selbst als Referenz dient, werde ich hier in unregelmäßigen Abständen weitere Informationen, die mir von Bedeutung erscheinen, relativ unstrukturiert anfügen.


Das als Tabelle ausgegebene Resultat eines Code Blocks lässt sich vom selben Block als Input wiederverwenden. Damit können bestehende Tabellen erweitert werden. Dazu ist der Output zu benennen:

#+begin_src elisp :results table :var data=bench
(append
 data
 `(,(-flatten `(,(format-time-string "%Y-%m-%d")
                ,(benchmark-run
                     (let ((company-org-headings/alist '()))
                       (company-org-headings/create-alist)))))))
#+end_src

#+name: bench
#+results:
|       Date | t total (in s) | N gc |        t gc (in s) |
|------------+----------------+------+--------------------|
| 2015-11-20 |       3.831938 |    0 |                0.0 |
| 2015-11-20 |     4.07715064 |    1 | 0.3274539200000035 |
| 2015-11-21 |     3.69213816 |    0 |                0.0 |

Alternativ zum weiter oben erwähnten coderef Label, das einer zu referenzierenden Zeile des Code Blocks ein mouseover Event verpasst, könnte man auch von den org-export-filter-* Funktionen Gebrauch machen, um, nachdem htmlize seine Arbeit getan hat, HTML Tags einzufügen, die der betreffenden Zeile ein GitHub-like Highlighting verleihen. Folgendes ist dazu vonnöten:

(defun org-html-hl-line (src backend info)
  (when (org-export-derived-backend-p backend 'html)
    (replace-regexp-in-string
     "\\([^\n]+\\)\\((hl:line)\\)\n"
     "<div style=\"background-color: rgb(248, 238, 199);\">\\1\n</div>" src)))

(add-to-list 'org-export-filter-src-block-functions
             'org-html-hl-line)

Nutzen wir das von uns eigens kreierte Label in einer hervorzuhebenden Zeile, erhalten wir folgendes Resultat:

(apply
'+
'(2 4 6 8))

Insbesondere für interaktive R oder Python Sessions gilt, dass produzierte Plots häufig in einem bestimmten, dafür vorgesehenen Verzeichnis gespeichert werden. Es ändert sich in weiterer Folge bloß der Dateiname. Die Header Argumente :output-dir und :file-ext machen in Kombination mit dem Namen des jeweiligen Source Blocks das Bilden entsprechender Dateinamen relativ einfach:

#+name: filenamebase
#+header: :output-dir ~/scratch :file-ext txt :file-desc "This is an Org-link"
#+begin_src python :results output :colnames yes
print "Build " + "a " + "whole " + "sentence" + "."
#+end_src

#+results: filenamebase
This is an Org-link

Verzichten wir auf die Beschreibung des Links mit :file-desc, dann sehen wir, dass die korrekte URL gebildet wurde: file:~/scratch/filenamebase.txt. Man beachte, dass ein :file Argument die eben erwähnten Argumente außer Kraft setzt. Verzeichnis und Dateiendung könnte man der Einfachheit halber als Property für den gesamten Buffer

#+PROPERTY: header-args:python  :output-dir ~/scratch :file-ext txt

bzw. als PROPERTIES Drawer für den Subtree festlegen.


Es sei darauf hingewiesen, dass Header Argumente auch als Lisp Form übergegeben werden können. Ein konditionales Argument wie in der nachstehenden header Zeile ist daher gültig:

#+header: :exports (when (eq org-export-current-backend 'html) "none")

Interaktiv lässt sich den jeweiligen Header Argumenten einer der zur Auswahl stehenden Werte übrigens mit org-babel-header-arg-expand zuweisen. Daher habe ich folgende Form in meine erweiterte org-cycle Funktion eingebunden:

(when (and (eq (char-before) ?\:) (org-babel-where-is-src-block-head))
  (org-babel-header-arg-expand))

Im Reproducible Research mag es an mancher Stelle zum Einsatz von „Boilerplate“ Code kommen, der im jeweiligen Kontext unwesentlich erscheint oder dem Leser allzu offensichtlich ist. In diesen Fällen bietet sich das :preamble Argument an, mit dem benötigter Code unmittelbar vor den Inhalt des Codeblocks gesetzt und mit ihm ausgeführt wird. Konkret wäre das zB. für geläufige import Statements in Python denkbar:

(defconst pypreamb "import numpy as np\nimport pandas as pd")
#+begin_src python :preamble (print pypreamb)
np.mat('1 2; 3 4')
#+end_src

Sollte diese Preambel für sämtliche Python Codeblöcke übernommen werden, bietet sich die 'org-babel-default-header-args Variable an:

(add-to-list 'org-babel-default-header-args:python
             '(:preamble . "import numpy as np"))

Manchmal macht es Sinn, den Output eines nicht erfolgreich ausgeführten Shell Blocks dennoch auszugeben. Mit dem :epilogue ;: Header Argument wird der Exit Status letztlich auf 0 gesetzt und damit verhindert, dass Org-Babel beim Ausführen des Blocks direkt in den Debugger springt:

#+begin_src shell :results output :epilogue ;:
echo "some output";
definitely fails when evaluated
#+end_src

#+results:
: some output

  1. „Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.“ – faqs.org
  2. Indexable variable values
  3. http://orgmode.org/manual/Literal-examples.html
  4. http://org-babel.readthedocs.org/en/latest/eval/#inline-code-blocks

Simple Footnotes für Org-export

Simple Footnotes für Org-export

Pelican, der Python-basierte Static Site Generator meiner Wahl, verwendet das dem gleichnamigen WordPress Plugin nachempfundene Simple Footnotes. Unterstützt wird u.a. Markdown, das ich in einer Vielzahl älterer Blogposts, die lange vor der Migration zu Pelican entstanden sind, verwendet habe. org-html-publish-to-html generiert allerdings Fußnoten in einem eigenen Format, das insbesondere durch die Funktion org-html-format-footnote-definition vorgegeben wird. Da ich die ordered list in Simple Footnotes vorziehe und um Konsistenz meines Blogs besorgt bin, überschreibe ich die Funktion folgendermaßen:

(defun org-html-format-footnote-definition--override (fn)
  (let ((n (car fn)) (def (cdr fn)))
    (format
     "<div class=\"footnote\">%s </div>\n"
     (format "<li>%s %s</li>"
             def
             (let* ((id (format "fn.%s" n))
                    (href (format " href=\"#fnr.%s\"" n))
                    (attributes
                     (concat
                      " class=\"footnote-backref\"" href
                      (format
                       " title=\"Jump back to footnote %s in the text\"" n)
                      " rev=\"footnote\"")))
               (org-html--anchor id "↩" attributes))))))
(advice-add #'org-html-format-footnote-definition :override
            #'org-html-format-footnote-definition--override)

Ergänzend ist aus org-html-footnote-section der eingefügte Paragraph Tag zu entfernen. Des Weiteren generiert der org-export ein eigenes Heading auch wenn Fußnoten inline definiert werden. Dem lässt sich mit simplem Auskommentieren begegnen:

(setf org-html-footnotes-section
      "<div id=\"footnotes\"><!--%s--><hr></hr><ol>%s</ol></div>")

Näheres zur Definition von Fußnoten in Org-mode findet sich im Manual (das hier zu Präsentationszwecken als Fußnote verlinkt ist)1.

Update 2015-11-15 So:

Das angeführte Setup gilt für die Org-mode Version 8.3beta. Beim heutigen Umsatteln auf die aktuelle Git Version 8.3beta durfte ich feststellen, dass sich in org-footnote.el einiges getan hat. Nachstehender Code sollte Simple Footnotes wiederum ermöglichen:

(setf org-html-footnotes-section
      (concat
       "<div id=\"footnotes\" class=\"footnote\">"
       "<!--%s--><hr></hr><ol>%s</ol></div>"))
(defun org-html-footnote-section--override (info)
  (let* ((fn-alist (org-export-collect-footnote-definitions info))
         (fn-alist
          (loop for (n _type raw) in fn-alist collect
                (cons n (org-trim (org-export-data raw info))))))
    (when fn-alist
      (format
       (plist-get info :html-footnotes-section)
       (org-html--translate "Footnotes" info)
       (format
        "%s"
        (mapconcat
         (lambda (fn)
           (let ((n (car fn)) (def (cdr fn)))
             (format
              "<li>%s %s</li>"
              def
              (org-html--anchor
               (format "fn.%d" n)
               "↩"
               (format
                (concat
                 " class=\"footnote-backref\" "
                 "href=\"#fnr.%d\" "
                 "rev=\"footnote\" "
                 "title=\"Jump back to footnote %d in the text\" "
                 "name=\"fn.%d\"") n n n)
               info))))
         fn-alist "\n"))))))
(advice-add 'org-html-footnote-section :override
            #'org-html-footnote-section--override)

Fancy Code Blocks mit minted und tcolorbox

Fancy Code Blocks mit minted und tcolorbox

Wie sich an der Gestaltung dieses Blogs erahnen lässt, nehme ich gerne mithilfe einer dezenten Hintergrundfarbe eine visuelle Trennung von Code Blocks und dem übrigen Inhalt vor. In der rechten oberen Ecke weise ich der Vollständigkeit halber auch die verwendete Programmiersprache aus. In etwa diese Darstellung hatte ich bereits für den Source Code in meiner Diplomarbeit vor dem geistigen Auge, scheiterte jedoch einerseits am Zeitdruck, andererseits am mangelnden Verständnis für LaTeX. Einige Monate später bin ich hierfür doch noch auf eine interessante Kombination gestoßen, die sich zudem als ausgesprochen flexibel erweist. Mithilfe der Pakete minted und tcolorbox definiere ich nachstehendes neues environment namens bpbox:

\newtcolorbox{bpbox}[2][]
{%
  enhanced,
  colbacktitle=TealBlue,
  coltitle=black,
  interior style={%
    top color=SkyBlue,
    bottom color=SkyBlue!40
  },
  boxrule=0.1mm,
  arc=0.6mm,
  width= (\linewidth-10mm),
  fonttitle=\footnotesize,
  adjusted title=\texttt{#1},
  after title={%
    \hfill\setlength{\fboxsep}{1.5pt}
    \colorbox{MidnightBlue!20}{\textcolor{Black}
      {\footnotesize{\texttt{#2}}}}
  },
  overlay={%
    \begin{tcbclipinterior}\fill[MidnightBlue!20] (frame.south west)
      rectangle ([xshift=5mm]frame.north west);
    \end{tcbclipinterior}
  },
  top=0mm,
  bottom=0mm,
  left=5mm,
  right=0mm,
  shadow={0.7mm}{-0.7mm}{0mm}{black!20}
}

Mit \newminted lässt sich zudem auch ein neues environment für (in diesem Fall) Python erstellen:

\newminted{py}{%
  linenos,
  fontsize=\footnotesize,
  numbersep=7pt
}

Kombiniert ergibt sich daraufhin das nachstehende .pdf. Die Farbkombination mag verbesserungswürdig sein, fürs Erste ging es mir bloß darum, den Machbarkeitsnachweis zu erbringen. Ein vollständiges MWE befindet sich in diesem Gist.

\begin{bpbox}[Some Title]{python}
  \begin{pycode}
cmd  = Popen([emacsclient, "-e", lisp],
             stdout=PIPE,
             shell=False,
             )
cmd.communicate()
return
  \end{pycode}
\end{bpbox}
tcolorbox.png
Abbildung 1: LaTeX Code Block mit minted und tcolorbox

Task-tree Organisation mit Org-clock

Task-tree Organisation mit Org-clock

Als einer der interessantesten Aspekte des Emacs Org-mode, der letztlich bei einem großen Projekt wie der Thesis dabei geholfen hat, mich nicht bei einzelnen Kapiteln oder sonstigen Aufgaben in für das Gesamtresultat unwesentlichen Details zu verzetteln, hat sich die Zeitnahme erwiesen. Während Org-mode naturgemäß ein diesbezüglich ausschweifendes Setup gestattet, möchte ich hier bloß auf die Variablen org-clock-in-switch-to-state und org-clock-out-switch-to-state eingehen: Beide akzeptieren eine Funktion mit dem aktuellen Todo Status als Parameter und dem gewünschten Todo Keyword als Rückgabewert. Da es sich um eine Funktion handelt, können wir beiläufig einige Nebeneffekte herbeiführen.

Während ich meine Aufgaben gerne als Projekte organisiere, zugleich aber Projekte oftmals aus einzelnen Todo Einträgen, die, während ich mich mit ihnen befasse, den ein oder anderen Subtask erhalten, entstehen, möchte ich sie ohne weiteres Zutun nach bestimmten Regeln definieren. Nachstehende Funktion erlaubt es, bei einem org-clock-in einen Task-tree als solchen auszumachen und einen fehlenden PROJECT Status zu setzen. Zugleich verhindere ich verschachtelte Projekte und schütze bestimmte Todo Status wie beispielsweise HABIT. Der aktuelle Task Status wird, sofern nicht geschützt, auf CLOCKED gesetzt. Das gesamte Setup lebt u.a. davon, dass durch org-todo-state-tags-triggers ein Projekt mit einem entsprechenden project Tag versehen und dieser dank org-use-tag-inheritance auf die Subtasks angewandt wird. Außerdem verwende ich in meinen Org Dateien kontextuelle Überschriften ohne Todo Status.

(defvar bp/safe-todo-states '("PROJECT" "PHONE" "HABIT")
  "Todo states that must not change when clocking the respective task.
Skips tasks in `org-capture-mode'.")
(defun bp/clock-out-to-hold (x)
  "Switch a task to HOLD when clocking out."
  (unless (or (and (boundp 'org-capture-mode) org-capture-mode)
              (member (org-get-todo-state) bp/safe-todo-states))
    "HOLD"))
(defun bp/clock-in-to-next (x)
  "Switch a task to CLOCKED when clocking in.
Skips tasks in `org-capture-mode'. Looks for the contextual
parent heading with no `org-get-todo-state' and turns the task
one level below into a PROJECT."
  (when (not (and (boundp 'org-capture-mode) org-capture-mode))
    (save-restriction
      (widen)
      (let* ((this-level (funcall outline-level))
             (sibl-level (save-excursion
                           (outline-next-heading)
                           (funcall outline-level)))
             (has-sibl? (> sibl-level this-level))
             (cont-parent-l
              ;; `nil' when heading has inherited the project tag
              ;; prevents me from building nested projects
              (unless (member "project" (org-get-tags-at (point)))
                (save-excursion
                  (while (org-get-todo-state)
                    (org-up-heading-safe))
                  (funcall outline-level))))
             (next-state (lambda (x)
                           (if (member (org-get-todo-state)
                                       bp/safe-todo-states)
                               (org-get-todo-state)
                             x))))
        (if (and has-sibl?
                 cont-parent-l
                 (= 1 (- this-level cont-parent-l)))
            (funcall next-state "PROJECT")
          (when (and
                 cont-parent-l
                 (> this-level cont-parent-l))
            (unless (= this-level (1+ cont-parent-l))
              (save-excursion
                (outline-up-heading
                 (- this-level cont-parent-l 1))
                (org-todo (funcall next-state "PROJECT")))))
          (funcall next-state "CLOCKED"))))))
(setq
 org-clock-in-switch-to-state 'bp/clock-in-to-next
 org-clock-out-switch-to-state 'bp/clock-out-to-hold)

Ein Beispiel macht die Funktionalität am ehesten verständlich. Ein möglicher Task-tree in der Ausgangssituation mag so aussehen:

* Contextual Heading
** TODO level 1
*** TODO level 2
**** TODO level 3

Naturgemäß sind die Aufgaben in einer solchen Struktur von innen nach außen zu bewältigen. Beginnt man also mit dem Level 3 Task mit einem org-clock-in, wird das Level 1 TODO in ein Projekt umgewandelt:

* Contextual Heading
** PROJECT level 1 :project:
*** TODO level 2
**** CLOCKED level 3 :clocked:
:LOGBOOK:
CLOCK: [2015-09-01 Di 15:28]
:END:

Da die Subtasks den :project: Tag erben, setzt die Funktion das Definieren eines Projekts aus, sollte der Tag bereits vorhanden sein. Dasselbe gilt für den Fall, dass der Level 1 Task einen geschützten Todo Status besitzt. Wird die aktuelle Aufgabe mit einem org-clock-out unterbrochen, erhält sie den HOLD Status.

Dieses Setup ist bewusst relativ simpel gehalten, der Ausbaufähigkeit sind aber, wie so oft in Emacs, keine Grenzen gesetzt.

← Newer    Older →