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);
});
});