Back

adamham.dev

Extending gatsby-remark-embed-gist to support line selection

April 14, 2020

For years i've battled with Wordpress to manage my content, it was full of bloatware and it became demotivating to use. WP is also expensive to run compared to Gatsby which is a statically generated bundle of files that can be hosted behind a CDN for cheap, fast, global access.

I stumbled across Gatsby and I was hooked. I get to write my content in Markdown and the gatsby-transformer-remark plugin translates that into HTML.

For my site I needed to be able to include short snippets of code from GitHub. Luckily Patricio Treviño had already created a plugin that lets you embed a Gist gatsby-remark-embed-gist

This plugin allows you to highlight lines but I also needed to be able to include only specific lines. This feature is not native to the Gist API, but I found some comments online that suggested it was possible with Javascript.

Digging into the code, I found that the highlight feature works by adding a class to the DOM node of the lines that are chosen to be highlighted.

▼ gist:botoxparty/3eaf29fbb8b69e52fd2f27d6d2e7dcd3#index.js?lines=64-73,153-157

// explode the highlights ranges, if any
let highlights = [];
if (typeof query.highlights === "string") {
highlights = rangeParser.parse(query.highlights);
} else if (Array.isArray(query.highlights)) {
highlights = query.highlights;
}
query.highlights = highlights;
if (hasHighlights) {
query.highlights.forEach(line => {
$(`#file-${file}-LC${line}`).addClass("highlighted");
});
}
view raw index.js hosted with ❤ by GitHub

So we need to remove certain lines, we can use that same process to remove DOM nodes too!

▼ gist:botoxparty/3eaf29fbb8b69e52fd2f27d6d2e7dcd3#index.js?highlights=74-81,159-170&lines=64-82,143-171

// explode the highlights ranges, if any
let highlights = [];
if (typeof query.highlights === "string") {
highlights = rangeParser.parse(query.highlights);
} else if (Array.isArray(query.highlights)) {
highlights = query.highlights;
}
query.highlights = highlights;
// get the range of lines to display
let lines = [];
if (typeof query.lines === "string") {
lines = rangeParser.parse(query.lines);
} else if (Array.isArray(query.lines)) {
lines = query.lines;
}
query.lines = lines;
const hasHighlights = query.highlights.length > 0;
const hasLines = query.lines.length > 0;
if (hasHighlights || hasLines) {
const $ = cheerio.load(html);
const file = query.file
? query.file.replace(/[^a-zA-Z0-9_]+/g, "-").toLowerCase()
: "";
// highlight the specify lines, if any
if (hasHighlights) {
query.highlights.forEach(line => {
$(`#file-${file}-LC${line}`).addClass("highlighted");
});
}
// remove the specific lines, if any
if (hasLines) {
const codeLines = rangeParser.parse(`1-${$("table tr").length}`);
codeLines.forEach(line => {
if (query.lines.includes(line)) {
return;
}
$(`#file-${file}-LC${line}`)
.parent()
.remove();
});
}
view raw index.js hosted with ❤ by GitHub