diff --git a/lib/hexo/default_config.js b/lib/hexo/default_config.js index daaf6b4a89..8c529ac7bf 100644 --- a/lib/hexo/default_config.js +++ b/lib/hexo/default_config.js @@ -48,6 +48,12 @@ module.exports = { wrap: true, hljs: false }, + prismjs: { + enable: false, + preprocess: true, + line_number: true, + tab_replace: '' + }, // Category & Tag default_category: 'uncategorized', category_map: {}, diff --git a/lib/plugins/filter/before_post_render/backtick_code_block.js b/lib/plugins/filter/before_post_render/backtick_code_block.js index ca608692ad..36f609117c 100644 --- a/lib/plugins/filter/before_post_render/backtick_code_block.js +++ b/lib/plugins/filter/before_post_render/backtick_code_block.js @@ -1,51 +1,38 @@ 'use strict'; -const { highlight } = require('hexo-util'); +let highlight, prismHighlight; const rBacktick = /^((?:[^\S\r\n]*>){0,3}[^\S\r\n]*)(`{3,}|~{3,})[^\S\r\n]*((?:.*?[^`\s])?)[^\S\r\n]*\n((?:[\s\S]*?\n)?)(?:(?:[^\S\r\n]*>){0,3}[^\S\r\n]*)\2(\n+|$)/gm; const rAllOptions = /([^\s]+)\s+(.+?)\s+(https?:\/\/\S+|\/\S+)\s*(.+)?/; const rLangCaption = /([^\s]+)\s*(.+)?/; +const escapeSwigTag = str => str.replace(/{/g, '{').replace(/}/g, '}'); + function backtickCodeBlock(data) { - const config = this.config.highlight || {}; - if (!config.enable) return; + const hljsCfg = this.config.highlight || {}; + const prismCfg = this.config.prismjs || {}; + data.content = data.content.replace(rBacktick, ($0, start, $2, _args, _content, end) => { let content = _content.replace(/\n$/, ''); - const args = _args.split('=').shift(); - - const options = { - hljs: config.hljs, - autoDetect: config.auto_detect, - gutter: config.line_number, - tab: config.tab_replace, - wrap: config.wrap - }; - if (options.gutter) { - config.first_line_number = config.first_line_number || 'always1'; - if (config.first_line_number === 'inline') { + // neither highlight or prismjs is enabled, return escaped content directly. + if (!hljsCfg.enable && !prismCfg.enable) return escapeSwigTag($0); - // setup line number by inline - _args = _args.replace('=+', '='); - options.gutter = _args.includes('='); - - // setup fiestLineNumber; - options.firstLine = options.gutter ? _args.split('=')[1] || 1 : 0; - } - } + // Extrace langauge and caption of code blocks + const args = _args.split('=').shift(); + let lang, caption; if (args) { const match = rAllOptions.exec(args) || rLangCaption.exec(args); - if (match) { - options.lang = match[1]; + lang = match[1]; if (match[2]) { - options.caption = `${match[2]}`; + caption = `${match[2]}`; if (match[3]) { - options.caption += `${match[4] ? match[4] : 'link'}`; + caption += `${match[4] ? match[4] : 'link'}`; } } } @@ -59,11 +46,52 @@ function backtickCodeBlock(data) { content = content.replace(regexp, ''); } - content = highlight(content, options) - .replace(/{/g, '{') - .replace(/}/g, '}'); + // Since prismjs have better performance, so prismjs should have higher priority. + if (prismCfg.enable) { + if (!prismHighlight) prismHighlight = require('hexo-util').prismHighlight; + + const options = { + lineNumber: prismCfg.line_number, + tab: prismCfg.tab_replace, + isPreprocess: prismCfg.preprocess, + lang + }; + + content = prismHighlight(content, options); + } else if (hljsCfg.enable) { + if (!highlight) highlight = require('hexo-util').highlight; + + const options = { + hljs: hljsCfg.hljs, + autoDetect: hljsCfg.auto_detect, + gutter: hljsCfg.line_number, + tab: hljsCfg.tab_replace, + wrap: hljsCfg.wrap, + lang, + caption + }; + + if (options.gutter) { + hljsCfg.first_line_number = hljsCfg.first_line_number || 'always1'; + if (hljsCfg.first_line_number === 'inline') { + + // setup line number by inline + _args = _args.replace('=+', '='); + options.gutter = _args.includes('='); + + // setup firstLineNumber; + options.firstLine = options.gutter ? _args.split('=')[1] || 1 : 0; + } + } + + content = highlight(content, options); + } - return `${start}${end}`; + return start + + '' + + end; }); } diff --git a/lib/plugins/tag/code.js b/lib/plugins/tag/code.js index a831db6fb0..d668a3cb7d 100644 --- a/lib/plugins/tag/code.js +++ b/lib/plugins/tag/code.js @@ -2,7 +2,7 @@ // Based on: https://raw.github.com/imathis/octopress/master/plugins/code_block.rb -const { escapeHTML, highlight } = require('hexo-util'); +const { escapeHTML, highlight, prismHighlight } = require('hexo-util'); const rCaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/\S+)\s+(.+)/i; const rCaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/\S+)/i; @@ -25,13 +25,13 @@ const rCaption = /\S[\S\s]*/; * Example: `mark:1,4-7,10` will mark line 1, 4 to 7 and 10. * @param {Object} wrap Wrap the code block in , value must be a boolean * @returns {String} Code snippet with code highlighting - */ +*/ -function getHighlightOptions(config, args) { +function parseArgs(args) { const _else = []; const len = args.length; - let lang = ''; - let { line_number, wrap } = config; + let lang, + line_number, wrap; let firstLine = 1; const mark = []; for (let i = 0; i < len; i++) { @@ -86,8 +86,9 @@ function getHighlightOptions(config, args) { } const arg = _else.join(' '); - let caption = ''; - let match; + // eslint-disable-next-line one-var + let match, caption = ''; + if ((match = arg.match(rCaptionUrlTitle)) != null) { caption = `${match[1]}${match[3]}`; } else if ((match = arg.match(rCaptionUrl)) != null) { @@ -100,37 +101,60 @@ function getHighlightOptions(config, args) { lang, firstLine, caption, - gutter: line_number, - hljs: config.hljs, + line_number, mark, - tab: config.tab_replace, - autoDetect: config.auto_detect, wrap }; } module.exports = ctx => function codeTag(args, content) { - const config = ctx.config.highlight || {}; - let { enable } = config; + const hljsCfg = ctx.config.highlight || {}; + const prismjsCfg = ctx.config.prismjs || {}; let index; + let enableHighlight = true; if ((index = args.findIndex(item => item.startsWith('highlight:'))) !== -1) { const arg = args[index]; - const _enable = arg.slice(10); - enable = _enable === 'true'; + const highlightStr = arg.slice(10); + enableHighlight = highlightStr === 'true'; args.splice(index, 1); } - if (!enable) { - content = escapeHTML(content); - return `
${content}
`; + // If 'hilight: false' is given, return escaped code directly + // If neither highlight.js nor prism.js is enabled, return escaped code directly + if (!enableHighlight || (!hljsCfg.enable && !prismjsCfg.enable)) { + return `
${escapeHTML(content)}
`; } - content = highlight(content, getHighlightOptions(config, args)); - - content = content.replace(/{/g, '{') - .replace(/}/g, '}'); + const { lang, firstLine, caption, line_number, mark, wrap } = parseArgs(args); + + if (prismjsCfg.enable) { + const prismjsOption = { + lang, + firstLine, + lineNumber: typeof line_number !== 'undefined' ? line_number : prismjsCfg.line_number, + mark, + tab: prismjsCfg.tab_replace, + isPreprocess: prismjsCfg.preprocess + }; + + content = prismHighlight(content, prismjsOption); + } else { + const hljsOption = { + lang: typeof lang !== 'undefined' ? lang : '', + firstLine, + caption, + gutter: typeof line_number !== 'undefined' ? line_number : hljsCfg.line_number, + hljs: hljsCfg.hljs, + mark, + tab: hljsCfg.tab_replace, + autoDetect: hljsCfg.auto_detect, + wrap: typeof wrap === 'undefined' ? wrap : hljsCfg.wrap + }; + + content = highlight(content, hljsOption); + } - return content; + return content.replace(/{/g, '{').replace(/}/g, '}'); }; diff --git a/lib/plugins/tag/include_code.js b/lib/plugins/tag/include_code.js index 96823c5332..a4bab70037 100644 --- a/lib/plugins/tag/include_code.js +++ b/lib/plugins/tag/include_code.js @@ -2,7 +2,7 @@ const fs = require('hexo-fs'); const { basename, extname, join } = require('path'); -const { highlight } = require('hexo-util'); +const { highlight, prismHighlight } = require('hexo-util'); const rCaptionTitleFile = /(.*)?(?:\s+|^)(\/*\S+)/; const rLang = /\s*lang:(\w+)/i; @@ -17,7 +17,6 @@ const rTo = /\s*to:(\d+)/i; */ module.exports = ctx => function includeCodeTag(args) { - const config = ctx.config.highlight || {}; let codeDir = ctx.config.code_dir; let arg = args.join(' '); @@ -47,22 +46,31 @@ module.exports = ctx => function includeCodeTag(args) { const path = match[2]; - // If the title is not defined, use file name instead - const title = match[1] || basename(path); - // If the language is not defined, use file extension instead lang = lang || extname(path).substring(1); const src = join(ctx.source_dir, codeDir, path); + // If the title is not defined, use file name instead + const title = match[1] || basename(path); const caption = `${title}view raw`; - const options = { + const hljsCfg = ctx.config.highlight || {}; + const prismjsCfg = ctx.config.prismjs || {}; + + const hljsOptions = { lang, caption, - gutter: config.line_number, - hljs: config.hljs, - tab: config.tab_replace + gutter: hljsCfg.line_number, + hljs: hljsCfg.hljs, + tab: hljsCfg.tab_replace + }; + + const prismjsOptions = { + lang, + lineNumber: prismjsCfg.line_number, + tab: prismjsCfg.tab_replace, + isPreprocess: prismjsCfg.preprocess }; return fs.exists(src).then(exist => { @@ -73,10 +81,12 @@ module.exports = ctx => function includeCodeTag(args) { const lines = code.split('\n'); code = lines.slice(from, to).join('\n').trim(); - if (!config.enable) { - return `
${code}
`; + if (prismjsCfg.enable) { + return prismHighlight(code, prismjsOptions); + } else if (hljsCfg.enable) { + return highlight(code, hljsOptions); } - return highlight(code, options); + return `
${code}
`; }); }; diff --git a/test/scripts/filters/backtick_code_block.js b/test/scripts/filters/backtick_code_block.js index 278c22b48c..dd3aec048c 100644 --- a/test/scripts/filters/backtick_code_block.js +++ b/test/scripts/filters/backtick_code_block.js @@ -9,7 +9,7 @@ describe('Backtick code block', () => { const codeBlock = require('../../../lib/plugins/filter/before_post_render/backtick_code_block').bind(hexo); const code = [ - 'if (tired && night){', + 'if (tired && night) {', ' sleep();', '}' ].join('\n'); @@ -20,9 +20,28 @@ describe('Backtick code block', () => { .replace(/}/g, '}'); } + function prism(code, options) { + return util.prismHighlight(code, options || {}) + .replace(/{/g, '{') + .replace(/}/g, '}'); + } + + // Used for prismjs related test cases + function enablePrismjs() { + hexo.config.highlight.enable = false; + hexo.config.prismjs.enable = true; + } + beforeEach(() => { // Reset config hexo.config.highlight = Object.assign({}, defaultConfig.highlight); + hexo.config.prismjs = Object.assign({}, defaultConfig.prismjs); + }); + + after(() => { + // Reset config for further test + hexo.config.highlight = defaultConfig.highlight; + hexo.config.prismjs = defaultConfig.prismjs; }); it('disabled', () => { @@ -35,8 +54,9 @@ describe('Backtick code block', () => { const data = {content}; hexo.config.highlight.enable = false; + hexo.config.prismjs.enable = false; codeBlock(data); - data.content.should.eql(content); + data.content.should.eql(content.replace(/{/g, '{').replace(/}/g, '}')); }); it('with no config (disabled)', () => { @@ -48,16 +68,19 @@ describe('Backtick code block', () => { const data = {content}; - const oldConfig = hexo.config.highlight; + const oldHljsCfg = hexo.config.highlight; + const oldPrismCfg = hexo.config.prismjs; delete hexo.config.highlight; + delete hexo.config.prismjs; codeBlock(data); - data.content.should.eql(content); + data.content.should.eql(content.replace(/{/g, '{').replace(/}/g, '}')); - hexo.config.highlight = oldConfig; + hexo.config.highlight = oldHljsCfg; + hexo.config.prismjs = oldPrismCfg; }); - it('default', () => { + it('highlightjs - default', () => { const data = { content: [ '``` js', @@ -70,7 +93,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('without language name', () => { + it('highlightjs - without language name', () => { const data = { content: [ '```', @@ -85,7 +108,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('without language name - ignore tab character', () => { + it('highlightjs - without language name - ignore tab character', () => { const data = { content: [ '``` \t', @@ -100,7 +123,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('title', () => { + it('highlightjs - title', () => { const data = { content: [ '``` js Hello world', @@ -118,7 +141,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('url', () => { + it('highlightjs - url', () => { const data = { content: [ '``` js Hello world https://hexo.io/', @@ -136,7 +159,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('link text', () => { + it('highlightjs - link text', () => { const data = { content: [ '``` js Hello world https://hexo.io/ Hexo', @@ -154,7 +177,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('indent', () => { + it('highlightjs - indent', () => { const indentCode = code.split('\n').map(line => ' ' + line).join('\n'); const data = { @@ -174,7 +197,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('line number false', () => { + it('highlightjs - line number false', () => { hexo.config.highlight.line_number = false; const data = { @@ -194,7 +217,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('line number false, don`t first_line_number always1', () => { + it('highlightjs - line number false, don`t first_line_number always1', () => { hexo.config.highlight.line_number = false; hexo.config.highlight.first_line_number = 'always1'; @@ -215,7 +238,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('line number false, don`t care first_line_number inilne', () => { + it('highlightjs - line number false, don`t care first_line_number inilne', () => { hexo.config.highlight.line_number = false; hexo.config.highlight.first_line_number = 'inilne'; @@ -236,7 +259,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('line number true', () => { + it('highlightjs - line number true', () => { hexo.config.highlight.line_number = true; const data = { @@ -256,7 +279,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('line number, first_line_number always1, js=', () => { + it('highlightjs - line number, first_line_number always1, js=', () => { hexo.config.highlight.line_number = true; hexo.config.highlight.first_line_number = 'always1'; @@ -278,7 +301,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('line number, first_line_number inline, js', () => { + it('highlightjs - line number, first_line_number inline, js', () => { hexo.config.highlight.line_number = true; hexo.config.highlight.first_line_number = 'inline'; @@ -300,7 +323,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('line number, first_line_number inline, js=1', () => { + it('highlightjs - line number, first_line_number inline, js=1', () => { hexo.config.highlight.line_number = true; hexo.config.highlight.first_line_number = 'inline'; @@ -322,7 +345,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('line number, first_line_number inline, js=2', () => { + it('highlightjs - line number, first_line_number inline, js=2', () => { hexo.config.highlight.line_number = true; hexo.config.highlight.first_line_number = 'inline'; @@ -344,7 +367,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('tab replace', () => { + it('highlightjs - tab replace', () => { hexo.config.highlight.tab_replace = ' '; const code = [ @@ -370,7 +393,7 @@ describe('Backtick code block', () => { data.content.should.eql(''); }); - it('wrap', () => { + it('highlightjs - wrap', () => { hexo.config.highlight.wrap = false; const data = { @@ -398,8 +421,8 @@ describe('Backtick code block', () => { '```' ].join('\n') }; - codeBlock(data); + data.content.should.eql('```foo```\n\n'); }); @@ -419,5 +442,126 @@ describe('Backtick code block', () => { codeBlock(data); data.content.should.eql(''); + + }); + + it('prismjs - default', () => { + enablePrismjs(); + + const data = { + content: [ + '``` js', + code, + '```' + ].join('\n') + }; + + codeBlock(data); + + data.content.should.eql(''); + }); + + it('prismjs - without language name', () => { + enablePrismjs(); + + const data = { + content: [ + '```', + code, + '```' + ].join('\n') + }; + + const expected = prism(code); + + codeBlock(data); + data.content.should.eql(''); + }); + + + it('prismjs - without language name - ignore tab character', () => { + enablePrismjs(); + + const data = { + content: [ + '``` \t', + code, + '```' + ].join('\n') + }; + + const expected = prism(code); + + codeBlock(data); + data.content.should.eql(''); + }); + + it('prismjs - indent', () => { + enablePrismjs(); + + const indentCode = code.split('\n').map(line => ' ' + line).join('\n'); + + const data = { + content: [ + '``` js', + indentCode, + '```' + ].join('\n') + }; + + const expected = prism(code, { lang: 'js' }); + + codeBlock(data); + data.content.should.eql(''); + }); + + it('prismjs - line number false', () => { + enablePrismjs(); + + hexo.config.prismjs.line_number = false; + + const data = { + content: [ + '``` js', + code, + '```' + ].join('\n') + }; + + const expected = prism(code, { + lang: 'js', + lineNumber: false + }); + + codeBlock(data); + data.content.should.eql(''); + }); + + it('prismjs - tab replace', () => { + enablePrismjs(); + + hexo.config.prismjs.tab_replace = ' '; + + const code = [ + 'if (tired && night){', + '\tsleep();', + '}' + ].join('\n'); + + const data = { + content: [ + '``` js', + code, + '```' + ].join('\n') + }; + + const expected = prism(code, { + lang: 'js', + tab: ' ' + }); + + codeBlock(data); + data.content.should.eql(''); }); }); diff --git a/test/scripts/tags/code.js b/test/scripts/tags/code.js index 5ab15a80a0..c9c3cf5039 100644 --- a/test/scripts/tags/code.js +++ b/test/scripts/tags/code.js @@ -7,7 +7,7 @@ describe('code', () => { const Hexo = require('../../../lib/hexo'); const hexo = new Hexo(); const codeTag = require('../../../lib/plugins/tag/code')(hexo); - const escapeHTML = util.escapeHTML; + const { escapeHTML } = util; const fixture = [ 'if (tired && night){', @@ -19,18 +19,30 @@ describe('code', () => { return codeTag(args.split(' '), content); } + // Used for prismjs related test cases + function enablePrismjs() { + hexo.config.highlight.enable = false; + hexo.config.prismjs.enable = true; + } + function highlight(code, options) { return util.highlight(code, options || {}) .replace(/{/g, '{') .replace(/}/g, '}'); } - it('default', () => { + function prism(code, options) { + return util.prismHighlight(code, options || {}) + .replace(/{/g, '{') + .replace(/}/g, '}'); + } + + it('highlightjs - default', () => { const result = code('', fixture); result.should.eql(highlight(fixture)); }); - it('non standard indent', () => { + it('highlightjs - non standard indent', () => { const nonStandardIndent = [ ' ', ' return x;', @@ -43,14 +55,14 @@ describe('code', () => { result.should.eql(highlight(nonStandardIndent)); }); - it('lang', () => { + it('highlightjs - lang', () => { const result = code('lang:js', fixture); result.should.eql(highlight(fixture, { lang: 'js' })); }); - it('line_number', () => { + it('highlightjs - line_number', () => { let result = code('line_number:false', fixture); result.should.eql(highlight(fixture, { gutter: false @@ -61,19 +73,19 @@ describe('code', () => { })); }); - it('highlight disable', () => { + it('highlightjs - highlight disable', () => { const result = code('highlight:false', fixture); result.should.eql('
' + escapeHTML(fixture) + '
'); }); - it('title', () => { + it('highlightjs - title', () => { const result = code('Hello world', fixture); result.should.eql(highlight(fixture, { caption: 'Hello world' })); }); - it('link', () => { + it('highlightjs - link', () => { const result = code('Hello world https://hexo.io/', fixture); const expected = highlight(fixture, { caption: 'Hello worldlink' @@ -82,7 +94,7 @@ describe('code', () => { result.should.eql(expected); }); - it('link text', () => { + it('highlightjs - link text', () => { const result = code('Hello world https://hexo.io/ Hexo', fixture); const expected = highlight(fixture, { caption: 'Hello worldHexo' @@ -91,7 +103,7 @@ describe('code', () => { result.should.eql(expected); }); - it('disabled', () => { + it('highlightjs - disabled', () => { hexo.config.highlight.enable = false; const result = code('', fixture); @@ -100,7 +112,7 @@ describe('code', () => { hexo.config.highlight.enable = true; }); - it('first_line', () => { + it('highlightjs - first_line', () => { let result = code('first_line:1234', fixture); result.should.eql(highlight(fixture, { firstLine: 1234 @@ -111,7 +123,7 @@ describe('code', () => { })); }); - it('mark', () => { + it('highlightjs - mark', () => { const source = [ 'const http = require(\'http\');', '', @@ -135,13 +147,13 @@ describe('code', () => { })); }); - it('# lines', () => { + it('highlightjs - # lines', () => { const result = code('', fixture); const $ = cheerio.load(result); $('.gutter .line').should.have.lengthOf(3); }); - it('wrap', () => { + it('highlightjs - wrap', () => { let result = code('wrap:false', fixture); result.should.eql(highlight(fixture, { wrap: false @@ -151,4 +163,104 @@ describe('code', () => { wrap: true })); }); + + it('prismjs - default', () => { + enablePrismjs(); + + const result = code('', fixture); + result.should.eql(prism(fixture)); + }); + + it('prismjs - non standard indent', () => { + enablePrismjs(); + + const nonStandardIndent = [ + ' ', + ' return x;', + '}', + '', + fixture, + ' ' + ].join('/n'); + const result = code('', nonStandardIndent); + result.should.eql(prism(nonStandardIndent)); + }); + + it('prismjs - lang', () => { + enablePrismjs(); + + const result = code('lang:js', fixture); + result.should.eql(prism(fixture, { + lang: 'js' + })); + }); + + it('prismjs - line_number', () => { + enablePrismjs(); + + let result = code('line_number:false', fixture); + result.should.eql(prism(fixture, { + lineNumber: false + })); + result = code('line_number:true', fixture); + result.should.eql(prism(fixture, { + lineNumber: true + })); + }); + + it('prismjs - highlight disable', () => { + enablePrismjs(); + + const result = code('highlight:false', fixture); + result.should.eql('
' + escapeHTML(fixture) + '
'); + }); + + it('prismjs - disabled', () => { + hexo.config.highlight.enable = false; + hexo.config.prismjs.enable = false; + + const result = code('', fixture); + result.should.eql('
' + escapeHTML(fixture) + '
'); + + hexo.config.highlight.enable = true; + }); + + it('prismjs - first_line', () => { + enablePrismjs(); + + let result = code('first_line:1234', fixture); + result.should.eql(prism(fixture, { + firstLine: 1234 + })); + result = code('', fixture); + result.should.eql(prism(fixture, { + firstLine: 1 + })); + }); + + it('prismjs - mark', () => { + enablePrismjs(); + + const source = [ + 'const http = require(\'http\');', + '', + 'const hostname = \'127.0.0.1\';', + 'const port = 1337;', + '', + 'http.createServer((req, res) => {', + ' res.writeHead(200, { \'Content-Type\': \'text/plain\' });', + ' res.end(\'Hello World\n\');', + '}).listen(port, hostname, () => {', + ' console.log(`Server running at http://${hostname}:${port}/`);', + '});' + ].join('\n'); + + code('mark:1,7-9,11', source).should.eql(prism(source, { + mark: [1, 7, 8, 9, 11] + })); + + code('mark:11,9-7,1', source).should.eql(prism(source, { + mark: [1, 7, 8, 9, 11] + })); + }); }); diff --git a/test/scripts/tags/include_code.js b/test/scripts/tags/include_code.js index a9902ca63c..844c82ede2 100644 --- a/test/scripts/tags/include_code.js +++ b/test/scripts/tags/include_code.js @@ -2,7 +2,7 @@ const pathFn = require('path'); const fs = require('hexo-fs'); -const { highlight } = require('hexo-util'); +const { highlight, prismHighlight } = require('hexo-util'); const Promise = require('bluebird'); describe('include_code', () => { @@ -17,15 +17,16 @@ describe('include_code', () => { '}' ].join('\n'); - function code(args) { - return includeCode(args.split(' ')); - } + const code = args => includeCode(args.split(' ')); before(() => fs.writeFile(path, fixture)); after(() => fs.rmdir(hexo.base_dir)); - it('default', () => { + it('highlightjs - default', () => { + hexo.config.highlight.enable = true; + hexo.config.prismjs.enable = false; + const expected = highlight(fixture, { lang: 'js', caption: 'test.jsview raw' @@ -36,7 +37,7 @@ describe('include_code', () => { }); }); - it('title', () => { + it('highlightjs - title', () => { const expected = highlight(fixture, { lang: 'js', caption: 'Hello worldview raw' @@ -47,7 +48,7 @@ describe('include_code', () => { }); }); - it('lang', () => { + it('highlightjs - lang', () => { const expected = highlight(fixture, { lang: 'js', caption: 'Hello worldview raw' @@ -58,7 +59,7 @@ describe('include_code', () => { }); }); - it('from', () => { + it('highlightjs - from', () => { const fixture = [ '}' ].join('\n'); @@ -72,7 +73,7 @@ describe('include_code', () => { }); }); - it('to', () => { + it('highlightjs - to', () => { const fixture = [ 'if (tired && night){', ' sleep();' @@ -87,7 +88,7 @@ describe('include_code', () => { }); }); - it('from and to', () => { + it('highlightjs - from and to', () => { const fixture = [ 'sleep();' ].join('\n'); @@ -101,11 +102,11 @@ describe('include_code', () => { }); }); - it('file not found', () => code('nothing').then(result => { + it('highlightjs - file not found', () => code('nothing').then(result => { should.not.exist(result); })); - it('disabled', () => { + it('highlightjs - disabled', () => { hexo.config.highlight.enable = false; return code('test.js').then(result => { @@ -113,4 +114,81 @@ describe('include_code', () => { hexo.config.highlight.enable = true; }); }); + + it('prismjs - default', () => { + hexo.config.highlight.enable = false; + hexo.config.prismjs.enable = true; + + const expected = prismHighlight(fixture, { + lang: 'js' + }); + + return code('test.js').then(result => { + result.should.eql(expected); + }); + }); + + it('prismjs - lang', () => { + const expected = prismHighlight(fixture, { + lang: 'js', + caption: 'Hello worldview raw' + }); + + return code('Hello world lang:js test.js').then(result => { + result.should.eql(expected); + }); + }); + + it('prismjs - from', () => { + const fixture = [ + '}' + ].join('\n'); + const expected = prismHighlight(fixture, { + lang: 'js' + }); + + return code('Hello world lang:js from:3 test.js').then(result => { + result.should.eql(expected); + }); + }); + + it('prismjs - to', () => { + const fixture = [ + 'if (tired && night){', + ' sleep();' + ].join('\n'); + const expected = prismHighlight(fixture, { + lang: 'js' + }); + + return code('Hello world lang:js to:2 test.js').then(result => { + result.should.eql(expected); + }); + }); + + it('prismjs - from and to', () => { + const fixture = [ + 'sleep();' + ].join('\n'); + const expected = prismHighlight(fixture, { + lang: 'js' + }); + + return code('Hello world lang:js from:2 to:2 test.js').then(result => { + result.should.eql(expected); + }); + }); + + it('prismjs - file not found', () => code('nothing').then(result => { + should.not.exist(result); + })); + + it('prismjs - disabled', () => { + hexo.config.highlight.enable = false; + hexo.config.prismjs.enable = false; + + return code('test.js').then(result => { + result.should.eql('
' + fixture + '
'); + }); + }); });