Skip to content

Commit 75bc34f

Browse files
committed
enh(parser) multi-class in a single mode
1 parent 8e024dd commit 75bc34f

File tree

4 files changed

+63
-6
lines changed

4 files changed

+63
-6
lines changed

src/highlight.js

+22-3
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,30 @@ const HLJS = function(hljs) {
246246
modeBuffer = '';
247247
}
248248

249+
/**
250+
* @param {Mode} mode
251+
* @param {EnhancedMatch} match
252+
*/
253+
function emitMultiClass(mode, match) {
254+
let i = 1;
255+
while (match[i]) {
256+
const klass = mode.className[i];
257+
const text = match[i];
258+
if (klass) { emitter.addKeyword(text, klass); } else { emitter.addText(text); }
259+
i++;
260+
}
261+
}
262+
249263
/**
250264
* @param {Mode} mode - new mode to start
265+
* @param {EnhancedMatch} match
251266
*/
252-
function startNewMode(mode) {
253-
if (mode.className) {
267+
function startNewMode(mode, match) {
268+
if (mode.isMultiClass) {
269+
// at this point modeBuffer should just be the match
270+
modeBuffer = "";
271+
emitMultiClass(mode, match);
272+
} else if (mode.className) {
254273
emitter.openNode(language.classNameAliases[mode.className] || mode.className);
255274
}
256275
top = Object.create(mode, { parent: { value: top } });
@@ -340,7 +359,7 @@ const HLJS = function(hljs) {
340359
modeBuffer = lexeme;
341360
}
342361
}
343-
startNewMode(newMode);
362+
startNewMode(newMode, match);
344363
// if (mode["after:begin"]) {
345364
// let resp = new Response(mode);
346365
// mode["after:begin"](match, resp);

src/languages/vim.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Website: https://www.vim.org
66
Category: scripting
77
*/
88

9+
import * as regex from '../lib/regex.js';
10+
911
export default function(hljs) {
1012
return {
1113
name: 'Vim Script',
@@ -99,8 +101,15 @@ export default function(hljs) {
99101
begin: /[bwtglsav]:[\w\d_]+/
100102
},
101103
{
102-
className: 'function',
103-
beginKeywords: 'function function!',
104+
begin: [
105+
/function|function!/,
106+
/\s+/,
107+
hljs.IDENT_RE
108+
],
109+
className: {
110+
1: "keyword",
111+
3: "title"
112+
},
104113
end: '$',
105114
relevance: 0,
106115
contains: [

src/lib/ext/multi_class.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* eslint-disable no-throw-literal */
2+
import * as regex from "../regex.js";
3+
4+
const MultiClassError = new Error();
5+
6+
/**
7+
*
8+
* @param {CompiledMode} mode
9+
*/
10+
export function MultiClass(mode) {
11+
if (!Array.isArray(mode.begin)) return;
12+
13+
if (mode.skip || mode.excludeBegin || mode.returnBegin) {
14+
console.error("skip, excludeBegin, returnBegin not compatible with multi-class")
15+
throw MultiClassError;
16+
}
17+
18+
if (typeof mode.className !== "object") {
19+
console.error("className must be object or array");
20+
throw MultiClassError;
21+
}
22+
23+
const items = mode.begin.map(x => regex.concat("(", x, ")"));
24+
mode.begin = regex.concat(...items);
25+
mode.isMultiClass = true;
26+
27+
}

src/lib/mode_compiler.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as regex from './regex.js';
22
import { inherit } from './utils.js';
33
import * as EXT from "./compiler_extensions.js";
44
import { compileKeywords } from "./compile_keywords.js";
5+
import { MultiClass } from "./ext/multi_class.js";
56

67
// compilation
78

@@ -284,7 +285,8 @@ export function compileLanguage(language, { plugins }) {
284285
[
285286
// do this early so compiler extensions generally don't have to worry about
286287
// the distinction between match/begin
287-
EXT.compileMatch
288+
EXT.compileMatch,
289+
MultiClass
288290
].forEach(ext => ext(mode, parent));
289291

290292
language.compilerExtensions.forEach(ext => ext(mode, parent));

0 commit comments

Comments
 (0)