diff --git a/.eleventy.js b/.eleventy.js index 377289f..1facbb4 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -1,14 +1,31 @@ -const liquidPlain = require("./src/liquidSyntaxHighlightPlain"); -const liquidPrismJs = require("./src/liquidSyntaxHighlightPrism"); +const Prism = require("prismjs"); +const hasTemplateFormat = require("./src/hasTemplateFormat"); +const HighlightPairedShortcode = require("./src/HighlightPairedShortcode"); +const LiquidHighlightTag = require("./src/LiquidHighlightTag"); const markdownPrismJs = require("./src/markdownSyntaxHighlight"); -module.exports = function(eleventyConfig, pluginNamespace) { - eleventyConfig.namespace(pluginNamespace, () => { - // compatibility with existing {% highlight js %} and others - eleventyConfig.addLiquidTag("highlight", liquidPrismJs); - eleventyConfig.addMarkdownHighlighter(markdownPrismJs); +module.exports = { + initArguments: { Prism }, + configFunction: function(eleventyConfig, options = {}) { + // TODO hbs? + if( hasTemplateFormat(options.templateFormats, "liquid") ) { + eleventyConfig.addLiquidTag("highlight", (liquidEngine) => { + // {% highlight js 0 2 %} + let highlight = new LiquidHighlightTag(liquidEngine); + return highlight.getObject(); + }); + } - // Deprecated, use {% highlight text %} instead. - eleventyConfig.addLiquidTag("highlight-plain", liquidPlain); - }); + if( hasTemplateFormat(options.templateFormats, "njk") ) { + eleventyConfig.addPairedNunjucksShortcode("highlight", (content, args) => { + // {% highlight "js 0 2-3" %} + let [language, ...highlightNumbers] = args.split(" "); + return HighlightPairedShortcode(content, language, highlightNumbers.join(" ")); + }); + } + + if( hasTemplateFormat(options.templateFormats, "md") ) { + eleventyConfig.addMarkdownHighlighter(markdownPrismJs); + } + } }; diff --git a/README.md b/README.md index 62c3221..b6d2611 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,36 @@ You are responsible for including [your favorite PrismJS theme CSS](https://gith Read more about [Eleventy plugins.](https://www.11ty.io/docs/plugins/) +### Options + +Optionally pass in an options object as the second argument to `addPlugin` to further customize this plugin pack. + +``` +const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight"); +module.exports = function(eleventyConfig) { + eleventyConfig.addPlugin(syntaxHighlight, { + + // Change which syntax highlighters are installed + templateFormats: ["*"], // default + + // Or, just njk and md syntax highlighters (do not install liquid) + // templateFormats: ["njk", "md"], + + // init callback lets you customize Prism + init: function({ Prism }) { + Prism.languages.myCustomLanguage = /* */; + } + }); +}; +``` + ## Usage ### This plugin provides: * Markdown Highlighter: syntax highlights using PrismJS -* Liquid Tag `{% highlight %}`: syntax highlights using PrismJS. +* Liquid Custom Tag `{% highlight %}`: syntax highlights using PrismJS. +* Nunjucks Paired Shortcode `{% highlight %}`: syntax highlights using PrismJS. ### Markdown Highlighter @@ -37,6 +61,7 @@ Optionally specify a language after the start of the markdown fenced code block. * [List of supported PrismJS languages](http://prismjs.com/#languages-list) ```` + ``` js function myFunction() { return true; @@ -45,8 +70,12 @@ function myFunction() { ```` ```` -// Line highlighting classes (single highlight) -// Adds `highlight-line-active` class to lines 1,3,4,5 (for line highlighting) + + + ``` js/1,3-5 function myFunction() { // … @@ -56,9 +85,13 @@ function myFunction() { ```` ```` -// Line highlighting classes (add and remove mode) -// Adds `highlight-line-add` class to lines 1,3 -// Adds `highlight-line-remove` class to lines 5,6,7,8 + + + ``` js/1,3/5-8 function myFunction() { // … @@ -85,6 +118,7 @@ function myFunction() { * [List of supported PrismJS languages](http://prismjs.com/#languages-list) ``` + {% highlight js %} function myFunction() { return true; @@ -93,8 +127,12 @@ function myFunction() { ``` ``` -// Line highlighting classes (single highlight) -// Adds `highlight-line-active` class to lines 1,3,4,5 (for line highlighting) + + + {% highlight js 1,3-5 %} function myFunction() { // … @@ -104,9 +142,13 @@ function myFunction() { ``` ``` -// Line highlighting classes (add and remove) -// Adds `highlight-line-add` class to lines 1,3 -// Adds `highlight-line-remove` class to lines 5,6,7,8 + + + {% highlight js 1,3 5-8 %} function myFunction() { // … @@ -120,6 +162,7 @@ function myFunction() { Use `text` to use the line highlighting features without PrismJS. ``` + {% highlight text 1-2 %} function myFunction() { let highlighted = true; @@ -128,16 +171,79 @@ function myFunction() { {% endhighlight %} ``` -### Sample Line Highlighting CSS +### Nunjucks Paired Shortcode: Prism Syntax Highlighter + +* [List of supported PrismJS languages](http://prismjs.com/#languages-list) + +``` + +{% highlight "js" %} +function myFunction() { + return true; +} +{% endhighlight %} +``` ``` + + + +{% highlight "js 1,3-5" %} +function myFunction() { + // … + return true; +} +{% endhighlight %} +``` + +``` + + + +{% highlight "js 1,3 5-8" %} +function myFunction() { + // … + return true; +} +{% endhighlight %} +``` + +#### Plain text + +Use `text` to use the line highlighting features without PrismJS. + +``` + +{% highlight "text 1-2" %} +function myFunction() { + let highlighted = true; + return highlighted; +} +{% endhighlight %} +``` + +### Sample Line Highlighting CSS + +```css .highlight-line { display: block; - padding: 0.125em 1em; text-decoration: none; /* override del, ins, mark defaults */ color: inherit; /* override del, ins, mark defaults */ } -.highlight-line:not(:empty) + br { + +/* allow highlighting empty lines */ +.highlight-line:empty:before { + content: " "; +} +/* avoid double line breaks when using display: block; */ +.highlight-line + br { display: none; } diff --git a/package.json b/package.json index 51cc18f..58f4aec 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "ava": "^0.25.0" }, "dependencies": { - "@11ty/eleventy": "^0.3.5", - "prismjs": "^1.13.0" + "@11ty/eleventy": "^0.5.4", + "prismjs": "^1.15.0" } } diff --git a/src/HighlightLinesGroup.js b/src/HighlightLinesGroup.js index 1afecba..8f55098 100644 --- a/src/HighlightLinesGroup.js +++ b/src/HighlightLinesGroup.js @@ -5,9 +5,9 @@ class HighlightLinesGroup { this.init(str, delimiter); } - init(str, delimiter) { + init(str = "", delimiter = " ") { this.str = str; - this.delimiter = delimiter || " "; + this.delimiter = delimiter; let split = str.split(this.delimiter); this.highlights = new HighlightLines(split.length === 1 ? split[0] : ""); diff --git a/src/HighlightPairedShortcode.js b/src/HighlightPairedShortcode.js new file mode 100644 index 0000000..e8e0cdb --- /dev/null +++ b/src/HighlightPairedShortcode.js @@ -0,0 +1,24 @@ +const Prism = require("prismjs"); +const PrismLoader = require("prismjs/components/index.js"); +const HighlightLinesGroup = require("./HighlightLinesGroup"); + +module.exports = function(content, language, highlightNumbers) { + let highlightedContent; + if( language === "text" ) { + highlightedContent = content.trim(); + } else { + if( !Prism.languages[ language ] ) { + PrismLoader([language]); + } + + highlightedContent = Prism.highlight(content.trim(), Prism.languages[ language ]); + } + + let group = new HighlightLinesGroup(highlightNumbers); + + let lines = highlightedContent.split("\n").map(function(line, j) { + return group.getLineMarkup(j, line); + }); + + return `
` + lines.join("
") + "
";
+};
diff --git a/src/LiquidHighlight.js b/src/LiquidHighlightTag.js
similarity index 50%
rename from src/LiquidHighlight.js
rename to src/LiquidHighlightTag.js
index b59a6ca..3a3242d 100644
--- a/src/LiquidHighlight.js
+++ b/src/LiquidHighlightTag.js
@@ -1,18 +1,9 @@
const HighlightLinesGroup = require("./HighlightLinesGroup");
+const HighlightPairedShortcode = require("./HighlightPairedShortcode");
-class LiquidHighlight {
+class LiquidHighlightTag {
constructor(liquidEngine) {
this.liquidEngine = liquidEngine;
- this.hooks = [];
- this.classHooks = [];
- }
-
- addHook(hookFunction) {
- this.hooks.push(hookFunction);
- }
-
- addClassHook(hookFunction) {
- this.classHooks.push(hookFunction);
}
getObject() {
@@ -22,7 +13,7 @@ class LiquidHighlight {
let split = tagToken.args.split(" ");
this.language = split.shift();
- this.highlights = new HighlightLinesGroup(split.join(" "));
+ this.highlightLines = split.join(" ");
this.tokens = [];
@@ -46,23 +37,7 @@ class LiquidHighlight {
let tokens = this.tokens.map(token => token.raw);
let tokenStr = tokens.join("").trim();
- for( let hook of highlighter.hooks ) {
- tokenStr = hook.call(this, this.language, tokenStr);
- }
-
- let lines = tokenStr.split("\n").map(function(line, j) {
- let classHookClasses = [];
- for( let classHook of highlighter.classHooks ) {
- let ret = classHook(this.language, line, j);
- if( ret ) {
- classHookClasses.push(ret);
- }
- }
-
- return this.highlights.getLineMarkup(j, line, classHookClasses);
- }.bind(this));
-
- return Promise.resolve(`` + lines.join("
") + "
");
+ return Promise.resolve(HighlightPairedShortcode(tokenStr, this.language, this.highlightLines));
}
};
};
@@ -71,4 +46,4 @@ class LiquidHighlight {
}
}
-module.exports = LiquidHighlight;
+module.exports = LiquidHighlightTag;
diff --git a/src/hasTemplateFormat.js b/src/hasTemplateFormat.js
new file mode 100644
index 0000000..ee81e89
--- /dev/null
+++ b/src/hasTemplateFormat.js
@@ -0,0 +1,13 @@
+module.exports = function(templateFormats = ["*"], format = false) {
+ if(!Array.isArray(templateFormats)) {
+ templateFormats = [templateFormats];
+ }
+
+ if( Array.isArray(templateFormats) ) {
+ if( templateFormats.indexOf("*") > -1 || templateFormats.indexOf(format) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+};
diff --git a/src/liquidSyntaxHighlightPrism.js b/src/liquidSyntaxHighlightPrism.js
deleted file mode 100644
index 7fd0ece..0000000
--- a/src/liquidSyntaxHighlightPrism.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const Prism = require("prismjs");
-const PrismLoader = require("prismjs/components/index.js");
-const LiquidHighlight = require( "./LiquidHighlight" );
-
-module.exports = function(liquidEngine) {
- let highlight = new LiquidHighlight(liquidEngine);
-
- highlight.addHook(function(language, htmlStr, lines) {
- if( language === "text" ) {
- return htmlStr;
- } else {
- if( !Prism.languages[ language ] ) {
- PrismLoader([language]);
- }
-
- return Prism.highlight(htmlStr, Prism.languages[ language ]);
- }
- });
-
- return highlight.getObject();
-};
diff --git a/test/HasTemplateFormatTest.js b/test/HasTemplateFormatTest.js
new file mode 100644
index 0000000..f77747b
--- /dev/null
+++ b/test/HasTemplateFormatTest.js
@@ -0,0 +1,25 @@
+import test from "ava";
+import hasTemplateFormat from "../src/hasTemplateFormat";
+
+test("hasTemplateFormats", t => {
+ t.true(hasTemplateFormat("*", "liquid"));
+ t.false(hasTemplateFormat([], "liquid"));
+
+ // options not specified, defaults to *
+ t.true(hasTemplateFormat(undefined, "liquid"));
+ t.false(hasTemplateFormat(null, "liquid"));
+
+ t.true(hasTemplateFormat("*", false));
+ t.false(hasTemplateFormat([], false));
+
+ // options not specified, defaults to *
+ t.true(hasTemplateFormat(undefined, false));
+ t.false(hasTemplateFormat(null, false));
+
+ t.true(hasTemplateFormat(["*"], "liquid"));
+ t.true(hasTemplateFormat(["liquid"], "liquid"));
+ t.true(hasTemplateFormat(["liquid", "njk"], "liquid"));
+ t.true(hasTemplateFormat(["liquid", "njk"], "njk"));
+ t.true(hasTemplateFormat(["liquid", "njk", "md"], "md"));
+ t.false(hasTemplateFormat(["liquid", "njk", "md"], "pug"));
+});
diff --git a/test/HighlightPairedShortcodeTest.js b/test/HighlightPairedShortcodeTest.js
new file mode 100644
index 0000000..b90a81f
--- /dev/null
+++ b/test/HighlightPairedShortcodeTest.js
@@ -0,0 +1,23 @@
+import test from "ava";
+import HighlightPairedShortcode from "../src/HighlightPairedShortcode";
+
+test("Base", async t => {
+ t.is(await HighlightPairedShortcode(`alert();
+alert();`, "js"), `alert();
alert();
`);
+});
+
+test("Highlight Active", async t => {
+ t.is(await HighlightPairedShortcode(`alert();
+alert();`, "js", "0"), `alert();
alert();
`);
+
+ t.is(await HighlightPairedShortcode(`alert();
+alert();`, "js", "0-1"), `alert();
alert();
`);
+});
+
+test("Highlight Add/Remove", async t => {
+ t.is(await HighlightPairedShortcode(`alert();
+alert();`, "js", "0 1"), `alert();
alert();
`);
+
+ t.is(await HighlightPairedShortcode(`alert();
+alert();`, "js", "1 0"), `alert();
alert();
`);
+});