@bhsd/codemirror-mediawiki 3.12.2 → 3.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/static.d.ts CHANGED
@@ -24,6 +24,10 @@ export declare const tagModes: {
24
24
  templatedata: string;
25
25
  maplink: string;
26
26
  mapframe: string;
27
+ math: string;
28
+ chem: string;
29
+ ce: string;
30
+ score: string;
27
31
  };
28
32
  /**
29
33
  * @ignore
package/dist/static.js CHANGED
@@ -23,6 +23,10 @@ export const tagModes = {
23
23
  templatedata: 'json',
24
24
  maplink: 'jsonc',
25
25
  mapframe: 'jsonc',
26
+ math: 'text/math',
27
+ chem: 'text/math',
28
+ ce: 'text/math',
29
+ score: 'lilypond',
26
30
  };
27
31
  /**
28
32
  * @ignore
package/dist/token.d.ts CHANGED
@@ -4,7 +4,6 @@
4
4
  * @see https://gerrit.wikimedia.org/g/mediawiki/extensions/CodeMirror
5
5
  */
6
6
  import { Tag } from '@lezer/highlight';
7
- import { jsonBasic, jsonc } from './json.js';
8
7
  import type { MwConfig as MwConfigBase } from '@bhsd/cm-util';
9
8
  import type { EditorState } from '@codemirror/state';
10
9
  import type { StreamParser, StringStream as StringStreamBase } from '@codemirror/language';
@@ -28,7 +27,7 @@ export interface State extends Nesting {
28
27
  };
29
28
  readonly data: MediaWikiData;
30
29
  tokenize: Tokenizer;
31
- extMode: StreamParser<object> | false;
30
+ extMode: StreamParser<object> | boolean;
32
31
  lbrack: boolean | undefined;
33
32
  bold: boolean;
34
33
  italic: boolean;
@@ -207,7 +206,9 @@ export declare class MediaWiki {
207
206
  'text/inputbox'(): StreamParser<State>;
208
207
  inGallery(section?: boolean): Tokenizer;
209
208
  'text/gallery'(tags: string[]): StreamParser<State>;
210
- json(): typeof jsonBasic;
211
- jsonc(): typeof jsonc;
209
+ 'text/math'(): StreamParser<object>;
210
+ json(): StreamParser<object>;
211
+ jsonc(): StreamParser<object>;
212
+ lilypond(): StreamParser<object>;
212
213
  }
213
214
  export {};
package/dist/token.js CHANGED
@@ -44,6 +44,8 @@ import { decodeHTML } from '@bhsd/browser';
44
44
  import { otherParserFunctions } from '@bhsd/cm-util';
45
45
  import { htmlTags, voidHtmlTags, selfClosingTags, tokenTable, tokens } from './config.js';
46
46
  import { jsonBasic, jsonc } from './json.js';
