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
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 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
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
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
To export a snippet, highlight some code, and invoke
In the launched browser window, select all and copy:
Paste into GMail, Google Slides, or anything that will accept formatted HTML:
comments powered by Disqus