Convert markdown links from inline to reference

Save this as mdrelink.py in your Packages folder, and you can then run it with

view.run_command('mdrelink');

from within the command console.

I think I got the order thingy right – reversing is necessary because otherwise it would mess up the already cached indexes of next items. It should also automatically skip already used link numbers. My first Python and my first Sublime plugin, so please be gentle with me.

import sublime, sublime_plugin

class mdrelinkCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        oldlinks = []
        self.view.find_all("^\s*(\[\d+\]):", sublime.IGNORECASE, "\\1", oldlinks)
        newlinkpos = self.view.find_all("\[.+?\](\(.+?\))")
        orgtext = []
        self.view.find_all("(\[.+?\])\(.+?\)", sublime.IGNORECASE, "\\1", orgtext)
        orglink = []
        self.view.find_all("\[.+?\]\((.+?)\)", sublime.IGNORECASE, "\\1", orglink)
        orglink.reverse()
        self.view.insert(edit, self.view.size(), '\n\n')
        counter = 1
        newnumbers = []
        for r in newlinkpos:
            while '['+str(counter)+']' in oldlinks:
                 counter += 1
            oldlinks.append('['+str(counter)+']')
            line = '[' + str(counter)+']: '+ orglink.pop() + '\n'
            newnumbers.append('  ['+str(counter)+']')
            self.view.insert(edit, self.view.size(), line)
        for r in reversed(newlinkpos):
            self.view.replace(edit, r, orgtext.pop()+newnumbers.pop())

Came across this question thanks to Google. Maybe this can help others:

My answer isn't Sublime specific, but if you're using JavaScript (Node) already, I'd use a MD parser and CST transformer like remark.

For example, to transform all the inline links in README.md to numerically-ascending reference-style links, you could run the following at your project's root:

npm install --save-dev remark-reference-links remark-cli
npx remark README.md -o --use reference-links

Or, if you want reference-style links derived from the source uri:

npm install --save-dev remark-defsplit remark-cli
npx remark README.md -o --use defsplit

remark-cli's --use option doesn't play well with npx@6, but maybe this can be shortened to a transient one-liner with npx@7. The same might be achievable with some combination of remark-based editor plugins. Hopefully this info helps people like me not waste a whole day hacking together an unreliable regexp-based solution to this :)


That's a great requirement!

I've just created a new Node.js program (I know it's not a GUI but seems something more people would like the capability of) to do this on GitHub.

Here's also the code:

// node main.js test.md result.md

var fs = require('fs')
fs.readFile(process.argv[2], 'utf8', function (err, markdown) {
    if (err) {
        return console.log(err);
    }
    var counter = 1;
    var matches = {};
    var matcher = /\[.*?\]\((.*?)\)/g;
    while (match = matcher.exec(markdown)) {
        if (!matches[match[1]]) matches[match[1]] = counter++;
    }
    console.log(matches);
    Object.keys(matches).forEach(function(url) {
        var r = new RegExp("(\\[.*?\\])\\(" + url + "\\)", "g");
        markdown = markdown.replace(r, "$1[" + matches[url] + "]");
        markdown += "\n[" + matches[url] + "]: " + url;
    });

    fs.writeFile(process.argv[3], markdown, 'utf8', function (err) {
        if (err) return console.log(err);
    });

});