Elisp Lesson: Writing make-html-table

Xah Lee, 2008-04

This page shows a example of writing a emacs lisp function that turns the current block of text into a HTML table. If you don't know elisp, first take a look at Emacs Lisp Basics.

The Problem

I want to write a function, such that, when called, the current block of text the cursor is on, becomes a HTML table. Suppose the block of text is this:

a  b  c
1  2  3
this  and  that

after, pressing a button, it should become:

<table border="1" cellpadding="5" cellspacing="0">
<tr><td>a</td><td>b</td><td>c</td></tr>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>this</td><td>and</td><td>that</td></tr>
</table>

and is rendered in browser like this:

abc
123
thisandthat

Solution

The problem will have 3 major steps:

First, we do step 2. We write a function that takes 2 argument: a text block as string, and a separator as string, and return htmlized version of the text block.

This may sound complicated, but it is easily done by replacing the separator in the text block by “</td><td>, and wrap each line by “<tr><td>” and “</td></tr>”, then wrap a “<table>” and “</table>” around the whole block.

The primary function we'll use for this is “replace-regexp-in-string”. Here's the code:

(defun make-html-table-string (textblock delim)
  "Turn a text string into a HTML table.
See make-html-table."
  (let ()
    (setq textblock (replace-regexp-in-string delim "</td><td>" textblock))
    (setq textblock (replace-regexp-in-string "\n" "</td></tr>\n<tr><td>" textblock))
    (setq textblock (substring textblock 0 -8)) ;; delet the beginning “<tr><td>” in last line
    (concat "<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n<tr><td>" textblock "</table>")
    ))

To test this code, we can call it like this:

(make-html-table-string "1 2 3\na b c\n" " ")

All we have to do know, is to grab the current text block, then feed it into make-html-table-string, then insert the result.

Grabbing a block of text is done by knowing the position of occurances of a consecutive end of line characters (represented by "\n" in emacs), before and after the current cursor position. Such a unit of text is called “paragraph” in emacs, and the function “thing-at-point” will do this for us.

; set mytext to be the current paragraph
(setq mytext (thing-at-point 'paragraph))

; sets bnds to be a cons cell (cons p1 p2), where p1 and p2 are the
; beginning and ending positions of the semantic unit
(setq bnds (bounds-of-thing-at-point 'paragraph))

With this function, our job becomes very simple. Here's the code:

(defun make-html-table (sep)
  "Turn the current paragraph into a HTML table.

The “current paragraph” is defined as having empty lines before and
after the block of text the curson is on.

For example:

a•b•c
1•2•3
this•and•that

with “•” as separator, becomes

<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">
<tr><td>a</td><td>b</td><td>c</td></tr>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>this</td><td>and</td><td>that</td></tr>
</table>"
  (interactive "sEnter string pattern for column separation:")
  (let (bds p1 p2 myStr)
    (setq bds (bounds-of-thing-at-point 'paragraph))
    (setq p1 (+ (car bds) 1))
    (setq p2 (cdr bds))
    (setq myStr (buffer-substring-no-properties p1 p2))
    (delete-region p1 p2)
    (insert (make-html-table-string myStr sep) "\n")
  ))

One thing to note here is the code contained this line: “(interactive "sEnter string pattern for column separation:")”. What this line does, is that it will ask user to input a text pattern to be taken as the table column separater. The text the user enter will become the value of the parameter “sep” in the code. The first character “s”, in string of the argument of “interactive”, is to tell emacs that whatever the user entered should be interpreted as a string. (as opposed to, for example, a number)

In general, here's a simplified description on how to use “interactive”.

Reference: Elisp Manual: Defining-Commands.

Emacs rules!


The above is a simple method to turn a text blog into a HTML table. Once you have the table as html code, you can not easily add or delete row or columns. There is a method, that allows you to create table and edit table like a GUI application, including adding columns or merging a group of cells vertically. It takes about 10 minutes to learn how to use it though. The commands are table-capture and table-generate-source (new in emacs 22). For a detailed tutorial, see: http://www.emacswiki.org/cgi-bin/emacs-en/TableMode .


Related essays:


Page created: 2008-04.
© 2008 by Xah Lee.
Xah Signet