Turning Gedit into a Markdown IDE

Posted on Sun 15 November 2015 in Articles • 5 min read

I got an iPad mini not so long ago, mostly on the strength of the excellent Editorial app and to keep one foot in the door with Apple's services, which my wife and I find quite useful.

With Editorial, I can build workflows that let me work the way I want. I've created templates with user input and many small little utilities to speed up the things I do regularly. Editorial in short has become my go-to mobile text editor so much so that I began hankering for a desktop version.

There's plenty of good desktop markdown editors out there, not least MultiMarkdown Composer on OS X or the various Chrome-based editors such as Haroopad. There's also a crop of online, DropBox aware editors that are gaining in popularity. None of them support scripting however.

Then it occurred to me that I had a better equivalent all along: Gedit. Yes, the stock text editor for Gnome and Unity. Out of the box it's a nice lightweight editor with syntax highlighting for markdown, an adequate spell checker and find/replace with support for regular expressions. But dig around a bit and you'll find it can do much, much more.

Gedit has something that most basic markdown editors do not: plugin support. Out of the box, Gedit ships with two plugins that can transform the way you work: snippets and external tools.

Snippits are collections of reusable text that you can make available on a per-syntax basis. I use a lot as a technical writer for AsciiDoc but I didn't realise how useful they were because of their ability to wrap and modify existing text. I'll return to this shortly.

External tools allow you to use scripts that call system tools i.e. scripting languages. Again, I didn't realise just how useful this was until I worked out that you can use part or all of your document within the script's logic by using a few standard variables.

Then finally there's a possibility of writing your own plugin, if you want deeper integration into Gedit than an External tool provides. For example, with a plugin you can extend functionality of the side and bottom panels. I'll get to writing plugins in a later post since they are more work.

So, let's see what we can do to make life easier. We'll start with Snippets first.

The markdown variant I use is Fletcher Penny's MultiMarkdown. The dialect made early inroads into OS X, thanks to it's integration into Scrivener. It's open source and compiles easily on Linux. MultiMarkdown adds support for tables, CriticMarkup and document transclusion, all of which I find very useful. Most of the syntax extensions are also supported by Draft on Android (which I use on my phone) and Editorial on iOS.

By Fletcher's own admission, things like CriticMarkup are advanced features that most people probably won't use. CriticMarkup extends Markdown with support for comments, additions, deletions, substitutions, i.e. the sorts of things you do to a document when you want to edit or proofread the text without simply overwriting it. You can find out more about CriticMarkup on their website.

To begin with then, I'm going to create snippets for the five Critic marks:

  • Addition {++ ++}
  • Deletion {-- --}
  • Substitution {~~ ~> ~~}
  • Comment {>> <<}
  • Highlight {== ==}

To do so we'll create new snippets for each mark under Tools -> Manage Snippets. I've summarised the parameters I've used in the following table:

Name Snippet Tab Trigger Shortcut Key
CriticMarkupAddition {++@cgb $1$GEDIT_SELECTED_TEXT ++} cma Ctrl Shift +
CriticMarkupDeletion {-- $1$GEDIT_SELECTED_TEXT --} Ctrl Shift -
CriticMarkupSubstitution {~~ $GEDIT_SELECTED_TEXT ~> $2 ~~} Ctrl Shift ~
CriticMarkupComment {>>@cgb $1$GEDIT_SELECTED_TEXT <<} cmc Ctrl Shift C
CriticMarkupHighlight {== $1$GEDIT_SELECTED_TEXT ==} cmh Ctrl Shift H

It's pretty straight forward but there's a couple of things worth noting. $GEDIT_SELECTED_TEXT is a variable pointing the currently selected text. $1 and $2 are insertion points for new text. You can also add an attribute tag to each snippet, for example @cgb as I do by default on the comment snippet.

Now for an external rule. By default, the Python markdown modules don't ship with support for several MultiMarkdown features like document metadata, CriticMarkup and Transclusion. If I compile a markdown document that uses these features, the syntax won't be correctly processed into HTML.

So I'm going to write a simple script that compiles a markdown file using the MultiMarkdown command line utility. It's absurdly simple, all you need to do is created a new tool (Tools -> Manage External Tools) with the following command:

1
2
3
#!/bin/sh

multimarkdown -a -r $1

For input, choose Current Document and for Output select Create new document. Give it a name, I chose MMD to HTML, and add a keyboard shortcut if you want. To run the tool, open a markdown document and go to Tools -> External Tool and select the tool you created (or simply hit the shortcut key combination if you created one). Your markdown document will be rendered as HTML in a new unsaved document.

If you'd rather write it to file, simply add multimarkdown's output switch.

1
2
3
#!/bin/sh

multimarkdown -a -r $1 -o document_name.html

Since we're using MultiMarkdown, we can also access document metadata and use that for our file. Using Zenity, we can also handle files without a title by displaying a simple text entry box. For this version, I've pointed the output to Gedit's bottom panel so I can print messages.

Here's the code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash

DIR=$GEDIT_CURRENT_DOCUMENT_DIR
DOC=$GEDIT_CURRENT_DOCUMENT_PATH

TITLE=`/usr/local/bin/multimarkdown $DOC --extract="Title"`

if [ -z "$TITLE" ]; then

TITLE=$( zenity --entry \
     --title="Enter filename" \
     --text="Enter a title:" \
     --entry-text "new_title")
fi

TARGET="${TITLE// /_}.html"

echo "[MESSAGE] Title is: $TITLE"
echo "[MESSAGE] Working Directory is $DIR"
echo "[MESSAGE] Target file name is: $TARGET"

multimarkdown -a -r $DOC -o ${DIR}/${TARGET}

echo "[MESSAGE] Created doc.html in $DIR/$TARGET"

Let's break it down. At its heart this is a simple bash script.

First we create two variables and assign them each with Gedit's built in variables for the document's directory and its full path.

DIR=$GEDIT_CURRENT_DOCUMENT_DIR
DOC=$GEDIT_CURRENT_DOCUMENT_PATH

Next we create our title variable and assign it the title in the document's metadata.

TITLE=`/usr/local/bin/multimarkdown $DOC --extract="Title"`

If that metadata tag doesn’t exist, then I use zenity to prompt for one.

if [ -z "$TITLE" ]; then

TITLE=$( zenity --entry \
     --title="Enter filename" \
     --text="Enter a title:" \
     --entry-text "new_title")
fi

Next s a simple regular expression to remove spaces and add a file extension.

TARGET="${TITLE// /_}.html

Next I print out my variables to the console panel to make sure everything is as I expect and finally, I compile the document using the variables I created.

multimarkdown -a -r $DOC -o ${DIR}/${TARGET}

Share on: Diaspora*TwitterFacebookGoogle+Email