@bhsd/codemirror-mediawiki 3.12.1 → 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/codemirror.d.ts +2 -1
- package/dist/codemirror.js +5 -5
- package/dist/constants.d.ts +2 -1
- package/dist/constants.js +1 -1
- package/dist/css.js +2 -2
- package/dist/escape.js +9 -10
- package/dist/fold.d.ts +5 -8
- package/dist/fold.js +18 -18
- package/dist/hover.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/inlay.js +2 -2
- package/dist/javascript.d.ts +1 -1
- package/dist/javascript.js +8 -4
- package/dist/json.d.ts +8 -0
- package/dist/json.js +101 -0
- package/dist/keymap.d.ts +8 -1
- package/dist/keymap.js +89 -7
- package/dist/lilypond.d.ts +14 -0
- package/dist/lilypond.js +240 -0
- package/dist/lint.js +2 -2
- package/dist/lintsource.d.ts +1 -1
- package/dist/lintsource.js +7 -7
- package/dist/lua.d.ts +1 -1
- package/dist/lua.js +39 -63
- package/dist/main.min.js +32 -31
- package/dist/matchBrackets.d.ts +3 -11
- package/dist/matchBrackets.js +51 -39
- package/dist/matchTag.d.ts +5 -5
- package/dist/matchTag.js +4 -4
- package/dist/math.d.ts +3 -0
- package/dist/math.js +58 -0
- package/dist/mediawiki.d.ts +2 -3
- package/dist/mediawiki.js +34 -26
- package/dist/mw.min.js +33 -32
- package/dist/ref.d.ts +2 -2
- package/dist/ref.js +5 -5
- package/dist/signature.js +13 -13
- package/dist/static.d.ts +7 -0
- package/dist/static.js +7 -0
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +9 -3
- package/dist/token.d.ts +10 -6
- package/dist/token.js +54 -20
- package/dist/util.d.ts +35 -10
- package/dist/util.js +43 -15
- package/dist/wiki.min.js +33 -32
- package/i18n/en.json +1 -1
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/package.json +8 -10
package/dist/ref.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EditorState, Extension } from '@codemirror/state';
|
|
2
2
|
import type { CodeMirror6 } from './codemirror';
|
|
3
|
-
import type {
|
|
3
|
+
import type { WikiTag } from './matchTag';
|
|
4
4
|
/**
|
|
5
5
|
* 高亮<ref>内容
|
|
6
6
|
* @param state 编辑器EditorState
|
|
@@ -13,6 +13,6 @@ export declare const highlightRef: (state: EditorState, text: string) => string;
|
|
|
13
13
|
* @ignore
|
|
14
14
|
* @test
|
|
15
15
|
*/
|
|
16
|
-
export declare const needHover: (state: EditorState, { name, selfClosing, first, last }:
|
|
16
|
+
export declare const needHover: (state: EditorState, { name, selfClosing, first, last }: WikiTag) => boolean;
|
|
17
17
|
declare const _default: (articlePath?: string) => (cm: CodeMirror6) => Extension;
|
|
18
18
|
export default _default;
|
package/dist/ref.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ensureSyntaxTree, language, highlightingFor } from '@codemirror/languag
|
|
|
3
3
|
import { highlightCode } from '@lezer/highlight';
|
|
4
4
|
import { getLSP } from '@bhsd/browser';
|
|
5
5
|
import elt from 'crelt';
|
|
6
|
-
import {
|
|
6
|
+
import { baseData } from './constants.js';
|
|
7
7
|
import { tokens } from './config.js';
|
|
8
8
|
import { getTag } from './matchTag.js';
|
|
9
9
|
import { sliceDoc, indexToPos, posToIndex, escHTML, toConfigGetter, } from './util.js';
|
|
@@ -13,7 +13,7 @@ const trees = new WeakMap(), selector = '.cm-tooltip-ref', noDef = '.cm-tooltip-
|
|
|
13
13
|
* @param state
|
|
14
14
|
* @param node 语法树节点
|
|
15
15
|
*/
|
|
16
|
-
const
|
|
16
|
+
const getRefName = (state, node) => sliceDoc(state, node).trim();
|
|
17
17
|
/**
|
|
18
18
|
* 高亮<ref>内容
|
|
19
19
|
* @param state 编辑器EditorState
|
|
@@ -45,7 +45,7 @@ export const needHover = (state, { name, selfClosing, first, last }) => {
|
|
|
45
45
|
if (name === 'ref' && selfClosing) {
|
|
46
46
|
let prevSibling = last, nextSibling = null;
|
|
47
47
|
while (prevSibling && prevSibling.from > first.to) {
|
|
48
|
-
const key =
|
|
48
|
+
const key = getRefName(state, prevSibling);
|
|
49
49
|
if (prevSibling.name.split('_').includes(tokens.extTagAttribute)
|
|
50
50
|
&& /(?:^|\s)name(?:$|[\s=])/iu.test(key)) {
|
|
51
51
|
if (/(?:^|\s)name\s*=/iu.test(key)) {
|
|
@@ -56,7 +56,7 @@ export const needHover = (state, { name, selfClosing, first, last }) => {
|
|
|
56
56
|
({ prevSibling } = prevSibling);
|
|
57
57
|
}
|
|
58
58
|
if (nextSibling?.name.includes(tokens.extTagAttributeValue)) {
|
|
59
|
-
let target =
|
|
59
|
+
let target = getRefName(state, nextSibling);
|
|
60
60
|
const quote = target.charAt(0);
|
|
61
61
|
if (quote === '"' || quote === "'") {
|
|
62
62
|
target = target.slice(1, target.slice(-1) === quote ? -1 : undefined).trim();
|
|
@@ -75,7 +75,7 @@ export default (articlePath) => (cm) => {
|
|
|
75
75
|
if (node?.name.includes('-exttag-')) {
|
|
76
76
|
const tag = getTag(state, node);
|
|
77
77
|
if (tag && needHover(state, tag)) {
|
|
78
|
-
const { doc } = state, ref = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath),
|
|
78
|
+
const { doc } = state, ref = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), baseData.CDN)?.provideDefinition(doc.toString(), indexToPos(doc, tag.first.to));
|
|
79
79
|
return {
|
|
80
80
|
pos,
|
|
81
81
|
end: tag.to,
|
package/dist/signature.js
CHANGED
|
@@ -2,16 +2,16 @@ import { EditorView, showTooltip } from '@codemirror/view';
|
|
|
2
2
|
import { StateField, StateEffect } from '@codemirror/state';
|
|
3
3
|
import { syntaxTree } from '@codemirror/language';
|
|
4
4
|
import { getLSP } from '@bhsd/browser';
|
|
5
|
-
import {
|
|
6
|
-
import { createTooltipView, indexToPos, escHTML, toConfigGetter, findTemplateName,
|
|
7
|
-
const
|
|
5
|
+
import { baseData } from './constants.js';
|
|
6
|
+
import { createTooltipView, indexToPos, escHTML, toConfigGetter, findTemplateName, isTemplateParam, } from './util.js';
|
|
7
|
+
const signatureEffect = StateEffect.define(), signatureField = StateField.define({
|
|
8
8
|
create() {
|
|
9
9
|
return undefined;
|
|
10
10
|
},
|
|
11
11
|
update(oldValue, { state: { doc, selection: { main: { head } } }, effects }) {
|
|
12
12
|
const text = doc.toString();
|
|
13
13
|
for (const effect of effects) {
|
|
14
|
-
if (effect.is(
|
|
14
|
+
if (effect.is(signatureEffect)) {
|
|
15
15
|
const { value } = effect;
|
|
16
16
|
if (head === value.cursor && text === value.text) {
|
|
17
17
|
return value;
|
|
@@ -40,25 +40,25 @@ export const getSignatureHelp = ({ signatures, activeParameter: active }) => sig
|
|
|
40
40
|
}).join('<br>');
|
|
41
41
|
export default (articlePath) => (cm) => {
|
|
42
42
|
return [
|
|
43
|
-
|
|
43
|
+
signatureField,
|
|
44
44
|
EditorView.updateListener.of(({ view, state, docChanged, selectionSet }) => {
|
|
45
|
-
if (docChanged || selectionSet && state.field(
|
|
45
|
+
if (docChanged || selectionSet && state.field(signatureField)?.signatureHelp?.signatures.length) {
|
|
46
46
|
const { doc, selection: { main } } = state, { head: cursor } = main, text = doc.toString();
|
|
47
47
|
if (!main.empty) {
|
|
48
48
|
view.dispatch({
|
|
49
|
-
effects:
|
|
49
|
+
effects: signatureEffect.of({ text, cursor }),
|
|
50
50
|
});
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
(async () => {
|
|
54
|
-
let signatureHelp = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath),
|
|
54
|
+
let signatureHelp = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), baseData.CDN)?.provideSignatureHelp(text, indexToPos(doc, cursor));
|
|
55
55
|
if (!signatureHelp && typeof cm.langConfig?.templateSignature === 'function') {
|
|
56
56
|
const tree = syntaxTree(state);
|
|
57
57
|
let node = tree.resolve(cursor, -1);
|
|
58
|
-
if (node.to === cursor && !
|
|
58
|
+
if (node.to === cursor && !isTemplateParam(node)) {
|
|
59
59
|
node = tree.resolve(cursor, 1);
|
|
60
60
|
}
|
|
61
|
-
if (
|
|
61
|
+
if (isTemplateParam(node)) {
|
|
62
62
|
const [templateName, parameterName] = findTemplateName(state, node), tooltip = cm.langConfig.templateSignature(templateName, parameterName);
|
|
63
63
|
if (tooltip) {
|
|
64
64
|
signatureHelp = { signatures: [tooltip] };
|
|
@@ -66,7 +66,7 @@ export default (articlePath) => (cm) => {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
view.dispatch({
|
|
69
|
-
effects:
|
|
69
|
+
effects: signatureEffect.of({ text, cursor, signatureHelp }),
|
|
70
70
|
});
|
|
71
71
|
})();
|
|
72
72
|
}
|
|
@@ -76,12 +76,12 @@ export default (articlePath) => (cm) => {
|
|
|
76
76
|
if (key === 'Escape') {
|
|
77
77
|
const { doc, selection: { main: { head } } } = view.state;
|
|
78
78
|
view.dispatch({
|
|
79
|
-
effects:
|
|
79
|
+
effects: signatureEffect.of({ text: doc.toString(), cursor: head }),
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
}),
|
|
84
|
-
showTooltip.from(
|
|
84
|
+
showTooltip.from(signatureField, (value) => {
|
|
85
85
|
if (!value) {
|
|
86
86
|
return null;
|
|
87
87
|
}
|
package/dist/static.d.ts
CHANGED
|
@@ -21,6 +21,13 @@ export declare const tagModes: {
|
|
|
21
21
|
combobox: string;
|
|
22
22
|
combooption: string;
|
|
23
23
|
inputbox: string;
|
|
24
|
+
templatedata: string;
|
|
25
|
+
maplink: string;
|
|
26
|
+
mapframe: string;
|
|
27
|
+
math: string;
|
|
28
|
+
chem: string;
|
|
29
|
+
ce: string;
|
|
30
|
+
score: string;
|
|
24
31
|
};
|
|
25
32
|
/**
|
|
26
33
|
* @ignore
|
package/dist/static.js
CHANGED
|
@@ -20,6 +20,13 @@ export const tagModes = {
|
|
|
20
20
|
combobox: 'text/combobox',
|
|
21
21
|
combooption: 'mediawiki',
|
|
22
22
|
inputbox: 'text/inputbox',
|
|
23
|
+
templatedata: 'json',
|
|
24
|
+
maplink: 'jsonc',
|
|
25
|
+
mapframe: 'jsonc',
|
|
26
|
+
math: 'text/math',
|
|
27
|
+
chem: 'text/math',
|
|
28
|
+
ce: 'text/math',
|
|
29
|
+
score: 'lilypond',
|
|
23
30
|
};
|
|
24
31
|
/**
|
|
25
32
|
* @ignore
|
package/dist/theme.d.ts
CHANGED
package/dist/theme.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EditorView } from '@codemirror/view';
|
|
2
2
|
import { syntaxHighlighting, HighlightStyle, defaultHighlightStyle } from '@codemirror/language';
|
|
3
|
-
import { nord
|
|
3
|
+
import { nord } from 'cm6-theme-nord';
|
|
4
4
|
import { matchingCls, nonmatchingCls, actionSelector, panelsSelector, bgDark, } from './constants.js';
|
|
5
5
|
const focused = '&.cm-focused', matching = `${focused} .${matchingCls}`, nonmatching = `${focused} .${nonmatchingCls}`;
|
|
6
6
|
export const lightHighlightStyle = /* @__PURE__ */ (() => syntaxHighlighting(HighlightStyle.define(defaultHighlightStyle.specs, { themeType: 'light' })))();
|
|
@@ -36,6 +36,9 @@ export const light = /* @__PURE__ */ EditorView.theme({
|
|
|
36
36
|
'.cm-doctag-type>*': {
|
|
37
37
|
color: '#085',
|
|
38
38
|
},
|
|
39
|
+
'.cm-doctag-var>*': {
|
|
40
|
+
color: '#00f',
|
|
41
|
+
},
|
|
39
42
|
[matching]: {
|
|
40
43
|
backgroundColor: 'rgb(50,140,130,.32)',
|
|
41
44
|
},
|
|
@@ -48,8 +51,8 @@ export const light = /* @__PURE__ */ EditorView.theme({
|
|
|
48
51
|
* @author Bhsd
|
|
49
52
|
* @see https://zh.moegirl.org.cn/User:%E9%AC%BC%E5%BD%B1233/nord-moeskin.css
|
|
50
53
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
nordDark = /* @__PURE__ */ (() => [
|
|
55
|
+
nord,
|
|
53
56
|
EditorView.theme({
|
|
54
57
|
'&': {
|
|
55
58
|
'--cm-arg': '#9f78a5',
|
|
@@ -81,6 +84,9 @@ nord = /* @__PURE__ */ (() => [
|
|
|
81
84
|
'.cm-doctag-type>*': {
|
|
82
85
|
color: '#ebcb8b',
|
|
83
86
|
},
|
|
87
|
+
'.cm-doctag-var>*': {
|
|
88
|
+
color: '#8fbcbb',
|
|
89
|
+
},
|
|
84
90
|
'div.cm-activeLine': {
|
|
85
91
|
backgroundColor: 'rgb(76,86,106,.27)',
|
|
86
92
|
},
|
package/dist/token.d.ts
CHANGED
|
@@ -21,21 +21,21 @@ declare interface Nesting extends Record<NestCount, number> {
|
|
|
21
21
|
export interface State extends Nesting {
|
|
22
22
|
readonly stack: Tokenizer[];
|
|
23
23
|
readonly inHtmlTag: string[];
|
|
24
|
+
readonly dt: Partial<Nesting> & {
|
|
25
|
+
n: number;
|
|
26
|
+
html: number;
|
|
27
|
+
};
|
|
28
|
+
readonly data: MediaWikiData;
|
|
24
29
|
tokenize: Tokenizer;
|
|
25
|
-
extMode: StreamParser<object> |
|
|
30
|
+
extMode: StreamParser<object> | boolean;
|
|
26
31
|
lbrack: boolean | undefined;
|
|
27
32
|
bold: boolean;
|
|
28
33
|
italic: boolean;
|
|
29
|
-
dt: Partial<Nesting> & {
|
|
30
|
-
n: number;
|
|
31
|
-
html: number;
|
|
32
|
-
};
|
|
33
34
|
sof: boolean;
|
|
34
35
|
redirect: {
|
|
35
36
|
colon: boolean;
|
|
36
37
|
} | false;
|
|
37
38
|
imgLink: boolean;
|
|
38
|
-
data: MediaWikiData;
|
|
39
39
|
}
|
|
40
40
|
declare type ExtState = Omit<State, 'dt'> & Partial<Pick<State, 'dt'>>;
|
|
41
41
|
declare interface Token {
|
|
@@ -206,5 +206,9 @@ export declare class MediaWiki {
|
|
|
206
206
|
'text/inputbox'(): StreamParser<State>;
|
|
207
207
|
inGallery(section?: boolean): Tokenizer;
|
|
208
208
|
'text/gallery'(tags: string[]): StreamParser<State>;
|
|
209
|
+
'text/math'(): StreamParser<object>;
|
|
210
|
+
json(): StreamParser<object>;
|
|
211
|
+
jsonc(): StreamParser<object>;
|
|
212
|
+
lilypond(): StreamParser<object>;
|
|
209
213
|
}
|
|
210
214
|
export {};
|
package/dist/token.js
CHANGED
|
@@ -43,6 +43,9 @@ import { getRegex } from '@bhsd/common';
|
|
|
43
43
|
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
|
+
import { jsonBasic, jsonc } from './json.js';
|
|
47
|
+
import { math } from './math.js';
|
|
48
|
+
import { lilypond } from './lilypond.js';
|
|
46
49
|
class MediaWikiData {
|
|
47
50
|
constructor(tags, urlProtocols) {
|
|
48
51
|
this.tags = tags.includes('translate') ? tags.filter(tag => tag !== 'tvar') : tags;
|
|
@@ -119,7 +122,10 @@ const copyState = (state) => {
|
|
|
119
122
|
result[key] = [...val];
|
|
120
123
|
}
|
|
121
124
|
else if (key === 'extState') {
|
|
122
|
-
|
|
125
|
+
const f = state.extName && typeof state.extMode !== 'boolean'
|
|
126
|
+
&& state.extMode.copyState?.bind(state.extMode)
|
|
127
|
+
|| copyState;
|
|
128
|
+
result[key] = f(val);
|
|
123
129
|
}
|
|
124
130
|
else if (key !== 'data' && key !== 'extMode' && val && typeof val === 'object') {
|
|
125
131
|
// @ts-expect-error initial value
|
|
@@ -330,7 +336,7 @@ const peekSpace = (stream, sol) => {
|
|
|
330
336
|
const peek = stream.peek();
|
|
331
337
|
return Boolean(peek && !peek.trim());
|
|
332
338
|
};
|
|
333
|
-
const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre']), pageFunctions = new Set([
|
|
339
|
+
const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre', 'score']), pageFunctions = new Set([
|
|
334
340
|
'raw',
|
|
335
341
|
'msg',
|
|
336
342
|
'filepath',
|
|
@@ -342,7 +348,7 @@ const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre']), pageFunct
|
|
|
342
348
|
'canonicalurle',
|
|
343
349
|
'int',
|
|
344
350
|
'msgnw',
|
|
345
|
-
]), substs = new Set(['subst', 'safesubst']), headerRegex = new RegExp(String.raw `^(?:[^&[<{~'\-]|${lookahead("<{~'-")})+`, 'iu'), templateRegex = new RegExp(`^(?:[^|{}<]|${lookahead('{}<', true)})+`, 'u'), argumentRegex = new RegExp(String.raw `^(?:[^|[&:}{<~'__\-]|${
|
|
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 => {
|
|
346
352
|
const punctuations = getPunctuations(lpar), source = getUrlRegex(punctuations);
|
|
347
353
|
return new RegExp(`^(?:${source}|[${punctuations}]+(?=${source}))*`, 'u');
|
|
348
354
|
}), indentedTableRegex = [false, true].map(isTemplate => new RegExp(String.raw `^:*\s*(?=\{${getPipe(isTemplate)})`, 'u')), tableRegex = [false, true]
|
|
@@ -353,10 +359,10 @@ const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre']), pageFunct
|
|
|
353
359
|
new RegExp(String.raw `^(?:[<>{}]|%(?:3[ce]|[57][bd])|${lookahead('[]')})+`, 'iu'),
|
|
354
360
|
new RegExp(String.raw `^(?:\}|${lookahead('[]{')})+`, 'u'),
|
|
355
361
|
new RegExp(String.raw `^(?:[>}]|%(?:3[ce]|[57][bd])|${lookahead('[]{<')})+`, 'iu'),
|
|
356
|
-
], tableDefinitionValueRegex = ['', '='].map(equal => new RegExp(String.raw `^(?:[^\s&${tableDefinitionChars}${equal}]|${
|
|
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 = {
|
|
357
363
|
_: /^[\p{L}\p{N}_]+?__/u,
|
|
358
364
|
'_': /^[\p{L}\p{N}__]+?_{2}/u,
|
|
359
|
-
}, 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}]|${
|
|
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'
|
|
360
366
|
? /<\/onlyinclude(?:>|$)/u
|
|
361
367
|
: new RegExp(String.raw `</${name}\s*(?:>|$)`, 'iu')), getNestedRegex = getRegex(tag => new RegExp(String.raw `^(?:[^<]|<(?!${tag}(?:[\s/>]|$)))+`, 'iu'));
|
|
362
368
|
/** Adapted from the original CodeMirror 5 stream parser by Pavel Astakhov */
|
|
@@ -482,7 +488,7 @@ let MediaWiki = (() => {
|
|
|
482
488
|
.join('|')}))|\d+\s*(?:${spImgKeys.filter(word => img[word] !== 'img_width').map(word => word.slice(2))
|
|
483
489
|
.join('|')}))\s*(?=\||\]\]|$))`, 'u');
|
|
484
490
|
this.tags = [...Object.keys(tags), 'includeonly', 'noinclude', 'onlyinclude'];
|
|
485
|
-
this.convertRegex = new RegExp(String.raw `^(?:[^}|;&='{[<~__\-]|\}(?!-)|=(?!>)|\[(?!\[|${urlProtocols})|${
|
|
491
|
+
this.convertRegex = new RegExp(String.raw `^(?:[^}|;&='{[<~__\-]|\}(?!-)|=(?!>)|\[(?!\[|${urlProtocols})|${tableCellLookAhead})+`, 'iu');
|
|
486
492
|
this.convertSemicolon = variants && new RegExp(String.raw `^;\s*(?=(?:[^;]*?=>\s*)?(?:${variants.join('|')})\s*:|(?:$|\}-))`, 'iu');
|
|
487
493
|
this.convertLang = variants
|
|
488
494
|
&& new RegExp(String.raw `^(?:=>\s*)?(?:${variants.join('|')})\s*:`, 'iu');
|
|
@@ -559,6 +565,9 @@ let MediaWiki = (() => {
|
|
|
559
565
|
}
|
|
560
566
|
for (const tag of this.tags) {
|
|
561
567
|
this.addToken(`tag-${tag}`, tag !== 'nowiki' && tag !== 'pre' && tag !== 'ref');
|
|
568
|
+
if (tag === 'score') {
|
|
569
|
+
this.addToken('tag-score-scheme');
|
|
570
|
+
}
|
|
562
571
|
this.addToken(`ext-${tag}`, true);
|
|
563
572
|
}
|
|
564
573
|
for (const tag of this.permittedHtmlTags) {
|
|
@@ -1229,7 +1238,7 @@ let MediaWiki = (() => {
|
|
|
1229
1238
|
}
|
|
1230
1239
|
const t = state.stack[0], pipe = (['inTemplateArgument', 'inParserFunctionArgument', 'inVariable'].includes(t.name) ? '|' : '')
|
|
1231
1240
|
+ getEqual(t);
|
|
1232
|
-
if (pipe.includes(stream.peek()
|
|
1241
|
+
if (pipe.includes(stream.peek() || '')) {
|
|
1233
1242
|
pop(state);
|
|
1234
1243
|
return '';
|
|
1235
1244
|
}
|
|
@@ -1266,12 +1275,17 @@ let MediaWiki = (() => {
|
|
|
1266
1275
|
const advance = (stream, state, re) => {
|
|
1267
1276
|
const mt = stream.match(re);
|
|
1268
1277
|
if (isLang) {
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
lang
|
|
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
|
+
}
|
|
1272
1286
|
}
|
|
1273
|
-
if (
|
|
1274
|
-
state.extMode =
|
|
1287
|
+
else if (mt[0].trim() === 'ABC') {
|
|
1288
|
+
state.extMode = true;
|
|
1275
1289
|
}
|
|
1276
1290
|
}
|
|
1277
1291
|
return makeLocalStyle(tokens.extTagAttributeValue + (isPage ? ` ${tokens.pageName}` : ''), state);
|
|
@@ -1294,7 +1308,7 @@ let MediaWiki = (() => {
|
|
|
1294
1308
|
...state.data.tags.filter(tag => tag !== name),
|
|
1295
1309
|
...name === 'translate' ? ['tvar'] : [],
|
|
1296
1310
|
]);
|
|
1297
|
-
if (state.extMode) {
|
|
1311
|
+
if (typeof state.extMode !== 'boolean') {
|
|
1298
1312
|
state.extState = state.extMode.startState(0);
|
|
1299
1313
|
}
|
|
1300
1314
|
state.tokenize = this.eatExtTagArea(name);
|
|
@@ -1349,7 +1363,7 @@ let MediaWiki = (() => {
|
|
|
1349
1363
|
inExtTokens(origString) {
|
|
1350
1364
|
return (stream, state) => {
|
|
1351
1365
|
let ret;
|
|
1352
|
-
if (state.extMode ===
|
|
1366
|
+
if (typeof state.extMode === 'boolean') {
|
|
1353
1367
|
ret = `mw-tag-${state.extName} ${tokens.extTag}`;
|
|
1354
1368
|
stream.skipToEnd();
|
|
1355
1369
|
}
|
|
@@ -1709,7 +1723,7 @@ let MediaWiki = (() => {
|
|
|
1709
1723
|
};
|
|
1710
1724
|
}
|
|
1711
1725
|
eatEntity(stream, style) {
|
|
1712
|
-
const entity = stream.match(/^(?:#x[a-f\d]+|#\d+|[a-z\d]
|
|
1726
|
+
const entity = stream.match(/^(?:#x[a-f\d]+|#\d+|[a-z][a-z\d]*);/iu);
|
|
1713
1727
|
return entity && isHtmlEntity(entity[0]) ? tokens.htmlEntity : style;
|
|
1714
1728
|
}
|
|
1715
1729
|
/**
|
|
@@ -1745,7 +1759,7 @@ let MediaWiki = (() => {
|
|
|
1745
1759
|
state[key] = other[key];
|
|
1746
1760
|
}
|
|
1747
1761
|
}
|
|
1748
|
-
if (!(state.extName && state.extMode)
|
|
1762
|
+
if (!(state.extName && typeof state.extMode !== 'boolean')
|
|
1749
1763
|
&& state.nLink === 0
|
|
1750
1764
|
&& typeof style === 'string'
|
|
1751
1765
|
&& style.includes(tokens.apostrophes)) {
|
|
@@ -1868,15 +1882,21 @@ let MediaWiki = (() => {
|
|
|
1868
1882
|
return '';
|
|
1869
1883
|
},
|
|
1870
1884
|
blankLine(state) {
|
|
1871
|
-
if (state.extName && state.extMode && state.extMode.blankLine) {
|
|
1885
|
+
if (state.extName && typeof state.extMode !== 'boolean' && state.extMode.blankLine) {
|
|
1872
1886
|
state.extMode.blankLine(state.extState, 0);
|
|
1873
1887
|
}
|
|
1874
1888
|
},
|
|
1875
1889
|
indent(state, textAfter, context) {
|
|
1876
|
-
return state.extName && state.extMode && state.extMode.indent
|
|
1890
|
+
return state.extName && typeof state.extMode !== 'boolean' && state.extMode.indent
|
|
1877
1891
|
? state.extMode.indent(state.extState, textAfter, context)
|
|
1878
1892
|
: null;
|
|
1879
1893
|
},
|
|
1894
|
+
languageData: {
|
|
1895
|
+
closeBrackets: {
|
|
1896
|
+
brackets: ['(', '[', '{', '"'],
|
|
1897
|
+
before: ')]}>',
|
|
1898
|
+
},
|
|
1899
|
+
},
|
|
1880
1900
|
...tags
|
|
1881
1901
|
? undefined
|
|
1882
1902
|
: {
|
|
@@ -1978,8 +1998,10 @@ let MediaWiki = (() => {
|
|
|
1978
1998
|
chain(state, this.inComment);
|
|
1979
1999
|
return tokens.comment;
|
|
1980
2000
|
}
|
|
1981
|
-
|
|
1982
|
-
|
|
2001
|
+
else if (stream.match(/^\{\{(?!\{)/u)) {
|
|
2002
|
+
return this.eatTransclusion(stream, state) ?? '';
|
|
2003
|
+
}
|
|
2004
|
+
stream.match(/^(?:[^<{]|<(?!!--)|\{(?!\{(?!\{)))+/u);
|
|
1983
2005
|
return '';
|
|
1984
2006
|
};
|
|
1985
2007
|
}
|
|
@@ -2021,6 +2043,18 @@ let MediaWiki = (() => {
|
|
|
2021
2043
|
},
|
|
2022
2044
|
};
|
|
2023
2045
|
}
|
|
2046
|
+
'text/math'() {
|
|
2047
|
+
return math;
|
|
2048
|
+
}
|
|
2049
|
+
json() {
|
|
2050
|
+
return jsonBasic;
|
|
2051
|
+
}
|
|
2052
|
+
jsonc() {
|
|
2053
|
+
return jsonc;
|
|
2054
|
+
}
|
|
2055
|
+
lilypond() {
|
|
2056
|
+
return lilypond;
|
|
2057
|
+
}
|
|
2024
2058
|
};
|
|
2025
2059
|
})();
|
|
2026
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
|
-
|
|
8
|
+
export interface DocRange {
|
|
9
|
+
from: number;
|
|
10
|
+
to: number;
|
|
11
|
+
}
|
|
7
12
|
/**
|
|
8
13
|
* 转义HTML字符串
|
|
9
14
|
* @param text 原字符串
|
|
@@ -52,19 +57,46 @@ 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
|
|
58
89
|
* @param from 起始位置
|
|
59
90
|
* @param mt 正则表达式匹配结果,第1个捕获组为标签,第2个捕获组为类型的起始括号`{`
|
|
91
|
+
* @param offset Decoration 向外扩展的大小,默认为0
|
|
60
92
|
* @test
|
|
61
93
|
*/
|
|
62
|
-
export declare const markDocTagType: (decorations: Range<Decoration>[], from: number, mt: RegExpExecArray) =>
|
|
94
|
+
export declare const markDocTagType: (decorations: Range<Decoration>[], from: number, mt: RegExpExecArray, offset?: number) => number;
|
|
63
95
|
/**
|
|
64
96
|
* Check if the node is a template parameter value
|
|
65
97
|
* @param node 语法树节点
|
|
66
98
|
*/
|
|
67
|
-
export declare const
|
|
99
|
+
export declare const isTemplateParam: (node: SyntaxNode) => boolean;
|
|
68
100
|
/**
|
|
69
101
|
* Find the current template name and parameter name
|
|
70
102
|
* @param state
|
|
@@ -72,10 +104,3 @@ export declare const isTemplate: (node: SyntaxNode) => boolean;
|
|
|
72
104
|
* @test
|
|
73
105
|
*/
|
|
74
106
|
export declare const findTemplateName: (state: EditorState, node: SyntaxNode) => [string | null, string];
|
|
75
|
-
export declare const toConfigGetter: (configGetter?: ConfigGetter, articlePath?: string) => ConfigGetter | undefined;
|
|
76
|
-
/**
|
|
77
|
-
* 获取字符串开头的空白字符
|
|
78
|
-
* @param str 字符串
|
|
79
|
-
* @test
|
|
80
|
-
*/
|
|
81
|
-
export declare const leadingSpaces: (str: string) => string;
|
package/dist/util.js
CHANGED
|
@@ -71,14 +71,51 @@ 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
|
|
77
113
|
* @param from 起始位置
|
|
78
114
|
* @param mt 正则表达式匹配结果,第1个捕获组为标签,第2个捕获组为类型的起始括号`{`
|
|
115
|
+
* @param offset Decoration 向外扩展的大小,默认为0
|
|
79
116
|
* @test
|
|
80
117
|
*/
|
|
81
|
-
export const markDocTagType = (decorations, from, mt) => {
|
|
118
|
+
export const markDocTagType = (decorations, from, mt, offset = 0) => {
|
|
82
119
|
const { input, indices } = mt, [start, end] = indices[1];
|
|
83
120
|
pushDecoration(decorations, doctagMark, from + start, from + end);
|
|
84
121
|
if (mt[2]) {
|
|
@@ -88,19 +125,19 @@ export const markDocTagType = (decorations, from, mt) => {
|
|
|
88
125
|
while (m) {
|
|
89
126
|
balance += m[0] === '{' ? 1 : -1;
|
|
90
127
|
if (balance === 0) {
|
|
91
|
-
pushDecoration(decorations, typeMark, from + left, from + m.index);
|
|
92
|
-
|
|
128
|
+
pushDecoration(decorations, typeMark, from + left - offset, from + m.index + offset);
|
|
129
|
+
return m.index + 1;
|
|
93
130
|
}
|
|
94
131
|
m = re.exec(input);
|
|
95
132
|
}
|
|
96
133
|
}
|
|
97
|
-
return
|
|
134
|
+
return end;
|
|
98
135
|
};
|
|
99
136
|
/**
|
|
100
137
|
* Check if the node is a template parameter value
|
|
101
138
|
* @param node 语法树节点
|
|
102
139
|
*/
|
|
103
|
-
export const
|
|
140
|
+
export const isTemplateParam = (node) => node.name.split('_').includes(tokens.template);
|
|
104
141
|
/**
|
|
105
142
|
* Find the current template name and parameter name
|
|
106
143
|
* @param state
|
|
@@ -109,7 +146,7 @@ export const isTemplate = (node) => node.name.split('_').includes(tokens.templat
|
|
|
109
146
|
*/
|
|
110
147
|
export const findTemplateName = (state, node) => {
|
|
111
148
|
let stack = -1, { prevSibling } = node,
|
|
112
|
-
/** 可包含`_`、`:`等 */ page = '', parameter = '', need =
|
|
149
|
+
/** 可包含`_`、`:`等 */ page = '', parameter = '', need = isTemplateParam(node);
|
|
113
150
|
while (prevSibling) {
|
|
114
151
|
const { name } = prevSibling;
|
|
115
152
|
if (name.includes(tokens.templateBracket)) {
|
|
@@ -149,12 +186,3 @@ export const findTemplateName = (state, node) => {
|
|
|
149
186
|
}
|
|
150
187
|
return [prevSibling && page, parameter];
|
|
151
188
|
};
|
|
152
|
-
export const toConfigGetter = (configGetter, articlePath) => articlePath
|
|
153
|
-
? async () => Object.assign(await (configGetter ?? wikiparse.getConfig)(), { articlePath })
|
|
154
|
-
: configGetter;
|
|
155
|
-
/**
|
|
156
|
-
* 获取字符串开头的空白字符
|
|
157
|
-
* @param str 字符串
|
|
158
|
-
* @test
|
|
159
|
-
*/
|
|
160
|
-
export const leadingSpaces = (str) => /^\s*/u.exec(str)[0];
|