Skip to content

Instantly share code, notes, and snippets.

@offbynull
Created April 14, 2019 18:29
Show Gist options
  • Save offbynull/2009cfc1e76dfc6f6260a340282fcfe8 to your computer and use it in GitHub Desktop.
Save offbynull/2009cfc1e76dfc6f6260a340282fcfe8 to your computer and use it in GitHub Desktop.
Custom markup in markdown-it
var MarkdownIt = require("markdown-it");
var md = new MarkdownIt('commonmark');
// Add custom INLINE rule that pulls in anything wrapped in a ::: <TEXT> ::: and wrap in a span tag
function custom_inline(state, silent) {
let pos = state.pos;
let matchStart = pos;
let marker = '';
while (true) {
let ch = state.src.charCodeAt(pos);
if (ch !== 0x3A/* : */) {
break;
}
marker += String.fromCharCode(ch);
pos++;
}
if (marker.length < 3) {
return false;
}
let contentStart = pos;
let contentEnd = state.src.indexOf(marker, pos + marker.length);
if (contentEnd === -1) {
return false;
}
let matchEnd = contentEnd + marker.length;
if (!silent) {
let token;
token = state.push('custom_inline', '', 0);
// token.attrs = [ [ 'key1', val1 ], [ 'key2', val2] ];
token.markup = marker;
token.content = state.src.slice(contentStart, contentEnd).trim();
}
state.pos = matchEnd;
return true;
}
md.inline.ruler.before('backticks', 'custom_inline', custom_inline);
md.renderer.rules.custom_inline = function (tokens, idx, options, env, self) {
return '<span>' + md.utils.escapeHtml(tokens[idx].content) + '</span>';
};
// Add custom BLOCK rule that pulls in anything sandwiched between a startings and ending ::: lines and wraps in a div tag
function getLine(state, lineNum) {
return state.src.slice(state.bMarks[lineNum], state.eMarks[lineNum]);
}
function custom(state, startLine, endLine, silent) {
let line;
let content = [];
// no whitespace allowed before beginning
if (state.sCount[startLine] - state.blkIndent > 0) {
return false;
}
// read start marker
line = getLine(state, startLine);
let marker = '';
for (let i = 0; i < line.length; i++) {
const ch = line.charCodeAt(i);
if (ch !== 0x3A/* : */) {
break;
}
marker += String.fromCharCode(ch);
}
// if no marker found, skip
if (marker.length < 3) {
return false;
}
// first line must be just the marker
if (line.indexOf(marker) !== 0 || line.trim() !== marker) {
return false;
}
// keep reading until end marker
let properlyEnded = false;
let nextLine = startLine;
for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {
line = getLine(state, nextLine);
if (line.indexOf(marker) === 0 && line.trim() === marker) {
properlyEnded = true;
break;
}
content.push(line);
}
if (!properlyEnded) {
return false;
}
state.line = nextLine + 1;
if (silent) {
return true;
}
let token;
token = state.push('custom', '', 0);
token.content = content.join('\n');
token.markup = marker;
token.map = [ startLine, state.line ];
return true;
}
md.block.ruler.before('fence', 'custom', custom);
md.renderer.rules.custom = function (tokens, idx, options, env, self) {
return '<div>' + md.utils.escapeHtml(tokens[idx].content) + '</div>';
};
var result = md.render('# hello!\npooper :::hello1::: ```end```\n\n:::\nhello2\ntest\n\n\ntesttest\n:::\n\n');
console.log(result);
// OUTPUT
// ------
// <h1>hello!</h1>
// <p>pooper <span>hello1</span> <code>end</code></p>
// <div>hello2
// test
//
//
// testtest</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment