7

I'm using Emacs to write code samples that I later want to be able to paste into a MS-Word document, preserving the syntax highlighting. I understand that in order to do this I need to copy the text in either RTF or HTML format.

Currently I'm just killing from Emacs into http://www.tohtml.com and then copying from there and pasting into Word. It strikes me that someone, somewhere has probably written some Lisp to make this process at least a couple of keystrokes shorter, but I can't seem to find any existing solution or anything in the docs that suggests this is even possible.

So I'm keen to know if there is a ready made solution I can include in my config or if anyone has any pointers about how I could write something to achieve this.

I'm fairly new to Emacs, loving it, but my e-Lisp is currently very basic.

xlbloke
  • 71
  • 1
  • 3

4 Answers4

6

The htmlize package can do this. Install it with M-x package-install htmlize and you get access to the commands htmlize-region

(htmlize-region BEG END)

Convert the region to HTML, preserving colors and decorations.

and htmlize-region-for-paste

(htmlize-region-for-paste BEG END)

Htmlize the region and return just the HTML as a string. This forces the ‘inline-css’ style and only returns the HTML body, but without the BODY tag. This should make it useful for inserting the text to another HTML buffer.

erikstokes
  • 12,686
  • 2
  • 34
  • 56
6

The package https://github.com/Lindydancer/highlight2clipboard does exactly what you asked for. It use htmlize to create a HTML version of the text which it adds as an alternative paste text. (Note: This is a non-trivial operation which requires interfacing with the clipboard. This is operating system specific, currently OS X and MS-Windows are supported.)

When pasting into applications like MS-Word, the syntax highlighting is retained.

Lindydancer
  • 6,095
  • 1
  • 13
  • 25
2

I have this custom elisp function which I use to convert a selected region or the whole buffer to syntax fontified HTML.

(defvar modi/htmlize-output-directory
  (let ((dir (concat temporary-file-directory
                     (getenv "USER") "/.htmlize/"))) ; must end with /
    (make-directory dir :parents)
    dir)
  "Output directory for files exported by `modi/htmlize-region-to-file'.")

(defvar modi/htmlize-css-file (concat user-emacs-directory
                                      "misc/css/leuven_theme.css")
  "CSS file to be embedded in the html file created using the
             `modi/htmlize-region-to-file' function.")

(defun modi/htmlize-region-to-file (option)
  "Export the selected region to an html file. If a region is not
selected, export the whole buffer.

The output file is saved to `modi/htmlize-output-directory' and its fontification
is done using `modi/htmlize-css-file'.

If OPTION is non-nil (for example, using `\\[universal-argument]' prefix), copy
the output file name to kill ring.
If OPTION is \\='(16) (using `\\[universal-argument] \\[universal-argument]' prefix),
do the above and also open the html file in the default browser."
  (interactive "P")
  (let ((org-html-htmlize-output-type 'css)
        (org-html-htmlize-font-prefix "org-")
        (fname (concat modi/htmlize-output-directory
                       (if (buffer-file-name)
                           (file-name-nondirectory (buffer-file-name))
                         "temp")
                       ".html"))
        start end html-string)
    (if (use-region-p)
        (progn
          (setq start (region-beginning))
          (setq end (region-end)))
      (progn
        (setq start (point-min))
        (setq end (point-max))))
    (setq html-string (org-html-htmlize-region-for-paste start end))
    (with-temp-buffer
      ;; Insert the `modi/htmlize-css-file' contents in the temp buffer
      (insert-file-contents modi/htmlize-css-file nil nil nil :replace)
      ;; Go to the beginning of the buffer and insert comments and
      ;; opening tags for `html', `head' and `style'. These are
      ;; inserted *above* the earlier inserted css code.
      (goto-char (point-min))
      (insert (concat "<!-- This file is generated using the "
                      "`modi/htmlize-region-to-file' function\n"
                      "from https://github.com/kaushalmodi/.emacs.d/"
                      "blob/master/setup-files/setup-org.el -->\n"))
      (insert "<html>\n<head>\n<style media=\"screen\" type=\"text/css\">\n")
      ;; Go to the end of the buffer (end of the css code) and
      ;; insert the closing tags for `style' and `head' and opening
      ;; tag for `body'.
      (goto-char (point-max))
      (insert "</style>\n</head>\n<body>\n")
      ;; Insert the HTML for fontified text in `html-string'.
      (insert html-string)
      ;; Close the `body' and `html' tags.
      (insert "</body>\n</html>\n")
      (write-file fname)
      (when option
        (kill-new fname)
        (when (= 16 (car option))
          (browse-url-of-file fname))))))

Here are few points about the modi/htmlize-region-to-file function:

  • If the region is selected, only that region will be exported to an HTML file in modi/htmlize-output-directory directory.
  • If no region is selected, the whole buffer will be exported.
  • It requires ox-html (org-mode HTML exporter) as it uses org-html-htmlize-region-for-paste function which uses the htmlize package behind the scenes and also allows customizing how to associate CSS with the HTML code for fontification.
  • It is able to fontify code based on the css file specified by modi/htmlize-css-file variable. To use this function right-away you can save this custom leuven theme based css file somewhere and set this variable to that file path. If you use that css file, the exported code will always have the Leuven theme regardless of your emacs theme (which was my sole purpose for writing this function).
  • I would recommend installing the region-bindings-mode package. With that installed, you simply select the region you want to export and hit H... Voila! Your code will be saved to an HTML file in modi/htmlize-output-directory.

    (with-eval-after-load 'region-bindings-mode
        (define-key region-bindings-mode-map (kbd "H") #'modi/htmlize-region-to-file))
    
  • If you do C-u H, it will export the code and copy the output file name to the kill-ring.

  • If you do C-u C-u H instead, it will do the above and also open the HTML file it in your default browser using the browse-url-of-file function.

Below is what I got in my web browser when I did C-u C-u H on part of the above code:

enter image description here

NOTE: I need to save the HTML to a file. Saving the HTML annotated code just to the clipboard will not work for me because I don't know how to convert html code in clipboard directly to rendered html when pasting in Outlook/Word.

Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179
1

ESH can do this:

  • Clone the ESH repository, and add (add-to-list 'load-path "/path/to/the/repo") to your .emacs.
  • Use M-x load-library RET esh RET to load ESH
  • Open your code file, run M-x esh-htmlfontify-display (this opens a browser displaying a webpage generated (locally) by ESH).
  • Copy from the browser into your application.
Clément
  • 3,924
  • 1
  • 22
  • 37