Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support additional options for Backtick Code Block #5625

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/extend/syntax_highlight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ export interface HighlightOptions {

// plugins/tag/code.ts
language_attr?: boolean | undefined;
firstLine?: number;
firstLine?: string | number;
line_number?: boolean | undefined;
line_threshold?: number | undefined;
mark?: number[];
mark?: number[] | string;
wrap?: boolean | undefined;

}
Expand Down
89 changes: 82 additions & 7 deletions lib/plugins/filter/before_post_render/backtick_code_block.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,87 @@
import type { HighlightOptions } from '../../../extend/syntax_highlight';
import type Hexo from '../../../hexo';
import type { RenderData } from '../../../types';

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[^\S\r\n]?(\n+|$)/gm;
const rAllOptions = /([^\s]+)\s+(.+?)\s+(https?:\/\/\S+|\/\S+)\s*(.+)?/;
const rLangCaption = /([^\s]+)\s*(.+)?/;
const rAdditionalOptions = /\s((?:line_number|line_threshold|first_line|wrap|mark|language_attr|highlight):\S+)/g;

const escapeSwigTag = (str: string) => str.replace(/{/g, '{').replace(/}/g, '}');

interface Options {
lang: string,
caption: string,
lines_length: number,
firstLineNumber?: string | number
function parseArgs(args: string) {
const matches = [];

let match: RegExpExecArray | null, language_attr: boolean,
line_number: boolean, line_threshold: number, wrap: boolean;
let enableHighlight = true;
while ((match = rAdditionalOptions.exec(args)) !== null) {
matches.push(match[1]);
}

const len = matches.length;
const mark: number[] = [];
let firstLine = 1;
for (let i = 0; i < len; i++) {
const kv = matches[i].split(':');
const key = kv[0];
const value = kv[1];

switch (key) {
case 'highlight':
enableHighlight = value === 'true';
break;
case 'line_number':
line_number = value === 'true';
break;
case 'line_threshold':
if (!isNaN(Number(value))) line_threshold = +value;
break;
case 'first_line':
if (!isNaN(Number(value))) firstLine = +value;
break;
case 'wrap':
wrap = value === 'true';
break;
case 'mark': {
for (const cur of value.split(',')) {
const hyphen = cur.indexOf('-');
if (hyphen !== -1) {
let a = +cur.slice(0, hyphen);
let b = +cur.slice(hyphen + 1);
if (Number.isNaN(a) || Number.isNaN(b)) continue;
if (b < a) { // switch a & b
const temp = a;
a = b;
b = temp;
}

for (; a <= b; a++) {
mark.push(a);
}
}
if (!isNaN(Number(cur))) mark.push(+cur);
}
break;
}
case 'language_attr': {
language_attr = value === 'true';
break;
}
}
}
return {
options: {
language_attr,
firstLine,
line_number,
line_threshold,
mark,
wrap
},
enableHighlight,
_args: args.replace(rAdditionalOptions, '')
};
}

export = (ctx: Hexo): (data: RenderData) => void => {
Expand All @@ -26,6 +96,10 @@ export = (ctx: Hexo): (data: RenderData) => void => {
// neither highlight or prismjs is enabled, return escaped content directly.
if (!ctx.extend.highlight.query(ctx.config.syntax_highlighter)) return escapeSwigTag($0);

const parsedArgs = parseArgs(_args);
if (!parsedArgs.enableHighlight) return escapeSwigTag($0);
_args = parsedArgs._args;

// Extract language and caption of code blocks
const args = _args.split('=').shift();
let lang: string, caption: string;
Expand Down Expand Up @@ -54,10 +128,11 @@ export = (ctx: Hexo): (data: RenderData) => void => {
content = content.replace(regexp, '');
}

const options: Options = {
const options: HighlightOptions = {
lang,
caption,
lines_length: content.split('\n').length
lines_length: content.split('\n').length,
...parsedArgs.options
};
// setup line number by inline
_args = _args.replace('=+', '=');
Expand Down
23 changes: 6 additions & 17 deletions lib/plugins/highlight/highlight.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import type { HighlightOptions } from '../../extend/syntax_highlight';
import type Hexo from '../../hexo';

interface Options {
line_threshold?: number;
line_number?: boolean;
lines_length?: number;
language_attr?: boolean;
caption?: string;
firstLine?: number;
lang?: string;
mark?: number[];
firstLineNumber?: number;
}

// Lazy require highlight.js
let highlight;
let highlight: typeof import('hexo-util').highlight;

module.exports = function highlightFilter(this: Hexo, code: string, options: Options) {
module.exports = function highlightFilter(this: Hexo, code: string, options: HighlightOptions) {
const hljsCfg = this.config.highlight || {} as any;
const line_threshold = options.line_threshold || hljsCfg.line_threshold || 0;
const shouldUseLineNumbers = typeof options.line_number === 'undefined' ? hljsCfg.line_number : options.line_number;
Expand All @@ -26,19 +15,19 @@ module.exports = function highlightFilter(this: Hexo, code: string, options: Opt
const hljsOptions = {
autoDetect: hljsCfg.auto_detect,
caption: options.caption,
firstLine: options.firstLine,
firstLine: options.firstLine as number,
gutter,
hljs: hljsCfg.hljs,
lang: options.lang,
languageAttr,
mark: options.mark,
mark: options.mark as number[],
tab: hljsCfg.tab_replace,
wrap: hljsCfg.wrap,
stripIndent: hljsCfg.strip_indent
};
if (hljsCfg.first_line_number === 'inline') {
if (typeof options.firstLineNumber !== 'undefined') {
hljsOptions.firstLine = options.firstLineNumber;
hljsOptions.firstLine = options.firstLineNumber as number;
} else {
hljsOptions.gutter = false;
}
Expand Down
13 changes: 8 additions & 5 deletions lib/plugins/highlight/prism.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import type { HighlightOptions } from '../../extend/syntax_highlight';
import type Hexo from '../../hexo';

// Lazy require prismjs
let prismHighlight;
let prismHighlight: typeof import('hexo-util').prismHighlight;

module.exports = function(code, options) {
const prismjsCfg = this.config.prismjs || {};
module.exports = function(this: Hexo, code: string, options: HighlightOptions) {
const prismjsCfg = this.config.prismjs || {} as any;
const line_threshold = options.line_threshold || prismjsCfg.line_threshold || 0;
const shouldUseLineNumbers = typeof options.line_number === 'undefined' ? prismjsCfg.line_number : options.line_number;
const surpassesLineThreshold = options.lines_length > line_threshold;
const lineNumber = shouldUseLineNumbers && surpassesLineThreshold;

const prismjsOptions = {
caption: options.caption,
firstLine: options.firstLine,
firstLine: options.firstLine as number,
isPreprocess: prismjsCfg.preprocess,
lang: options.lang,
lineNumber,
mark: options.mark,
mark: Array.isArray(options.mark) ? String(options.mark) : options.mark,
tab: prismjsCfg.tab_replace,
stripIndent: prismjsCfg.strip_indent
};
Expand Down
Loading
Loading