TiddlyWiki In Org
A friend of my sent me a message today:
Have you heard of TiddlyWiki? If not, it’s a featureful wiki system implemented as a single-page JS app, self-contained and server-less.
I know you’ll probably say, “I’m loyal to org.” I mention it because I find it’s a nice compromise between org and MediaWiki.
Wiki in Org?
I thought most features to make a personal wiki existed in Org.. I’ll admit I haven’t played with TiddlyWiki (or projects to make it more wiki-ish), but I assume the selling point is creating links to entries, and in an org file, that would be headers or headlines.
Emacs, out of the box, allows you to create a headline by hitting C-Return
. So, let’s do that:
* Apple Apples are firm with five seeds in a radial pattern, unlike a ▮
At this point, we would like to insert a link to an new entry. Type C-c C-l
to insert a new link. This function, org-insert-link
can accept most anything, from URLs, to embedded places in text files, but when you type a string (without colons that would indicate a URI), Org creates a link to a header in the current file. Which I believe can be what we want.
If you hit Return
at the Description
prompt, it uses the same name as the header. As in:
* Apple Apples are firm with five seeds in a radial pattern, unlike a [[Berry]].▮
Nice to know that we can link to a headline, but make it more readable, so this also works:
* Apple Apples are firm with five seeds in a radial pattern, unlike [[Berry][berries]].▮
If you now click on that link, you will see in the minibuffer the prompt:
No match - create this as a new heading? (yes or no)
Brilliant. Type y
and you have a new entry, that we can fill in:
* Apple Apples are firm with five seeds in a radial pattern, unlike a [[Berry]]. * Berry Ooey, gooey, berries are sweet and delicious, unlike an ▮
We can do the same here, by typing C-c C-l
, and typing the word, Apple
. But a Wiki would give you a choice of selecting existing headers, right? Org doesn’t have this particular feature out of the box, but we couldn’t have a howardism without a little bit of Lisp. Time for some fun.
Insert only Org Headers
Let’s create a function to insert a header. We initially could start with:
(defun org-insert-link-headline (header) "Insert internal link to HEADER entry in current file." (interactive "sHeader: ") (org-insert-link 1 header))
To get a list of the headlines to select, we need to add a completing-read
to the interactive
, like:
(defun org-insert-link-headline (header) "Insert internal link to HEADER entry in current file." (interactive (list (completing-read "Link: " (org-get-headings) nil nil))) (org-insert-link nil header))
The second nil
tells completing-read
that we will allow typing anything different to create a new heading, and the first nil
to org-insert-link
is the prefix (you know, the C-u
feature).
Shame org-get-headings
doesn’t exist.
The function org-map-entries
visits every headline in an org document, and calls a function. It then returns that list. We can also call org-get-heading
to return a list of information about the heading the point is on. The function:
(org-get-heading)
Could return more than 2400 characters:
#("TODO Some Headline Example :website:" 0 1 (fontified t line-prefix "" wrap-prefix # ("* " 0 2 (face org-indent)) org-todo-head # ("TODO" 0 4 (face org-todo)) face org-modern-todo display # (" T" 1 2 (cursor t)) composition ((4 . "⚑"))) 1 3 (fontified t line-prefix "" wrap-prefix # ("* " 0 2 (face org-indent)) org-todo-head # ("TODO" 0 4 (face org-todo)) face org-modern-todo composition ((4 . "⚑"))) ;; ...
Yes, I snipped it.
That’s too much information. The org-get-heading
allows us to trim some of that off with optional parameters, but:
(org-get-heading t t t t)
Still returns about 300 characters of information:
#("Some Headline Example" 0 13 (fontified t line-prefix "" wrap-prefix # ("* " 0 2 (face org-indent)) org-todo-head # ("TODO" 0 4 (face org-todo)) face org-level-1) 13 18 (fontified t line-prefix "" wrap-prefix # ("* " 0 2 (face org-indent)) org-todo-head # ("TODO" 0 4 (face org-todo)) face org-level-1))
That information is the text properties associated with the header, and while we could call propertize
to add properties, we can write an unpropertize
function to set all properties of some string to nil
:
(defun unpropertize (string) "Removes all text properties from STRING." (set-text-properties 0 (length string) nil string) string)
Now our org-get-headings
function is:
(defun org-get-headings () "Return a list of an org document's headings." (org-map-entries (lambda () (unpropertize (org-get-heading t t t t)))))
We can bind it to a local key map:
(define-key org-mode-map (kbd "C-c h") 'org-insert-link-headline)
And now we have the first hurdle to turning Org into a TiddlyWiki done in 3 small functions.

Next?
What features is missing from Org for it to fully replace TiddlyWiki as a personal wiki? Send me a message, and I’ll extend this essay with more ooey, gooey Lisp.