Pentadactyl set filetype in external Vim editor based on URL blog home

Posted Tuesday, 22-May-2012 by Ingo Karkat; last update Thursday, 14-Mar-2013

For keyboard centric power users like me, the Pentadactyl Firefox add-on brings modal editing and Vim-inspired key bindings to the Firefox browser. Even better, you can quickly edit any text field in Vim by pressing Ctrl + I. I use this for anything longer than a couple of words: Wiki edits, GitHub comments, Stack Overflow answers, etc.

Now, even though I have implemented some crude detection of various markups (Markdown, MediaWiki, Textile) inside Vim, wouldn't it be nice if the filetype could be derived automatically from the URL of the page I'm currently editing? Saving a manual :setf markdown on each launch, I would be able to enjoy the correct syntax highlighting from the start, even when triggering the external edit from a blank edit field.

Pentadactyl supports macros like <line> and <column>, but there is no such thing as <url> or <hostname>. (And even if it could be passed to Vim, it would still need to be translated into a filetype inside Vim.) But it is possible to hook into the triggering of the external editor via an Input mode mapping:

Inoremap <C-i> -javascript editExternallyWithFiletype()

Inside the JavaScript implementation of the mapping, we try to determine a filetype, and append this temporarily to the 'editor' setting. The filetype is passed to Vim via a +setf filetype command-line argument. Then the external editor is triggered by invoking the internal Pentadactyl function, and the setting is restored.

Update 14-Mar-2013: Just appending the +setf doesn't work when (like in the default option value) there's already a +cmd. I've extended the code to handle this.

javascript <<EOF
function editExternallyWithFiletype() {
    var save_editor = options["editor"];
    var filetype = editExternallyFiletype();
    if (filetype) {
        options["editor"] += " \"+setf " + filetype + "\"";
    }
    // Insert the :setf command before any existing +cmd, as there can be only one such argument.
    options["editor"] = options["editor"].replace(/ "\+/, " \"+setf " + filetype + "|")
    if (options["editor"] == save_editor) {
        // The 'editor' setting doesn't yet contain a passed +cmd; append it.
        options["editor"] += " \"+setf " + filetype + "\"";
    }
    editor.editFieldExternally();
    options["editor"] = save_editor;
}
EOF

For determining the filetype, we can test the properties of the Pentadactyl buffer.URL object for matching sites. This is the part that you have to adapt to the sites that you frequent, and to the Vim syntax definitions that you have installed (you can find many on vim.org). Here's an example:

javascript <<EOF
function editExternallyFiletype() {
    var host = buffer.URL.host
    switch(host.replace(/^www\./, "")) {
        case "github.com":
            if (! buffer.URL.path.match("/wiki/"))
                return "markdown";
        case "reddit.com":
            return "markdown";
        case "stackoverflow.com":
            return "markdown";
    }
    if (host.match(/.*\.wikia\.com$/) || host.match(/.*\.wikipedia\.org$/))
        return "mediawiki";
}
EOF

Put all of the above into your ~/.pentadactylrc configuration, and enjoy the enhanced, intelligent editing of web page forms with all the amenities of Vim's filetype mechanism1!

Ingo Karkat, 22-May-2012


  1. This is probably the topic of another blog post, but just to illustrate how powerful editing in Vim is: For various Wiki markup filetypes, I have defined uniform markup mappings (e.g. to make the current word or selection bold / italic / monotype), and have a :Cheat command that opens a ~/.vim/doc/cheat-filetype cheat sheet help page. This helps tremendously as I juggle with at least 4 different Wiki formats regularly.

ingo's blog is licensed under Attribution-ShareAlike 4.0 International

blog comments powered by Disqus