Converting TiddlyWiki Syntax into DokuWiki Markup with TextMate

I like TiddlyWikis. They are my electronic counterpart of a notepad. All notes, thoughts and code snippets with the interface for editing and searching in one single file to be carried around and used everywhere, I have a web browser at hands. But after heavy usage during at least three years I had collected too much of them and encountered the drawbacks: orphanhood and redundancy. Dozens of chunks of information I could not remember the path to the TiddlyWiki file I have put them into, and some other notes in several TiddlyWikis partly doubled and partly scattered without a link between the pieces.

Hence it was time to clean up things and put together what was living in the virtual diaspora of my hard disks. My remedy of choice is DokuWiki, a wiki software with an active community and few requirements, because the storage is based on plain old text files. Shortly: It needs a running web server with a PHP installation. The main disadvantage: It is not as easy to move back and forth to memory gadgets as it is with TiddlyWikis.

Unfortunately the markup notations used by both wikis differ in quite a lot of the typographic idioms. First I edited some of the tiddlers (as the tidbits of content are called in a TiddlyWiki) manually to make them fit into DokuWiki's markup grammar, just to get a feeling for the process and quickly let the programmer's layziness in me take over. The result was a command for my favourite and on macs very popular text editor TextMate, written in Ruby:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/env ruby -w
# Tiddly2DokuWiki - Converting TiddliWiki markup into DokuWiki markup
# [03.03.09:ofi]
$KCODE = 'U'
# Method of simple simultaneous conversion taken from
# "Ruby Cookbook, Recipe 1.18"
class String
  def mgsub (key_value_pairs=[].freeze)
    regexp_fragments = key_value_pairs.collect { |k,v| k }
    gsub( Regexp.union( *regexp_fragments ) ) do |match|
      key_value_pairs.detect{ |k,v| k =~ match } [1]
    end
  end
end
def simple_convert (text)
  text.mgsub([
    [/''/, '**' ],  #bold
    [/^\*[^*]/, '  * '],  # unordered lists 1st level
    [/^\*\*[^*]/, '    * '],  # unordered lists 2nd level
    [/^\*\*\*[^*]/, '      * '],  # unordered lists 3rd level
    [/^#[^#]/, '  - '],  # ordered lists 1st level
    [/^##[^#]/, '    - '],  # ordered lists 2nd level
    [/^###[^#]/, '      - '], # ordered lists 3rd level
    [/\|\!/, '^ '],  # table header
    [/\|\|/, '| |'],  # empty cell to blank cell, because...
    [/\|\~/, '| '],  # row span not supported in DokuWiki, use blank
    [/^\{\{\{$/, '< code>'], [/^\}\}\}$/, '< /code>']  # code paragraphs
# ATTENTION!       ^----- these blanks -----^  have to be removed!!!
# They are here only not to screw up the code output within WordPress!
  ])
end

text = simple_convert( STDIN.read ) # simple substitutions

text.gsub!( /\~(\w+)/, '\1' )  # remove WikiWord escapes
text.gsub!( /--(.+?)--/, '< del>\1< /del>' )  # strike thru
# ATTENTION! these blanks -^-------^  have to be removed!!!
# They are here only not to screw up the code output within WordPress!
text.gsub!( /^\!\s*(\w.*)/, '===== \1 =====' )  # h1 --> h2
text.gsub!( /^\!\!\s*(\w.*)/, '==== \1 ====' )  # h2 --> h3
text.gsub!( /^\!\!\!\s*(\w.*)/, '=== \1 ===' )  # h3 --> h4
text.gsub!( /\[\[(.+?)\|(.+?)\]\]/, '[[\2|\1]]' ) # links with text
text.gsub!( /\{\{\{(.+?)\}\}\}/, '\'\'\1\'\'' )  # code inline literals
# now the "master piece": converting column spanning table cells:
text.gsub!(/\|((>\|)+)([^|]+)\|/) {|m| '|' +$3 + '|'*($1.length/2) + '|' }
print text

This code is to be saved as a new command with the options Input: "Selected Text" or "Document" and Output: "Replace Selected Text", allowing you to choose between only converting the selected part of text or all of it when nothing is selected. As always you can assign a key for activation if you like, but more important: Don't forget to remove the spaces after the opening angular brackets in the "code" and "del" tags as indicated in the source! I had to insert them to not confuse the WordPress markup.

Disclaimer: This code is provided as is. It may serve as a tool for the purpose described here but I deny any fitness of it for any kind of usage. If  you use it, you agree that I am not responsible for any consequences following of its use.

That said, it does work well for me, but has some weaknesses:

  • The conversion is stateless, meaning that it does not distinguish if a conversion takes place wihtin a "code" or a "text" section. Thus it will convert strings within code snippets as well.
  • Hard line breaks will not be converted to the DokuWiki pendants (double backslash before newline or whitespace) for the same reason.
  • Conversion rules for superscript and subscript are missing. If you need them you may take the rule for the "strike through" format as a template and roll your own.

To transfer the code between the textareas of a wiki page and TextMate I use the It's All Text! add-on for Firefox, but copy and paste will do as well.

Definitely I will continue using TiddlyWikis, and with this command snippet I can do the housekeeping as long as I can keep track of all these tiddlers - hopefully.

Go Top