47
+ import { math } from './math.js';
48
+ import { lilypond } from './lilypond.js';
47
49
  class MediaWikiData {
48
50
  constructor(tags, urlProtocols) {
49
51
  this.tags = tags.includes('translate') ? tags.filter(tag => tag !== 'tvar') : tags;
@@ -120,7 +122,10 @@ const copyState = (state) => {
120
122
  result[key] = [...val];
121
123
  }
122
124
  else if (key === 'extState') {
123
- result[key] = (state.extName && state.extMode && state.extMode.copyState || copyState)(val);
125
+ const f = state.extName && typeof state.extMode !== 'boolean'
126
+ && state.extMode.copyState?.bind(state.extMode)
127
+ || copyState;
128
+ result[key] = f(val);
124
129
  }
125
130
  else if (key !== 'data' && key !== 'extMode' && val && typeof val === 'object') {
126
131
  // @ts-expect-error initial value
@@ -331,7 +336,7 @@ const peekSpace = (stream, sol) => {
331
336
  const peek = stream.peek();
332
337
  return Boolean(peek && !peek.trim());
333
338
  };
334
- const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre']), pageFunctions = new Set([
339
+ const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre', 'score']), pageFunctions = new Set([
335
340
  'raw',
336
341
  'msg',
337
342
  'filepath',
@@ -343,7 +348,7 @@ const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre']), pageFunct
343
348
  'canonicalurle',
344
349
  'int',
345
350
  'msgnw',
346
- ]), substs = new Set(['subst', 'safesubst']), headerRegex = new RegExp(String.raw `^(?:[^&[<{~'\-]|${lookahead("<{~'-")})+`, 'iu'), templateRegex = new RegExp(`^(?:[^|{}<]|${lookahead('{}<', true)})+`, 'u'), argumentRegex = new RegExp(String.raw `^(?:[^|[&:}{<~'__\-]|${lookahead("}{<~'__-")})+`, 'iu'), styleRegex = new RegExp(String.raw `^(?:[^|[&}{<~'__\-]|${lookahead("}{<~'__-")})+`, 'iu'), wikiRegex = new RegExp(String.raw `^(?:[^&:'{[<~__\-]|${lookahead("'{[<~__-")})+`, 'iu'), tableDefinitionRegex = new RegExp(`^(?:[^&={<]|${lookahead('{<')})+`, 'iu'), tableCellRegex = /^\s*(?:[|!]|\{\{\s*![!)\-+]?\s*\}\})/u, extLinkChars = "[{'<-", tableDefinitionChars = '{<', tableCellChars = "'<~__{-", htmlAttrChars = '{/', freeRegex = [false, true].map(lpar => {
351
+ ]), substs = new Set(['subst', 'safesubst']), extLinkChars = "[{'<-", tableDefinitionChars = '{<', tableCellChars = "'<~__{-", htmlAttrChars = '{/', tableDefinitionLookAhead = lookahead(tableDefinitionChars), htmlAttrLookAhead = lookahead(htmlAttrChars), tableCellLookAhead = lookahead(tableCellChars), argumentLookAhead = lookahead("}{<~'__-"), headerRegex = new RegExp(String.raw `^(?:[^&[<{~'\-]|${lookahead("<{~'-")})+`, 'iu'), templateRegex = new RegExp(`^(?:[^|{}<]|${lookahead('{}<', true)})+`, 'u'), argumentRegex = new RegExp(String.raw `^(?:[^|[&:}{<~'__\-]|${argumentLookAhead})+`, 'iu'), styleRegex = new RegExp(String.raw `^(?:[^|[&}{<~'__\-]|${argumentLookAhead})+`, 'iu'), wikiRegex = new RegExp(String.raw `^(?:[^&:'{[<~__\-]|${lookahead("'{[<~__-")})+`, 'iu'), tableDefinitionRegex = new RegExp(`^(?:[^&={<]|${tableDefinitionLookAhead})+`, 'iu'), tableCellRegex = /^\s*(?:[|!]|\{\{\s*![!)\-+]?\s*\}\})/u, freeRegex = [false, true].map(lpar => {
347
352
  const punctuations = getPunctuations(lpar), source = getUrlRegex(punctuations);
348
353
  return new RegExp(`^(?:${source}|[${punctuations}]+(?=${source}))*`, 'u');
349
354
  }), indentedTableRegex = [false, true].map(isTemplate => new RegExp(String.raw `^:*\s*(?=\{${getPipe(isTemplate)})`, 'u')), tableRegex = [false, true]
@@ -354,10 +359,10 @@ const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre']), pageFunct
354
359
  new RegExp(String.raw `^(?:[<>{}]|%(?:3[ce]|[57][bd])|${lookahead('[]')})+`, 'iu'),
355
360
  new RegExp(String.raw `^(?:\}|${lookahead('[]{')})+`, 'u'),
356
361
  new RegExp(String.raw `^(?:[>}]|%(?:3[ce]|[57][bd])|${lookahead('[]{<')})+`, 'iu'),
357
- ], tableDefinitionValueRegex = ['', '='].map(equal => new RegExp(String.raw `^(?:[^\s&${tableDefinitionChars}${equal}]|${lookahead(tableDefinitionChars)})+`, 'iu')), variableRegex = [false, true].map(isDefault => new RegExp(String.raw `^(?:[^|{}<${isDefault ? String.raw `[&~'__:\-` : ''}]|\}(?!\}\})|${isDefault ? lookahead("{<~'__-") : lookahead('{<', true)})+`, 'iu')), parserFunctionRegex = ['', '[&', '[&:'].map(s => getRegex(chars => new RegExp(`^(?:[^|${s}${escapeCharClass(chars)}]|${lookahead(chars)})+`, 'iu'))), doubleUnderscoreRegex = {
362
+ ], tableDefinitionValueRegex = ['', '='].map(equal => new RegExp(String.raw `^(?:[^\s&${tableDefinitionChars}${equal}]|${tableDefinitionLookAhead})+`, 'iu')), variableRegex = [false, true].map(isDefault => new RegExp(String.raw `^(?:[^|{}<${isDefault ? String.raw `[&~'__:\-` : ''}]|\}(?!\}\})|${isDefault ? tableCellLookAhead : lookahead(tableDefinitionChars, true)})+`, 'iu')), parserFunctionRegex = ['', '[&', '[&:'].map(s => getRegex(chars => new RegExp(`^(?:[^|${s}${escapeCharClass(chars)}]|${lookahead(chars)})+`, 'iu'))), doubleUnderscoreRegex = {
358
363
  _: /^[\p{L}\p{N}_]+?__/u,
359
364
  '_': /^[\p{L}\p{N}__]+?_{2}/u,
360
- }, getExtLinkTextRegex = getRegex(pipe => new RegExp(String.raw `^(?:[^\]&${pipe}${escapeCharClass(extLinkChars)}]|${lookahead(extLinkChars)})+`, 'iu')), getExtLinkRegex = getRegex(pipe => new RegExp(`^(?:${getUrlRegex(pipe)})+`, 'u')), getTableDefinitionRegex = getRegex(s => new RegExp(`^(?:[^&${tableDefinitionChars}${s}]|${lookahead(tableDefinitionChars)})+`, 'iu')), getTableCellRegex = getRegex(s => new RegExp(`^(?:[^[&${s}${escapeCharClass(tableCellChars)}]|${lookahead(tableCellChars)})+`, 'iu')), getHtmlAttrRegex = getRegex(s => new RegExp(`^(?:[^<>&${htmlAttrChars}${s}]|${lookahead(htmlAttrChars)})+`, 'u')), getHtmlAttrKeyRegex = getRegex(pipe => new RegExp(`^(?:[^<>&={/${pipe}]|${lookahead('{/')})+`, 'u')), getExtAttrRegex = getRegex(s => new RegExp(`^(?:[^>/${s}]|${lookahead('/')})+`, 'u')), getExtTagCloseRegex = getRegex(name => name === 'onlyinclude'
365
+ }, getExtLinkTextRegex = getRegex(pipe => new RegExp(String.raw `^(?:[^\]&${pipe}${escapeCharClass(extLinkChars)}]|${lookahead(extLinkChars)})+`, 'iu')), getExtLinkRegex = getRegex(pipe => new RegExp(`^(?:${getUrlRegex(pipe)})+`, 'u')), getTableDefinitionRegex = getRegex(s => new RegExp(`^(?:[^&${tableDefinitionChars}${s}]|${tableDefinitionLookAhead})+`, 'iu')), getTableCellRegex = getRegex(s => new RegExp(`^(?:[^[&${s}${escapeCharClass(tableCellChars)}]|${tableCellLookAhead})+`, 'iu')), getHtmlAttrRegex = getRegex(s => new RegExp(`^(?:[^<>&${htmlAttrChars}${s}]|${htmlAttrLookAhead})+`, 'u')), getHtmlAttrKeyRegex = getRegex(pipe => new RegExp(`^(?:[^<>&={/${pipe}]|${htmlAttrLookAhead})+`, 'u')), getExtAttrRegex = getRegex(s => new RegExp(`^(?:[^>/${s}]|${lookahead('/')})+`, 'u')), getExtTagCloseRegex = getRegex(name => name === 'onlyinclude'
361
366
  ? /<\/onlyinclude(?:>|$)/u
362
367
  : new RegExp(String.raw `</${name}\s*(?:>|$)`, 'iu')), getNestedRegex = getRegex(tag => new RegExp(String.raw `^(?:[^<]|<(?!${tag}(?:[\s/>]|$)))+`, 'iu'));
363
368
  /** Adapted from the original CodeMirror 5 stream parser by Pavel Astakhov */
@@ -483,7 +488,7 @@ let MediaWiki = (() => {
483
488
  .join('|')}))|\d+\s*(?:${spImgKeys.filter(word => img[word] !== 'img_width').map(word => word.slice(2))
484
489
  .join('|')}))\s*(?=\||\]\]|$))`, 'u');
485
490
  this.tags = [...Object.keys(tags), 'includeonly', 'noinclude', 'onlyinclude'];
486
- this.convertRegex = new RegExp(String.raw `^(?:[^}|;&='{[<~__\-]|\}(?!-)|=(?!>)|\[(?!\[|${urlProtocols})|${lookahead("'{<~__-")})+`, 'iu');
491
+ this.convertRegex = new RegExp(String.raw `^(?:[^}|;&='{[<~__\-]|\}(?!-)|=(?!>)|\[(?!\[|${urlProtocols})|${tableCellLookAhead})+`, 'iu');
487
492
  this.convertSemicolon = variants && new RegExp(String.raw `^;\s*(?=(?:[^;]*?=>\s*)?(?:${variants.join('|')})\s*:|(?:$|\}-))`, 'iu');
488
493
  this.convertLang = variants
489
494
  && new RegExp(String.raw `^(?:=>\s*)?(?:${variants.join('|')})\s*:`, 'iu');
@@ -560,6 +565,9 @@ let MediaWiki = (() => {
560
565
  }
561
566
  for (const tag of this.tags) {
562
567
  this.addToken(`tag-${tag}`, tag !== 'nowiki' && tag !== 'pre' && tag !== 'ref');
568
+ if (tag === 'score') {
569
+ this.addToken('tag-score-scheme');
570
+ }
563
571
  this.addToken(`ext-${tag}`, true);
564
572
  }
565
573
  for (const tag of this.permittedHtmlTags) {
@@ -1267,12 +1275,17 @@ let MediaWiki = (() => {
1267
1275
  const advance = (stream, state, re) => {
1268
1276
  const mt = stream.match(re);
1269
1277
  if (isLang) {
1270
- let lang = mt[0].trim().toLowerCase();
1271
- if (lang === 'wiki' || lang === 'wikitext') {
1272
- lang = 'mediawiki';
1278
+ if (name !== 'score') {
1279
+ let lang = mt[0].trim().toLowerCase();
1280
+ if (lang === 'wiki' || lang === 'wikitext') {
1281
+ lang = 'mediawiki';
1282
+ }
1283
+ if (lang in this.config.tagModes && lang in this) {
1284
+ state.extMode = this[lang]();
1285
+ }
1273
1286
  }
1274
- if (lang in this) {
1275
- state.extMode = this[lang]();
1287
+ else if (mt[0].trim() === 'ABC') {
1288
+ state.extMode = true;
1276
1289
  }
1277
1290
  }
1278
1291
  return makeLocalStyle(tokens.extTagAttributeValue + (isPage ? ` ${tokens.pageName}` : ''), state);
@@ -1295,7 +1308,7 @@ let MediaWiki = (() => {
1295
1308
  ...state.data.tags.filter(tag => tag !== name),
1296
1309
  ...name === 'translate' ? ['tvar'] : [],
1297
1310
  ]);
1298
- if (state.extMode) {
1311
+ if (typeof state.extMode !== 'boolean') {
1299
1312
  state.extState = state.extMode.startState(0);
1300
1313
  }
1301
1314
  state.tokenize = this.eatExtTagArea(name);
@@ -1350,7 +1363,7 @@ let MediaWiki = (() => {
1350
1363
  inExtTokens(origString) {
1351
1364
  return (stream, state) => {
1352
1365
  let ret;
1353
- if (state.extMode === false) {
1366
+ if (typeof state.extMode === 'boolean') {
1354
1367
  ret = `mw-tag-${state.extName} ${tokens.extTag}`;
1355
1368
  stream.skipToEnd();
1356
1369
  }
@@ -1710,7 +1723,7 @@ let MediaWiki = (() => {
1710
1723
  };
1711
1724
  }
1712
1725
  eatEntity(stream, style) {
1713
- const entity = stream.match(/^(?:#x[a-f\d]+|#\d+|[a-z\d]+);/iu);
1726
+ const entity = stream.match(/^(?:#x[a-f\d]+|#\d+|[a-z][a-z\d]*);/iu);
1714
1727
  return entity && isHtmlEntity(entity[0]) ? tokens.htmlEntity : style;
1715
1728
  }
1716
1729
  /**
@@ -1746,7 +1759,7 @@ let MediaWiki = (() => {
1746
1759
  state[key] = other[key];
1747
1760
  }
1748
1761
  }
1749
- if (!(state.extName && state.extMode)
1762
+ if (!(state.extName && typeof state.extMode !== 'boolean')
1750
1763
  && state.nLink === 0
1751
1764
  && typeof style === 'string'
1752
1765
  && style.includes(tokens.apostrophes)) {
@@ -1869,12 +1882,12 @@ let MediaWiki = (() => {
1869
1882
  return '';
1870
1883
  },
1871
1884
  blankLine(state) {
1872
- if (state.extName && state.extMode && state.extMode.blankLine) {
1885
+ if (state.extName && typeof state.extMode !== 'boolean' && state.extMode.blankLine) {
1873
1886
  state.extMode.blankLine(state.extState, 0);
1874
1887
  }
1875
1888
  },
1876
1889
  indent(state, textAfter, context) {
1877
- return state.extName && state.extMode && state.extMode.indent
1890
+ return state.extName && typeof state.extMode !== 'boolean' && state.extMode.indent
1878
1891
  ? state.extMode.indent(state.extState, textAfter, context)
1879
1892
  : null;
1880
1893
  },
@@ -1985,8 +1998,10 @@ let MediaWiki = (() => {
1985
1998
  chain(state, this.inComment);
1986
1999
  return tokens.comment;
1987
2000
  }
1988
- /** @todo braces should also be parsed */
1989
- stream.match(/^(?:[^<]|<(?!!--))+/u);
2001
+ else if (stream.match(/^\{\{(?!\{)/u)) {
2002
+ return this.eatTransclusion(stream, state) ?? '';
2003
+ }
2004
+ stream.match(/^(?:[^<{]|<(?!!--)|\{(?!\{(?!\{)))+/u);
1990
2005
  return '';
1991
2006
  };
1992
2007
  }
@@ -2028,12 +2043,18 @@ let MediaWiki = (() => {
2028
2043
  },
2029
2044
  };
2030
2045
  }
2046
+ 'text/math'() {
2047
+ return math;
2048
+ }
2031
2049
  json() {
2032
2050
  return jsonBasic;
2033
2051
  }
2034
2052
  jsonc() {
2035
2053
  return jsonc;
2036
2054
  }
2055
+ lilypond() {
2056
+ return lilypond;
2057
+ }
2037
2058
  };
2038
2059
  })();
2039
2060
  export { MediaWiki };
package/dist/util.d.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  import type { EditorView, TooltipView, Decoration } from '@codemirror/view';
2
2
  import type { Text, EditorState, SelectionRange, Range } from '@codemirror/state';
3
+ import type { StringStream } from '@codemirror/language';
4
+ import type { Completion } from '@codemirror/autocomplete';
3
5
  import type { SyntaxNode } from '@lezer/common';
4
6
  import type { Position } from 'vscode-languageserver-types';
5
7
  import type { ConfigGetter } from '@bhsd/browser';
6
- import type { DocRange } from './fold';
8
+ export interface DocRange {
9
+ from: number;
10
+ to: number;
11
+ }
7
12
  /**
8
13
  * 转义HTML字符串
9
14
  * @param text 原字符串
@@ -52,6 +57,32 @@ export declare const braceStackUpdate: (state: EditorState, node: SyntaxNode) =>
52
57
  * @param to 结束位置
53
58
  */
54
59
  export declare const pushDecoration: (decorations: Range<Decoration>[], decoration: Decoration, from: number | DocRange, to?: number) => void;
60
+ export declare const toConfigGetter: (configGetter?: ConfigGetter, articlePath?: string) => ConfigGetter | undefined;
61
+ /**
62
+ * Tokenizer for multiline comments
63
+ * @param parent 外层 Tokenizer
64
+ * @param end 注释结束标志
65
+ */
66
+ export declare const inComment: <T extends {
67
+ tokenize(stream: StringStream, state: T): string;
68
+ }>(parent: (stream: StringStream, state: T) => string, end: string) => (stream: StringStream, state: T) => string;
69
+ /**
70
+ * 生成自动补全选项
71
+ * @param labels 选项标签列表
72
+ * @param type 选项类型
73
+ */
74
+ export declare const getCompletions: (labels: string[], type?: string) => Completion[];
75
+ /**
76
+ * 从Token类型中获取扩展标签名
77
+ * @param types Token类型列表
78
+ */
79
+ export declare const getExtTags: (types: string[]) => string[];
80
+ /**
81
+ * 获取字符串开头的空白字符
82
+ * @param str 字符串
83
+ * @test
84
+ */
85
+ export declare const leadingSpaces: (str: string) => string;
55
86
  /**
56
87
  * Mark the type in a JSDoc/LDoc comment
57
88
  * @param decorations
@@ -73,10 +104,3 @@ export declare const isTemplateParam: (node: SyntaxNode) => boolean;
73
104
  * @test
74
105
  */
75
106
  export declare const findTemplateName: (state: EditorState, node: SyntaxNode) => [string | null, string];
76
- export declare const toConfigGetter: (configGetter?: ConfigGetter, articlePath?: string) => ConfigGetter | undefined;
77
- /**
78
- * 获取字符串开头的空白字符
79
- * @param str 字符串
80
- * @test
81
- */
82
- export declare const leadingSpaces: (str: string) => string;
package/dist/util.js CHANGED
@@ -71,6 +71,42 @@ export const pushDecoration = (decorations, decoration, from, to) => {
71
71
  decorations.push(decoration.range(from, to));
72
72
  }
73
73
  };
74
+ export const toConfigGetter = (configGetter, articlePath) => articlePath
75
+ ? async () => Object.assign(await (configGetter ?? wikiparse.getConfig)(), { articlePath })
76
+ : configGetter;
77
+ /**
78
+ * Tokenizer for multiline comments
79
+ * @param parent 外层 Tokenizer
80
+ * @param end 注释结束标志
81
+ */
82
+ export const inComment = (parent, end) => (stream, state) => {
83
+ if (stream.skipTo(end)) {
84
+ stream.next();
85
+ stream.next();
86
+ state.tokenize = parent;
87
+ }
88
+ else {
89
+ stream.skipToEnd();
90
+ }
91
+ return 'comment';
92
+ };
93
+ /**
94
+ * 生成自动补全选项
95
+ * @param labels 选项标签列表
96
+ * @param type 选项类型
97
+ */
98
+ export const getCompletions = (labels, type = 'keyword') => labels.map((label) => ({ label, type }));
99
+ /**
100
+ * 从Token类型中获取扩展标签名
101
+ * @param types Token类型列表
102
+ */
103
+ export const getExtTags = (types) => types.filter(type => type.startsWith('mw-tag-')).map(type => type.slice(7));
104
+ /**
105
+ * 获取字符串开头的空白字符
106
+ * @param str 字符串
107
+ * @test
108
+ */
109
+ export const leadingSpaces = (str) => /^\s*/u.exec(str)[0];
74
110
  /**
75
111
  * Mark the type in a JSDoc/LDoc comment
76
112
  * @param decorations
@@ -150,12 +186,3 @@ export const findTemplateName = (state, node) => {
150
186
  }
151
187
  return [prevSibling && page, parameter];
152
188
  };
153
- export const toConfigGetter = (configGetter, articlePath) => articlePath
154
- ? async () => Object.assign(await (configGetter ?? wikiparse.getConfig)(), { articlePath })
155
- : configGetter;
156
- /**
157
- * 获取字符串开头的空白字符
158
- * @param str 字符串
159
- * @test
160
- */
161
- export const leadingSpaces = (str) => /^\s*/u.exec(str)[0];