@bhsd/codemirror-mediawiki 3.9.2 → 3.10.1
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/README.md +147 -87
- package/dist/bidi.d.ts +9 -8
- package/dist/bidi.js +38 -23
- package/dist/codemirror.d.ts +7 -0
- package/dist/codemirror.js +22 -9
- package/dist/color.d.ts +8 -5
- package/dist/color.js +5 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -0
- package/dist/constants.d.ts +3 -2
- package/dist/constants.js +3 -2
- package/dist/css.d.ts +5 -0
- package/dist/css.js +14 -6
- package/dist/escape.d.ts +22 -2
- package/dist/escape.js +44 -25
- package/dist/fold.d.ts +57 -5
- package/dist/fold.js +149 -58
- package/dist/hover.d.ts +16 -3
- package/dist/hover.js +84 -67
- package/dist/html.js +17 -12
- package/dist/indent.d.ts +7 -0
- package/dist/indent.js +7 -1
- package/dist/index.d.ts +54 -16
- package/dist/index.js +91 -38
- package/dist/inlay.d.ts +1 -1
- package/dist/inlay.js +26 -25
- package/dist/javascript.d.ts +10 -1
- package/dist/javascript.js +50 -2
- package/dist/keybindings.d.ts +1 -0
- package/dist/keybindings.js +1 -0
- package/dist/keymap.d.ts +11 -0
- package/dist/keymap.js +3 -4
- package/dist/linter.d.ts +31 -2
- package/dist/linter.js +10 -3
- package/dist/lintsource.d.ts +47 -3
- package/dist/lintsource.js +50 -11
- package/dist/lua.d.ts +0 -2
- package/dist/lua.js +27 -10
- package/dist/main.min.js +31 -29
- package/dist/matchBrackets.d.ts +16 -0
- package/dist/matchBrackets.js +16 -0
- package/dist/matchTag.d.ts +5 -2
- package/dist/matchTag.js +11 -7
- package/dist/mediawiki.d.ts +15 -2
- package/dist/mediawiki.js +59 -45
- package/dist/mw.min.js +33 -37
- package/dist/mwConfig.js +2 -2
- package/dist/openLinks.d.ts +12 -2
- package/dist/openLinks.js +64 -54
- package/dist/ref.d.ts +16 -2
- package/dist/ref.js +110 -95
- package/dist/signature.d.ts +7 -1
- package/dist/signature.js +53 -49
- package/dist/static.d.ts +4 -0
- package/dist/static.js +4 -0
- package/dist/statusBar.js +9 -8
- package/dist/theme.d.ts +1 -0
- package/dist/theme.js +8 -0
- package/dist/token.d.ts +29 -7
- package/dist/token.js +33 -18
- package/dist/util.d.ts +25 -2
- package/dist/util.js +47 -1
- package/dist/wiki.min.js +32 -36
- package/i18n/en.json +2 -2
- package/i18n/zh-hans.json +2 -2
- package/i18n/zh-hant.json +2 -2
- package/package.json +15 -13
package/dist/theme.d.ts
CHANGED
package/dist/theme.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { EditorView } from '@codemirror/view';
|
|
2
|
+
import { syntaxHighlighting, HighlightStyle, defaultHighlightStyle } from '@codemirror/language';
|
|
2
3
|
import { nord as nordBase } from 'cm6-theme-nord';
|
|
3
4
|
import { matchingCls, nonmatchingCls, actionSelector, panelsSelector, bgDark, } from './constants.js';
|
|
4
5
|
const focused = '&.cm-focused', matching = `${focused} .${matchingCls}`, nonmatching = `${focused} .${nonmatchingCls}`;
|
|
6
|
+
export const getLightHighlightStyle = () => syntaxHighlighting(HighlightStyle.define(defaultHighlightStyle.specs, { themeType: 'light' }));
|
|
5
7
|
export const light = /* @__PURE__ */ EditorView.theme({
|
|
6
8
|
'&': {
|
|
7
9
|
backgroundColor: '#fff',
|
|
@@ -25,6 +27,9 @@ export const light = /* @__PURE__ */ EditorView.theme({
|
|
|
25
27
|
'--cm-var-name': '#ac6600',
|
|
26
28
|
'--cm-ref': 'rgb(223,242,235,.5)',
|
|
27
29
|
},
|
|
30
|
+
'.cm-globals, .cm-globals>*': {
|
|
31
|
+
color: '#164',
|
|
32
|
+
},
|
|
28
33
|
[matching]: {
|
|
29
34
|
backgroundColor: 'rgb(50,140,130,.32)',
|
|
30
35
|
},
|
|
@@ -61,6 +66,9 @@ nord = /* @__PURE__ */ (() => [
|
|
|
61
66
|
'--cm-var-name': '#d08770',
|
|
62
67
|
'--cm-ref': 'rgb(60,90,80,0.5)',
|
|
63
68
|
},
|
|
69
|
+
'.cm-globals, .cm-globals>*': {
|
|
70
|
+
color: '#d08770',
|
|
71
|
+
},
|
|
64
72
|
'div.cm-activeLine': {
|
|
65
73
|
backgroundColor: 'rgb(76,86,106,.27)',
|
|
66
74
|
},
|
package/dist/token.d.ts
CHANGED
|
@@ -13,12 +13,12 @@ declare type Style = string | [string];
|
|
|
13
13
|
declare type Tokenizer<T = Style> = ((stream: StringStream, state: State) => T) & {
|
|
14
14
|
args?: unknown[];
|
|
15
15
|
};
|
|
16
|
-
|
|
16
|
+
export type NestCount = 'nTemplate' | 'nExt' | 'nVar' | 'nLink' | 'nExtLink';
|
|
17
17
|
declare interface Nesting extends Record<NestCount, number> {
|
|
18
18
|
extName: string | false;
|
|
19
19
|
extState: object | false;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
export interface State extends Nesting {
|
|
22
22
|
readonly stack: Tokenizer[];
|
|
23
23
|
readonly inHtmlTag: string[];
|
|
24
24
|
tokenize: Tokenizer;
|
|
@@ -37,6 +37,7 @@ declare interface State extends Nesting {
|
|
|
37
37
|
imgLink: boolean;
|
|
38
38
|
data: MediaWikiData;
|
|
39
39
|
}
|
|
40
|
+
declare type ExtState = Omit<State, 'dt'> & Partial<Pick<State, 'dt'>>;
|
|
40
41
|
declare interface Token {
|
|
41
42
|
readonly char?: string | undefined;
|
|
42
43
|
readonly string: string;
|
|
@@ -44,11 +45,12 @@ declare interface Token {
|
|
|
44
45
|
pos: number;
|
|
45
46
|
style: Style;
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
+
export interface StringStream extends StringStreamBase {
|
|
48
49
|
match(pattern: string, consume?: boolean, caseInsensitive?: boolean): true | null;
|
|
49
50
|
match(pattern: RegExp, consume?: boolean): RegExpMatchArray | null;
|
|
50
51
|
}
|
|
51
|
-
export type
|
|
52
|
+
export type CompletionSectionName = 'Required' | 'Suggested' | 'Optional' | 'Deprecated';
|
|
53
|
+
export type ApiSuggestions<T = string[]> = [T, string?, string?, CompletionSectionName?][] & {
|
|
52
54
|
description?: string;
|
|
53
55
|
};
|
|
54
56
|
/**
|
|
@@ -57,17 +59,17 @@ export type ApiSuggestions = [string, string?][] & {
|
|
|
57
59
|
* @param subpage 是否为子页面
|
|
58
60
|
* @param namespace 命名空间
|
|
59
61
|
*/
|
|
60
|
-
export type ApiSuggest = (search: string, subpage?: boolean, namespace?: number) => ApiSuggestions | Promise<ApiSuggestions
|
|
62
|
+
export type ApiSuggest<T = string[]> = (search: string, subpage?: boolean, namespace?: number) => ApiSuggestions<T> | Promise<ApiSuggestions<T>>;
|
|
61
63
|
export interface MwConfig extends MwConfigBase {
|
|
62
64
|
nsid: Record<string, number>;
|
|
63
65
|
variants?: string[];
|
|
64
66
|
img?: Record<string, string>;
|
|
65
67
|
permittedHtmlTags?: string[];
|
|
66
68
|
implicitlyClosedHtmlTags?: string[];
|
|
67
|
-
|
|
69
|
+
articlePath?: string;
|
|
70
|
+
linkSuggest?: ApiSuggest<string>;
|
|
68
71
|
paramSuggest?: ApiSuggest;
|
|
69
72
|
titleParser?: (state: EditorState, node: SyntaxNode) => string | undefined;
|
|
70
|
-
isbnParser?: (link: string) => string;
|
|
71
73
|
}
|
|
72
74
|
declare class MediaWikiData {
|
|
73
75
|
/** 已解析的节点 */
|
|
@@ -83,6 +85,26 @@ declare class MediaWikiData {
|
|
|
83
85
|
readonly urlProtocols: RegExp;
|
|
84
86
|
constructor(tags: string[], urlProtocols: string);
|
|
85
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* 是否为行首语法
|
|
90
|
+
* @param stream
|
|
91
|
+
* @param table 是否允许表格
|
|
92
|
+
* @param file 是否为文件
|
|
93
|
+
* @test
|
|
94
|
+
*/
|
|
95
|
+
export declare const isSolSyntax: (stream: StringStream, table?: boolean, file?: boolean) => unknown;
|
|
96
|
+
/**
|
|
97
|
+
* 获取负向先行断言
|
|
98
|
+
* @param chars
|
|
99
|
+
* @param comment 是否仅排除注释
|
|
100
|
+
* @test
|
|
101
|
+
*/
|
|
102
|
+
export declare const lookahead: (chars: string, comment?: boolean | State) => string;
|
|
103
|
+
/**
|
|
104
|
+
* @ignore
|
|
105
|
+
* @test
|
|
106
|
+
*/
|
|
107
|
+
export declare const makeLocalStyle: (style: string, state: ExtState, endGround?: NestCount) => string;
|
|
86
108
|
/** Adapted from the original CodeMirror 5 stream parser by Pavel Astakhov */
|
|
87
109
|
export declare class MediaWiki {
|
|
88
110
|
readonly config: MwConfig;
|
package/dist/token.js
CHANGED
|
@@ -153,16 +153,18 @@ const pop = (state) => {
|
|
|
153
153
|
* @param stream
|
|
154
154
|
* @param table 是否允许表格
|
|
155
155
|
* @param file 是否为文件
|
|
156
|
+
* @test
|
|
156
157
|
*/
|
|
157
|
-
const isSolSyntax = (stream, table, file) => stream.sol() && (table && stream.match(/^\s*(?::+\s*)?\{\|/u, false)
|
|
158
|
+
export const isSolSyntax = (stream, table, file) => stream.sol() && (table && stream.match(/^\s*(?::+\s*)?\{\|/u, false)
|
|
158
159
|
|| stream.match(/^(?:-{4}|=)/u, false)
|
|
159
160
|
|| !file && /[*#;:]/u.test(stream.peek() || ''));
|
|
160
161
|
/**
|
|
161
162
|
* 获取负向先行断言
|
|
162
163
|
* @param chars
|
|
163
164
|
* @param comment 是否仅排除注释
|
|
165
|
+
* @test
|
|
164
166
|
*/
|
|
165
|
-
const lookahead = (chars, comment) => {
|
|
167
|
+
export const lookahead = (chars, comment) => {
|
|
166
168
|
const table = {
|
|
167
169
|
"'": "'(?!')",
|
|
168
170
|
'{': String.raw `\{(?!\{)`,
|
|
@@ -212,7 +214,11 @@ const getTokenizer = (method, context) => function (...args) {
|
|
|
212
214
|
const makeFullStyle = (style, state) => (typeof style === 'string'
|
|
213
215
|
? style
|
|
214
216
|
: `${style[0]} ${state.bold || state.dt?.n ? tokens.strong : ''} ${state.italic ? tokens.em : ''}`).trim().replace(/\s{2,}/gu, ' ') || ' ';
|
|
215
|
-
|
|
217
|
+
/**
|
|
218
|
+
* @ignore
|
|
219
|
+
* @test
|
|
220
|
+
*/
|
|
221
|
+
export const makeLocalStyle = (style, state, endGround) => {
|
|
216
222
|
let ground = '';
|
|
217
223
|
switch (state.nTemplate) {
|
|
218
224
|
case 0:
|
|
@@ -305,6 +311,11 @@ const getQuote = (stream) => {
|
|
|
305
311
|
* @param t Tokenizer
|
|
306
312
|
*/
|
|
307
313
|
const getEqual = (t) => t.name === 'inTemplateArgument' && t.args[0] ? '=' : '';
|
|
314
|
+
/**
|
|
315
|
+
* 转义字符类中的特殊字符
|
|
316
|
+
* @param chars 字符类
|
|
317
|
+
*/
|
|
318
|
+
const escapeCharClass = (chars) => chars.replace(/[\]-]/gu, String.raw `\$&`);
|
|
308
319
|
/**
|
|
309
320
|
* 下一个字符是否为空白字符
|
|
310
321
|
* @param stream StringStream
|
|
@@ -329,21 +340,21 @@ const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre']), pageFunct
|
|
|
329
340
|
'canonicalurle',
|
|
330
341
|
'int',
|
|
331
342
|
'msgnw',
|
|
332
|
-
]), substs = new Set(['subst', 'safesubst']), headerRegex = new RegExp(`^(?:[^&[<{~'
|
|
343
|
+
]), 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 => {
|
|
333
344
|
const punctuations = getPunctuations(lpar), source = getUrlRegex(punctuations);
|
|
334
345
|
return new RegExp(`^(?:${source}|[${punctuations}]+(?=${source}))*`, 'u');
|
|
335
346
|
}), indentedTableRegex = [false, true].map(isTemplate => new RegExp(String.raw `^:*\s*(?=\{${getPipe(isTemplate)})`, 'u')), tableRegex = [false, true]
|
|
336
347
|
.map(isTemplate => new RegExp(String.raw `^${getPipe(isTemplate)}\s*`, 'u')), spacedTableRegex = [false, true].map(isTemplate => new RegExp(String.raw `^\s*(:+\s*)?(?=\{${getPipe(isTemplate)})`, 'u')), linkTextRegex = [false, true].map(file => {
|
|
337
348
|
const chars = `]'{<${file ? '~' : '['}-`;
|
|
338
|
-
return new RegExp(`^(?:[^&${file ? '[|' : ''}
|
|
349
|
+
return new RegExp(`^(?:[^&${file ? '[|' : ''}${escapeCharClass(chars)}]|${lookahead(chars)})+`, 'iu');
|
|
339
350
|
}), linkErrorRegex = [
|
|
340
351
|
new RegExp(String.raw `^(?:[<>{}]|%(?:3[ce]|[57][bd])|${lookahead('[]')})+`, 'iu'),
|
|
341
352
|
new RegExp(String.raw `^(?:\}|${lookahead('[]{')})+`, 'u'),
|
|
342
353
|
new RegExp(String.raw `^(?:[>}]|%(?:3[ce]|[57][bd])|${lookahead('[]{<')})+`, 'iu'),
|
|
343
|
-
], tableDefinitionValueRegex = ['', '='].map(equal => new RegExp(String.raw `^(?:[^\s&${tableDefinitionChars}${equal}]|${lookahead(tableDefinitionChars)})+`, 'iu')), variableRegex = [false, true].map(isDefault => new RegExp(String.raw `^(?:[^|{}<${isDefault ?
|
|
354
|
+
], 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 = {
|
|
344
355
|
_: /^[\p{L}\p{N}_]+?__/u,
|
|
345
356
|
'_': /^[\p{L}\p{N}__]+?_{2}/u,
|
|
346
|
-
}, getExtLinkTextRegex = getRegex(pipe => new RegExp(String.raw `^(?:[^\]&${pipe}${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}${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'
|
|
357
|
+
}, 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'
|
|
347
358
|
? /<\/onlyinclude(?:>|$)/u
|
|
348
359
|
: new RegExp(String.raw `</${name}\s*(?:>|$)`, 'iu')), getNestedRegex = getRegex(tag => new RegExp(String.raw `^(?:[^<]|<(?!${tag}(?:[\s/>]|$)))+`, 'iu'));
|
|
349
360
|
/** Adapted from the original CodeMirror 5 stream parser by Pavel Astakhov */
|
|
@@ -463,15 +474,18 @@ let MediaWiki = (() => {
|
|
|
463
474
|
this.fileRegex = new RegExp(String.raw `^(?:${Object.entries(nsid).filter(([, id]) => id === 6).map(([ns]) => ns).join('|')})\s*:`, 'iu');
|
|
464
475
|
this.redirectRegex = new RegExp(String.raw `^\s*(?:${redirection.join('|')})(\s*:)?\s*(?=\[\[|$)`, 'iu');
|
|
465
476
|
this.img = Object.keys(img).filter(word => !/\$1./u.test(word));
|
|
477
|
+
const spImgKeys = Object.keys(img).filter(word => word.startsWith('$1'));
|
|
466
478
|
this.imgRegex = new RegExp(String.raw `^(?:${this.img.filter(word => word.endsWith('$1')).map(word => word.slice(0, -2))
|
|
467
|
-
.join('|')}|(?:${this.img.filter(word => !word.endsWith('$1')).join('|')}|(?:\d+x?|\d*x\d+)\s*(?:px)?
|
|
479
|
+
.join('|')}|(?:${this.img.filter(word => !word.endsWith('$1')).join('|')}|(?:(?:\d+x?|\d*x\d+)\s*(?:px)?(?:${spImgKeys.filter(word => img[word] === 'img_width').map(word => word.slice(2))
|
|
480
|
+
.join('|')}))|\d+\s*(?:${spImgKeys.filter(word => img[word] !== 'img_width').map(word => word.slice(2))
|
|
481
|
+
.join('|')}))\s*(?=\||\]\]|$))`, 'u');
|
|
468
482
|
this.tags = [...Object.keys(tags), 'includeonly', 'noinclude', 'onlyinclude'];
|
|
469
|
-
this.convertRegex = new RegExp(String.raw `^(?:[^}|;&='{[<~_
|
|
483
|
+
this.convertRegex = new RegExp(String.raw `^(?:[^}|;&='{[<~__\-]|\}(?!-)|=(?!>)|\[(?!\[|${urlProtocols})|${lookahead("'{<~__-")})+`, 'iu');
|
|
470
484
|
this.convertSemicolon = variants && new RegExp(String.raw `^;\s*(?=(?:[^;]*?=>\s*)?(?:${variants.join('|')})\s*:|(?:$|\}-))`, 'iu');
|
|
471
485
|
this.convertLang = variants
|
|
472
486
|
&& new RegExp(String.raw `^(?:=>\s*)?(?:${variants.join('|')})\s*:`, 'iu');
|
|
473
487
|
this.hasVariants = Boolean(variants?.length);
|
|
474
|
-
this.preRegex = [false, true].map(begin => new RegExp(String.raw `^(?:[
|
|
488
|
+
this.preRegex = [false, true].map(begin => new RegExp(String.raw `^(?:[^<&\-]|-${this.hasVariants ? String.raw `(?!\{)` : ''}|<(?!${begin ? '/' : ''}nowiki>))+`, 'iu'));
|
|
475
489
|
this.substRegex = new RegExp(String.raw `^\s*(?:(${Object.entries(insensitive).filter(([, v]) => substs.has(v))
|
|
476
490
|
.map(([k]) => k + (k.endsWith(':') ? '' : ':'))
|
|
477
491
|
.join('|')})\s*)?`, 'iu');
|
|
@@ -775,7 +789,7 @@ let MediaWiki = (() => {
|
|
|
775
789
|
stream.backUp(1);
|
|
776
790
|
}
|
|
777
791
|
else {
|
|
778
|
-
stream.eatWhile(/[^\p{L}\p{N}__&'{[
|
|
792
|
+
stream.eatWhile(/[^\p{L}\p{N}__&'{[<\-~:]/u);
|
|
779
793
|
}
|
|
780
794
|
const mt = stream.match(this.urlProtocols, false);
|
|
781
795
|
if (mt) {
|
|
@@ -1046,7 +1060,7 @@ let MediaWiki = (() => {
|
|
|
1046
1060
|
return (stream, state) => {
|
|
1047
1061
|
if (stream.sol()) {
|
|
1048
1062
|
stream.eatSpace();
|
|
1049
|
-
const mt = stream.match(/^(?:\||\{\{\s*!([!)
|
|
1063
|
+
const mt = stream.match(/^(?:\||\{\{\s*!([!)\-+])?\s*\}\})/u);
|
|
1050
1064
|
if (mt) {
|
|
1051
1065
|
if (mt[1] === '-' || !mt[1] && stream.eat('-')) {
|
|
1052
1066
|
stream.match(/^-*\s*/u);
|
|
@@ -1648,7 +1662,7 @@ let MediaWiki = (() => {
|
|
|
1648
1662
|
if (expectName
|
|
1649
1663
|
&& stream.match(new RegExp(`^(?:[^=|}{[<]|${lookahead('}{[<', state)})*=`, 'iu'))) {
|
|
1650
1664
|
state.tokenize = this.inTemplateArgument(false, parserFunction);
|
|
1651
|
-
return makeLocalTagStyle('templateArgumentName', state);
|
|
1665
|
+
return makeLocalTagStyle(parserFunction ? 'parserFunctionArgumentName' : 'templateArgumentName', state);
|
|
1652
1666
|
}
|
|
1653
1667
|
else if (isSolSyntax(stream) && stream.peek() !== '=') {
|
|
1654
1668
|
return this.eatWikiText(tag)(stream, state);
|
|
@@ -1684,7 +1698,7 @@ let MediaWiki = (() => {
|
|
|
1684
1698
|
if (stream.match('-{', false)) {
|
|
1685
1699
|
return this.eatWikiText(style)(stream, state);
|
|
1686
1700
|
}
|
|
1687
|
-
stream.match(/^(?:(?:[^}
|
|
1701
|
+
stream.match(/^(?:(?:[^}\-;=]|\}(?!-)|=(?!>)|-(?!\{))+|;|=>)/u);
|
|
1688
1702
|
return makeStyle(style, state);
|
|
1689
1703
|
}
|
|
1690
1704
|
return !isSolSyntax(stream, true) && stream.match(this.convertRegex) || space
|
|
@@ -1782,16 +1796,17 @@ let MediaWiki = (() => {
|
|
|
1782
1796
|
// get token style
|
|
1783
1797
|
stream.start = stream.pos;
|
|
1784
1798
|
const char = stream.peek(), style = state.tokenize(stream, state);
|
|
1785
|
-
if (typeof style === 'string' && style.includes(
|
|
1799
|
+
if (typeof style === 'string' && style.includes('-argument-name')) {
|
|
1800
|
+
const isTemplate = style.includes(tokens.templateArgumentName), argument = tokens[isTemplate ? 'template' : 'parserFunction'], argumentName = tokens[isTemplate ? 'templateArgumentName' : 'parserFunctionArgumentName'], delimiter = tokens[isTemplate ? 'templateDelimiter' : 'parserFunctionDelimiter'];
|
|
1786
1801
|
for (let i = readyTokens.length - 1; i >= 0; i--) {
|
|
1787
1802
|
const token = readyTokens[i];
|
|
1788
1803
|
if (cmpNesting(state, token.state, true)) {
|
|
1789
|
-
const types = typeof token.style === 'string' && token.style.split(' '), j = types && types.indexOf(
|
|
1804
|
+
const types = typeof token.style === 'string' && token.style.split(' '), j = types && types.indexOf(argument);
|
|
1790
1805
|
if (j !== false && j !== -1) {
|
|
1791
|
-
types[j] =
|
|
1806
|
+
types[j] = argumentName;
|
|
1792
1807
|
token.style = types.join(' ');
|
|
1793
1808
|
}
|
|
1794
|
-
else if (types && types.includes(
|
|
1809
|
+
else if (types && types.includes(delimiter)) {
|
|
1795
1810
|
break;
|
|
1796
1811
|
}
|
|
1797
1812
|
}
|
package/dist/util.d.ts
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import type { EditorView, TooltipView } from '@codemirror/view';
|
|
2
|
-
import type { Text, EditorState } from '@codemirror/state';
|
|
2
|
+
import type { Text, EditorState, SelectionRange } from '@codemirror/state';
|
|
3
3
|
import type { SyntaxNode } from '@lezer/common';
|
|
4
4
|
import type { Position } from 'vscode-languageserver-types';
|
|
5
|
+
import type { ConfigGetter } from '@bhsd/browser';
|
|
6
|
+
import type { TagName } from './config';
|
|
5
7
|
/**
|
|
6
8
|
* 转义HTML字符串
|
|
7
9
|
* @param text 原字符串
|
|
10
|
+
* @test
|
|
8
11
|
*/
|
|
9
12
|
export declare const escHTML: (text: string) => string;
|
|
10
13
|
/**
|
|
11
14
|
* 将索引转换为位置
|
|
12
15
|
* @param doc Text 实例
|
|
13
16
|
* @param index 索引
|
|
17
|
+
* @test
|
|
14
18
|
*/
|
|
15
19
|
export declare const indexToPos: (doc: Text, index: number) => Position;
|
|
16
20
|
/**
|
|
17
21
|
* 将位置转换为索引
|
|
18
22
|
* @param doc Text 实例
|
|
19
23
|
* @param pos 位置
|
|
24
|
+
* @test
|
|
20
25
|
*/
|
|
21
26
|
export declare const posToIndex: (doc: Text, pos: Position) => number;
|
|
22
27
|
/**
|
|
@@ -25,20 +30,38 @@ export declare const posToIndex: (doc: Text, pos: Position) => number;
|
|
|
25
30
|
* @param innerHTML 提示内容
|
|
26
31
|
*/
|
|
27
32
|
export declare const createTooltipView: (view: EditorView, innerHTML: string) => TooltipView;
|
|
33
|
+
/**
|
|
34
|
+
* 获取节点对应的字符串
|
|
35
|
+
* @param state EditorState 实例
|
|
36
|
+
* @param node 语法树节点
|
|
37
|
+
* @test
|
|
38
|
+
*/
|
|
39
|
+
export declare const sliceDoc: (state: EditorState, node: SyntaxNode | SelectionRange) => string;
|
|
28
40
|
/**
|
|
29
41
|
* Update the stack of opening (+) or closing (-) brackets
|
|
30
42
|
* @param state
|
|
31
43
|
* @param node 语法树节点
|
|
44
|
+
* @test
|
|
32
45
|
*/
|
|
33
46
|
export declare const braceStackUpdate: (state: EditorState, node: SyntaxNode) => [number, number];
|
|
47
|
+
/**
|
|
48
|
+
* Find the current template name
|
|
49
|
+
* @param state
|
|
50
|
+
* @param node 语法树节点
|
|
51
|
+
* @test
|
|
52
|
+
*/
|
|
53
|
+
export declare const findTemplateName: (state: EditorState, node: SyntaxNode) => string | null;
|
|
34
54
|
/**
|
|
35
55
|
* 判断节点是否包含指定类型
|
|
36
56
|
* @param types 节点类型
|
|
37
57
|
* @param names 指定类型
|
|
58
|
+
* @test
|
|
38
59
|
*/
|
|
39
|
-
export declare const hasTag: (types: Set<string>, names:
|
|
60
|
+
export declare const hasTag: (types: Set<string>, names: TagName | TagName[]) => boolean;
|
|
61
|
+
export declare const toConfigGetter: (configGetter?: ConfigGetter, articlePath?: string) => ConfigGetter | undefined;
|
|
40
62
|
/**
|
|
41
63
|
* 获取字符串开头的空白字符
|
|
42
64
|
* @param str 字符串
|
|
65
|
+
* @test
|
|
43
66
|
*/
|
|
44
67
|
export declare const leadingSpaces: (str: string) => string;
|
package/dist/util.js
CHANGED
|
@@ -5,12 +5,14 @@ const dict = { '\n': '<br>', '&': '&', '<': '<' };
|
|
|
5
5
|
/**
|
|
6
6
|
* 转义HTML字符串
|
|
7
7
|
* @param text 原字符串
|
|
8
|
+
* @test
|
|
8
9
|
*/
|
|
9
10
|
export const escHTML = (text) => text.replace(/[\n<&]/gu, ch => dict[ch]);
|
|
10
11
|
/**
|
|
11
12
|
* 将索引转换为位置
|
|
12
13
|
* @param doc Text 实例
|
|
13
14
|
* @param index 索引
|
|
15
|
+
* @test
|
|
14
16
|
*/
|
|
15
17
|
export const indexToPos = (doc, index) => {
|
|
16
18
|
const line = doc.lineAt(index);
|
|
@@ -20,6 +22,7 @@ export const indexToPos = (doc, index) => {
|
|
|
20
22
|
* 将位置转换为索引
|
|
21
23
|
* @param doc Text 实例
|
|
22
24
|
* @param pos 位置
|
|
25
|
+
* @test
|
|
23
26
|
*/
|
|
24
27
|
export const posToIndex = (doc, pos) => {
|
|
25
28
|
const line = doc.line(pos.line + 1);
|
|
@@ -36,23 +39,66 @@ export const createTooltipView = (view, innerHTML) => {
|
|
|
36
39
|
inner.innerHTML = innerHTML;
|
|
37
40
|
return { dom };
|
|
38
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* 获取节点对应的字符串
|
|
44
|
+
* @param state EditorState 实例
|
|
45
|
+
* @param node 语法树节点
|
|
46
|
+
* @test
|
|
47
|
+
*/
|
|
48
|
+
export const sliceDoc = (state, node) => state.sliceDoc(node.from, node.to);
|
|
39
49
|
/**
|
|
40
50
|
* Update the stack of opening (+) or closing (-) brackets
|
|
41
51
|
* @param state
|
|
42
52
|
* @param node 语法树节点
|
|
53
|
+
* @test
|
|
43
54
|
*/
|
|
44
55
|
export const braceStackUpdate = (state, node) => {
|
|
45
|
-
const brackets =
|
|
56
|
+
const brackets = sliceDoc(state, node);
|
|
46
57
|
return [brackets.split('{{').length - 1, 1 - brackets.split('}}').length];
|
|
47
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* Find the current template name
|
|
61
|
+
* @param state
|
|
62
|
+
* @param node 语法树节点
|
|
63
|
+
* @test
|
|
64
|
+
*/
|
|
65
|
+
export const findTemplateName = (state, node) => {
|
|
66
|
+
let stack = -1, { prevSibling } = node,
|
|
67
|
+
/** 可包含`_`、`:`等 */ page = '';
|
|
68
|
+
while (prevSibling) {
|
|
69
|
+
const { name } = prevSibling;
|
|
70
|
+
if (name.includes(tokens.templateBracket)) {
|
|
71
|
+
const [lbrace, rbrace] = braceStackUpdate(state, prevSibling);
|
|
72
|
+
stack += lbrace;
|
|
73
|
+
if (stack >= 0) {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
stack += rbrace;
|
|
77
|
+
}
|
|
78
|
+
else if (stack === -1 && name.includes(tokens.templateName)) {
|
|
79
|
+
page = sliceDoc(state, prevSibling) + page;
|
|
80
|
+
}
|
|
81
|
+
else if (page && !name.includes(tokens.comment)) {
|
|
82
|
+
prevSibling = null;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
({ prevSibling } = prevSibling);
|
|
86
|
+
}
|
|
87
|
+
return prevSibling && page;
|
|
88
|
+
};
|
|
48
89
|
/**
|
|
49
90
|
* 判断节点是否包含指定类型
|
|
50
91
|
* @param types 节点类型
|
|
51
92
|
* @param names 指定类型
|
|
93
|
+
* @test
|
|
52
94
|
*/
|
|
53
95
|
export const hasTag = (types, names) => (Array.isArray(names) ? names : [names]).some(name => types.has(name in tokens ? tokens[name] : name));
|
|
96
|
+
export const toConfigGetter = (configGetter, articlePath) => articlePath
|
|
97
|
+
? async () => Object.assign(await (configGetter ?? wikiparse.getConfig)(), { articlePath })
|
|
98
|
+
: configGetter;
|
|
54
99
|
/**
|
|
55
100
|
* 获取字符串开头的空白字符
|
|
56
101
|
* @param str 字符串
|
|
102
|
+
* @test
|
|
57
103
|
*/
|
|
58
104
|
export const leadingSpaces = (str) => /^\s*/u.exec(str)[0];
|