@bhsd/codemirror-mediawiki 3.12.0 → 3.12.2
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/LICENSE +19 -0
- package/dist/bidi.js +9 -8
- package/dist/codemirror.js +5 -5
- package/dist/constants.d.ts +2 -1
- package/dist/constants.js +2 -1
- package/dist/escape.js +3 -3
- package/dist/fold.d.ts +4 -4
- package/dist/fold.js +22 -19
- package/dist/hover.js +3 -3
- package/dist/html.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/inlay.js +2 -2
- package/dist/javascript.d.ts +3 -3
- package/dist/javascript.js +30 -9
- package/dist/json.d.ts +8 -0
- package/dist/json.js +108 -0
- package/dist/keymap.d.ts +1 -1
- package/dist/keymap.js +18 -3
- package/dist/lint.js +2 -2
- package/dist/lintsource.js +7 -7
- package/dist/lua.d.ts +16 -0
- package/dist/lua.js +65 -9
- package/dist/main.min.js +31 -29
- package/dist/matchBrackets.d.ts +3 -6
- package/dist/matchBrackets.js +61 -24
- package/dist/matchTag.d.ts +5 -5
- package/dist/matchTag.js +8 -8
- package/dist/mediawiki.d.ts +1 -2
- package/dist/mediawiki.js +4 -9
- package/dist/mw.min.js +34 -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 +3 -0
- package/dist/static.js +3 -0
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +21 -3
- package/dist/token.d.ts +8 -5
- package/dist/token.js +17 -4
- package/dist/util.d.ts +22 -4
- package/dist/util.js +45 -4
- package/dist/vue.js +2 -2
- package/dist/wiki.min.js +34 -32
- package/i18n/en.json +1 -1
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/package.json +13 -13
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
package/dist/static.js
CHANGED
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' })))();
|
|
@@ -30,6 +30,15 @@ export const light = /* @__PURE__ */ EditorView.theme({
|
|
|
30
30
|
'.cm-globals, .cm-globals>*': {
|
|
31
31
|
color: '#164',
|
|
32
32
|
},
|
|
33
|
+
'.cm-doctag>*': {
|
|
34
|
+
color: '#219',
|
|
35
|
+
},
|
|
36
|
+
'.cm-doctag-type>*': {
|
|
37
|
+
color: '#085',
|
|
38
|
+
},
|
|
39
|
+
'.cm-doctag-var>*': {
|
|
40
|
+
color: '#00f',
|
|
41
|
+
},
|
|
33
42
|
[matching]: {
|
|
34
43
|
backgroundColor: 'rgb(50,140,130,.32)',
|
|
35
44
|
},
|
|
@@ -42,8 +51,8 @@ export const light = /* @__PURE__ */ EditorView.theme({
|
|
|
42
51
|
* @author Bhsd
|
|
43
52
|
* @see https://zh.moegirl.org.cn/User:%E9%AC%BC%E5%BD%B1233/nord-moeskin.css
|
|
44
53
|
*/
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
nordDark = /* @__PURE__ */ (() => [
|
|
55
|
+
nord,
|
|
47
56
|
EditorView.theme({
|
|
48
57
|
'&': {
|
|
49
58
|
'--cm-arg': '#9f78a5',
|
|
@@ -69,6 +78,15 @@ nord = /* @__PURE__ */ (() => [
|
|
|
69
78
|
'.cm-globals, .cm-globals>*': {
|
|
70
79
|
color: '#d08770',
|
|
71
80
|
},
|
|
81
|
+
'.cm-doctag>*': {
|
|
82
|
+
color: '#81a1c1',
|
|
83
|
+
},
|
|
84
|
+
'.cm-doctag-type>*': {
|
|
85
|
+
color: '#ebcb8b',
|
|
86
|
+
},
|
|
87
|
+
'.cm-doctag-var>*': {
|
|
88
|
+
color: '#8fbcbb',
|
|
89
|
+
},
|
|
72
90
|
'div.cm-activeLine': {
|
|
73
91
|
backgroundColor: 'rgb(76,86,106,.27)',
|
|
74
92
|
},
|
package/dist/token.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
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';
|
|
7
8
|
import type { MwConfig as MwConfigBase } from '@bhsd/cm-util';
|
|
8
9
|
import type { EditorState } from '@codemirror/state';
|
|
9
10
|
import type { StreamParser, StringStream as StringStreamBase } from '@codemirror/language';
|
|
@@ -21,21 +22,21 @@ declare interface Nesting extends Record<NestCount, number> {
|
|
|
21
22
|
export interface State extends Nesting {
|
|
22
23
|
readonly stack: Tokenizer[];
|
|
23
24
|
readonly inHtmlTag: string[];
|
|
25
|
+
readonly dt: Partial<Nesting> & {
|
|
26
|
+
n: number;
|
|
27
|
+
html: number;
|
|
28
|
+
};
|
|
29
|
+
readonly data: MediaWikiData;
|
|
24
30
|
tokenize: Tokenizer;
|
|
25
31
|
extMode: StreamParser<object> | false;
|
|
26
32
|
lbrack: boolean | undefined;
|
|
27
33
|
bold: boolean;
|
|
28
34
|
italic: boolean;
|
|
29
|
-
dt: Partial<Nesting> & {
|
|
30
|
-
n: number;
|
|
31
|
-
html: number;
|
|
32
|
-
};
|
|
33
35
|
sof: boolean;
|
|
34
36
|
redirect: {
|
|
35
37
|
colon: boolean;
|
|
36
38
|
} | false;
|
|
37
39
|
imgLink: boolean;
|
|
38
|
-
data: MediaWikiData;
|
|
39
40
|
}
|
|
40
41
|
declare type ExtState = Omit<State, 'dt'> & Partial<Pick<State, 'dt'>>;
|
|
41
42
|
declare interface Token {
|
|
@@ -206,5 +207,7 @@ export declare class MediaWiki {
|
|
|
206
207
|
'text/inputbox'(): StreamParser<State>;
|
|
207
208
|
inGallery(section?: boolean): Tokenizer;
|
|
208
209
|
'text/gallery'(tags: string[]): StreamParser<State>;
|
|
210
|
+
json(): typeof jsonBasic;
|
|
211
|
+
jsonc(): typeof jsonc;
|
|
209
212
|
}
|
|
210
213
|
export {};
|
package/dist/token.js
CHANGED
|
@@ -43,6 +43,7 @@ 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';
|
|
46
47
|
class MediaWikiData {
|
|
47
48
|
constructor(tags, urlProtocols) {
|
|
48
49
|
this.tags = tags.includes('translate') ? tags.filter(tag => tag !== 'tvar') : tags;
|
|
@@ -121,7 +122,7 @@ const copyState = (state) => {
|
|
|
121
122
|
else if (key === 'extState') {
|
|
122
123
|
result[key] = (state.extName && state.extMode && state.extMode.copyState || copyState)(val);
|
|
123
124
|
}
|
|
124
|
-
else if (key !== 'data' && val && typeof val === 'object') {
|
|
125
|
+
else if (key !== 'data' && key !== 'extMode' && val && typeof val === 'object') {
|
|
125
126
|
// @ts-expect-error initial value
|
|
126
127
|
result[key] = { ...val }; // eslint-disable-line @typescript-eslint/no-misused-spread
|
|
127
128
|
}
|
|
@@ -1229,7 +1230,7 @@ let MediaWiki = (() => {
|
|
|
1229
1230
|
}
|
|
1230
1231
|
const t = state.stack[0], pipe = (['inTemplateArgument', 'inParserFunctionArgument', 'inVariable'].includes(t.name) ? '|' : '')
|
|
1231
1232
|
+ getEqual(t);
|
|
1232
|
-
if (pipe.includes(stream.peek()
|
|
1233
|
+
if (pipe.includes(stream.peek() || '')) {
|
|
1233
1234
|
pop(state);
|
|
1234
1235
|
return '';
|
|
1235
1236
|
}
|
|
@@ -1267,8 +1268,8 @@ let MediaWiki = (() => {
|
|
|
1267
1268
|
const mt = stream.match(re);
|
|
1268
1269
|
if (isLang) {
|
|
1269
1270
|
let lang = mt[0].trim().toLowerCase();
|
|
1270
|
-
if (lang === '
|
|
1271
|
-
lang = '
|
|
1271
|
+
if (lang === 'wiki' || lang === 'wikitext') {
|
|
1272
|
+
lang = 'mediawiki';
|
|
1272
1273
|
}
|
|
1273
1274
|
if (lang in this) {
|
|
1274
1275
|
state.extMode = this[lang]();
|
|
@@ -1877,6 +1878,12 @@ let MediaWiki = (() => {
|
|
|
1877
1878
|
? state.extMode.indent(state.extState, textAfter, context)
|
|
1878
1879
|
: null;
|
|
1879
1880
|
},
|
|
1881
|
+
languageData: {
|
|
1882
|
+
closeBrackets: {
|
|
1883
|
+
brackets: ['(', '[', '{', '"'],
|
|
1884
|
+
before: ')]}>',
|
|
1885
|
+
},
|
|
1886
|
+
},
|
|
1880
1887
|
...tags
|
|
1881
1888
|
? undefined
|
|
1882
1889
|
: {
|
|
@@ -2021,6 +2028,12 @@ let MediaWiki = (() => {
|
|
|
2021
2028
|
},
|
|
2022
2029
|
};
|
|
2023
2030
|
}
|
|
2031
|
+
json() {
|
|
2032
|
+
return jsonBasic;
|
|
2033
|
+
}
|
|
2034
|
+
jsonc() {
|
|
2035
|
+
return jsonc;
|
|
2036
|
+
}
|
|
2024
2037
|
};
|
|
2025
2038
|
})();
|
|
2026
2039
|
export { MediaWiki };
|
package/dist/util.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { EditorView, TooltipView } from '@codemirror/view';
|
|
2
|
-
import type { Text, EditorState, SelectionRange } from '@codemirror/state';
|
|
1
|
+
import type { EditorView, TooltipView, Decoration } from '@codemirror/view';
|
|
2
|
+
import type { Text, EditorState, SelectionRange, Range } from '@codemirror/state';
|
|
3
3
|
import type { SyntaxNode } from '@lezer/common';
|
|
4
4
|
import type { Position } from 'vscode-languageserver-types';
|
|
5
5
|
import type { ConfigGetter } from '@bhsd/browser';
|
|
6
|
+
import type { DocRange } from './fold';
|
|
6
7
|
/**
|
|
7
8
|
* 转义HTML字符串
|
|
8
9
|
* @param text 原字符串
|
|
@@ -37,17 +38,34 @@ export declare const createTooltipView: (view: EditorView, innerHTML: string) =>
|
|
|
37
38
|
*/
|
|
38
39
|
export declare const sliceDoc: (state: EditorState, node: SyntaxNode | SelectionRange) => string;
|
|
39
40
|
/**
|
|
40
|
-
* Update the stack of opening (+) or closing (-)
|
|
41
|
+
* Update the stack of opening (+) or closing (-) braces
|
|
41
42
|
* @param state
|
|
42
43
|
* @param node 语法树节点
|
|
43
44
|
* @test
|
|
44
45
|
*/
|
|
45
46
|
export declare const braceStackUpdate: (state: EditorState, node: SyntaxNode) => [number, number];
|
|
47
|
+
/**
|
|
48
|
+
* Push a decoration to the array if the range is not empty
|
|
49
|
+
* @param decorations Decoration 数组
|
|
50
|
+
* @param decoration Decoration 实例
|
|
51
|
+
* @param from 起始位置或节点
|
|
52
|
+
* @param to 结束位置
|
|
53
|
+
*/
|
|
54
|
+
export declare const pushDecoration: (decorations: Range<Decoration>[], decoration: Decoration, from: number | DocRange, to?: number) => void;
|
|
55
|
+
/**
|
|
56
|
+
* Mark the type in a JSDoc/LDoc comment
|
|
57
|
+
* @param decorations
|
|
58
|
+
* @param from 起始位置
|
|
59
|
+
* @param mt 正则表达式匹配结果,第1个捕获组为标签,第2个捕获组为类型的起始括号`{`
|
|
60
|
+
* @param offset Decoration 向外扩展的大小,默认为0
|
|
61
|
+
* @test
|
|
62
|
+
*/
|
|
63
|
+
export declare const markDocTagType: (decorations: Range<Decoration>[], from: number, mt: RegExpExecArray, offset?: number) => number;
|
|
46
64
|
/**
|
|
47
65
|
* Check if the node is a template parameter value
|
|
48
66
|
* @param node 语法树节点
|
|
49
67
|
*/
|
|
50
|
-
export declare const
|
|
68
|
+
export declare const isTemplateParam: (node: SyntaxNode) => boolean;
|
|
51
69
|
/**
|
|
52
70
|
* Find the current template name and parameter name
|
|
53
71
|
* @param state
|
package/dist/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import elt from 'crelt';
|
|
2
2
|
import { tokens } from './config.js';
|
|
3
|
-
import { hoverSelector, } from './constants.js';
|
|
3
|
+
import { hoverSelector, doctagMark, typeMark, } from './constants.js';
|
|
4
4
|
const dict = { '\n': '<br>', '&': '&', '<': '<' };
|
|
5
5
|
/**
|
|
6
6
|
* 转义HTML字符串
|
|
@@ -47,7 +47,7 @@ export const createTooltipView = (view, innerHTML) => {
|
|
|
47
47
|
*/
|
|
48
48
|
export const sliceDoc = (state, node) => state.sliceDoc(node.from, node.to);
|
|
49
49
|
/**
|
|
50
|
-
* Update the stack of opening (+) or closing (-)
|
|
50
|
+
* Update the stack of opening (+) or closing (-) braces
|
|
51
51
|
* @param state
|
|
52
52
|
* @param node 语法树节点
|
|
53
53
|
* @test
|
|
@@ -56,11 +56,52 @@ export const braceStackUpdate = (state, node) => {
|
|
|
56
56
|
const brackets = sliceDoc(state, node);
|
|
57
57
|
return [brackets.split('{{').length - 1, 1 - brackets.split('}}').length];
|
|
58
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* Push a decoration to the array if the range is not empty
|
|
61
|
+
* @param decorations Decoration 数组
|
|
62
|
+
* @param decoration Decoration 实例
|
|
63
|
+
* @param from 起始位置或节点
|
|
64
|
+
* @param to 结束位置
|
|
65
|
+
*/
|
|
66
|
+
export const pushDecoration = (decorations, decoration, from, to) => {
|
|
67
|
+
if (typeof from !== 'number') {
|
|
68
|
+
({ from, to } = from);
|
|
69
|
+
}
|
|
70
|
+
if (from < to) {
|
|
71
|
+
decorations.push(decoration.range(from, to));
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Mark the type in a JSDoc/LDoc comment
|
|
76
|
+
* @param decorations
|
|
77
|
+
* @param from 起始位置
|
|
78
|
+
* @param mt 正则表达式匹配结果,第1个捕获组为标签,第2个捕获组为类型的起始括号`{`
|
|
79
|
+
* @param offset Decoration 向外扩展的大小,默认为0
|
|
80
|
+
* @test
|
|
81
|
+
*/
|
|
82
|
+
export const markDocTagType = (decorations, from, mt, offset = 0) => {
|
|
83
|
+
const { input, indices } = mt, [start, end] = indices[1];
|
|
84
|
+
pushDecoration(decorations, doctagMark, from + start, from + end);
|
|
85
|
+
if (mt[2]) {
|
|
86
|
+
const re = /[{}]/gu, [, left] = indices[2];
|
|
87
|
+
re.lastIndex = left;
|
|
88
|
+
let m = re.exec(input), balance = 1;
|
|
89
|
+
while (m) {
|
|
90
|
+
balance += m[0] === '{' ? 1 : -1;
|
|
91
|
+
if (balance === 0) {
|
|
92
|
+
pushDecoration(decorations, typeMark, from + left - offset, from + m.index + offset);
|
|
93
|
+
return m.index + 1;
|
|
94
|
+
}
|
|
95
|
+
m = re.exec(input);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return end;
|
|
99
|
+
};
|
|
59
100
|
/**
|
|
60
101
|
* Check if the node is a template parameter value
|
|
61
102
|
* @param node 语法树节点
|
|
62
103
|
*/
|
|
63
|
-
export const
|
|
104
|
+
export const isTemplateParam = (node) => node.name.split('_').includes(tokens.template);
|
|
64
105
|
/**
|
|
65
106
|
* Find the current template name and parameter name
|
|
66
107
|
* @param state
|
|
@@ -69,7 +110,7 @@ export const isTemplate = (node) => node.name.split('_').includes(tokens.templat
|
|
|
69
110
|
*/
|
|
70
111
|
export const findTemplateName = (state, node) => {
|
|
71
112
|
let stack = -1, { prevSibling } = node,
|
|
72
|
-
/** 可包含`_`、`:`等 */ page = '', parameter = '', need =
|
|
113
|
+
/** 可包含`_`、`:`等 */ page = '', parameter = '', need = isTemplateParam(node);
|
|
73
114
|
while (prevSibling) {
|
|
74
115
|
const { name } = prevSibling;
|
|
75
116
|
if (name.includes(tokens.templateBracket)) {
|
package/dist/vue.js
CHANGED
|
@@ -3,13 +3,13 @@ import { htmlLanguage, htmlCompletionSource } from '@codemirror/lang-html';
|
|
|
3
3
|
import { javascript } from '@codemirror/lang-javascript';
|
|
4
4
|
import { LanguageSupport } from '@codemirror/language';
|
|
5
5
|
import { cssCompletion } from './css.js';
|
|
6
|
-
import { jsCompletion,
|
|
6
|
+
import { jsCompletion, markGlobalsAndDocTagPlugin } from './javascript.js';
|
|
7
7
|
export default (_, cm) => vue({
|
|
8
8
|
base: new LanguageSupport(htmlLanguage, [
|
|
9
9
|
htmlLanguage.data.of({ autocomplete: htmlCompletionSource }),
|
|
10
10
|
javascript().support,
|
|
11
11
|
jsCompletion,
|
|
12
12
|
cssCompletion(),
|
|
13
|
-
|
|
13
|
+
markGlobalsAndDocTagPlugin(cm),
|
|
14
14
|
]),
|
|
15
15
|
});
|