Exporting Formatted Code Snippets from Emacs
rayo - 13 Jun 2014
I wanted a way to create formatted code snippets (syntax highlighting, etc.) for pasting into GMail or Google Slides. The catch was I didn't want to use a web service (e.g. pastie, hilite.me) or switch from Emacs to another text editor (e.g. Sublime with the SublimeHighlight plugin).
Learning from Markdown-Mode
I remembered that Emacs markdown-mode lets you preview, in a browser, the Markdown text rendered as HTML.
Basically, when you install markdown-mode, you also install a Markdown executable like Python-Markdown. When you invoke markdown-preview in Emacs, markdown-mode runs the Markdown executable in a shell. The input is the Markdown text in the current Emacs region, and the HTML output goes to a temporary Emacs buffer. The buffer's contents, in turn, are opened in a browser by the Emacs command browse-url-of-buffer.
Pygments to the Rescue
We could use a similar strategy to markdown-mode's for exporting formatted code snippets. We just need a command-line tool that will receive code from stdin and send it formatted to stdout.
Pygments fits the bill. Pygments is a syntax higlighter written in Python, with many lexers and formatting options. It can be installed using pip (e.g. pip install pygments).
Lisp Isn't So Painful
After installing Pygments, you get a script called pygmentize. Of course to call it from Emacs, you'll need some Lisp. Here's a helper that constructs the desired invocation:
26 (defun pygmentize-html-command (beginning-line-number)
27 (let ((lexer (gethash major-mode pygmentize-lexers))
28 (linenostart (number-to-string beginning-line-number)))
29 (if (not lexer) (error (concat "error: no lexer for " (symbol-name major-mode))))
30 (concat "pygmentize -f html"
31 " -l " lexer
32 " -O style=autumn,linenos=inline,noclasses=true,linenostart=" linenostart)))
A lookup table maps Emacs major-modes to their lexer argument for pygmentize:
16 (setq pygmentize-lexers (make-hash-table))
17 (puthash 'emacs-lisp-mode "common-lisp" pygmentize-lexers)
18 (puthash 'scala-mode "scala" pygmentize-lexers)
19 (puthash 'java-mode "java" pygmentize-lexers)
20 (puthash 'ruby-mode "rb" pygmentize-lexers)
21 (puthash 'python-mode "py" pygmentize-lexers)
22 (puthash 'sh-mode "sh" pygmentize-lexers)
23 (puthash 'diff-mode "diff" pygmentize-lexers)
The Emacs clip region is passed via stdin to pygmentize, with stdout redirected to a temporary buffer:
38 (defun pygmentize-html (&optional output-buffer-name)
39 (interactive)
40 (save-window-excursion
41 (unless output-buffer-name
42 (setq output-buffer-name pygmentize-html-output-buffer-name))
43 (let* ((beginning-line-number (line-number-at-pos (region-beginning)))
44 (shell-command (pygmentize-html-command beginning-line-number)))
45 (shell-command-on-region (region-beginning)
46 (region-end)
47 shell-command
48 output-buffer-name))
49 (switch-to-buffer output-buffer-name)
50 (clipboard-kill-ring-save (point-min) (point-max))
51 output-buffer-name))
The temporary buffer's syntax-highlighted, HTML-formatted contents will be opened in a browser, using Emacs's browse-url-of-buffer function:
53 (defun pygmentize-html-preview (&optional output-buffer-name)
54 (interactive)
55 (unless output-buffer-name
56 (setq output-buffer-name pygmentize-html-output-buffer-name))
57 (browse-url-of-buffer (pygmentize-html output-buffer-name)))
Gotta have a keybinding:
59 (global-set-key (kbd "C-c h p") 'pygmentize-html-preview)
Exporting the Snippets
This gist contains the full Emacs-Lisp code. (And it easily embeds into a .emacs file.)
To export a snippet, highlight some code, and invoke pygmentize-html-preview:

In the launched browser window, select all and copy:

Paste into GMail, Google Slides, or anything that will accept formatted HTML:
