@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.
@@ -4,7 +4,8 @@ import type { Extension, StateField } from '@codemirror/state';
4
4
  import type { SyntaxNode } from '@lezer/common';
5
5
  import type { ConfigGetter } from '@bhsd/browser';
6
6
  import type { ConfigData } from 'wikiparser-node';
7
- import type { DocRange, foldHandler } from './fold';
7
+ import type { foldHandler } from './fold';
8
+ import type { DocRange } from './util';
8
9
  import type { detectIndent } from './indent';
9
10
  import type { Option, LiveOption } from './linter';
10
11
  import type { LintSource, LintSources, LintSourceGetter } from './lintsource';
@@ -1,4 +1,5 @@
1
1
  import { Decoration } from '@codemirror/view';
2
- export declare const baseData: Record<'CDN', string | undefined>, hoverSelector = ".cm-tooltip-hover-mw", diagnosticSelector = ".cm-diagnosticText-clickable", panelSelector = ".cm-panel", panelsSelector = ".cm-panels", actionSelector = ".cm-diagnosticAction", doctagMark: Decoration, typeMark: Decoration, noDetectionLangs: Set<string>, bgDark = "#4c566a", matchingCls = "cm-matchingTag", nonmatchingCls = "cm-nonmatchingTag";
2
+ import type { Completion } from '@codemirror/autocomplete';
3
+ export declare const baseData: Record<'CDN', string | undefined>, extData: Record<string, Set<string>>, extCompletion: Record<string, Completion[]>, hoverSelector = ".cm-tooltip-hover-mw", diagnosticSelector = ".cm-diagnosticText-clickable", panelSelector = ".cm-panel", panelsSelector = ".cm-panels", actionSelector = ".cm-diagnosticAction", doctagMark: Decoration, typeMark: Decoration, noDetectionLangs: Set<string>, bgDark = "#4c566a", matchingCls = "cm-matchingTag", nonmatchingCls = "cm-nonmatchingTag";
3
4
  export declare const isWMF: boolean;
4
5
  export declare const isMac: boolean;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Decoration } from '@codemirror/view';
2
2
  import { wmf } from '@bhsd/common';
3
- export const baseData = { CDN: undefined }, hoverSelector = '.cm-tooltip-hover-mw', diagnosticSelector = '.cm-diagnosticText-clickable', panelSelector = '.cm-panel', panelsSelector = '.cm-panels', actionSelector = '.cm-diagnosticAction', doctagMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag' }), typeMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag-type' }), noDetectionLangs = new Set(['plain', 'mediawiki']), bgDark = '#4c566a', matchingCls = 'cm-matchingTag', nonmatchingCls = 'cm-nonmatchingTag';
3
+ export const baseData = { CDN: undefined }, extData = {}, extCompletion = {}, hoverSelector = '.cm-tooltip-hover-mw', diagnosticSelector = '.cm-diagnosticText-clickable', panelSelector = '.cm-panel', panelsSelector = '.cm-panels', actionSelector = '.cm-diagnosticAction', doctagMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag' }), typeMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag-type' }), noDetectionLangs = new Set(['plain', 'mediawiki']), bgDark = '#4c566a', matchingCls = 'cm-matchingTag', nonmatchingCls = 'cm-nonmatchingTag';
4
4
  export const isWMF = /* @__PURE__ */ (() => typeof location === 'object'
5
5
  && new RegExp(String.raw `\.(?:${wmf})\.org$`, 'u').test(location.hostname))();
6
6
  export const isMac = /* @__PURE__ */ (() => {
package/dist/css.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { cssLanguage, cssCompletionSource } from '@codemirror/lang-css';
2
2
  import { LanguageSupport, syntaxTree } from '@codemirror/language';
3
- import { sliceDoc } from './util.js';
4
- const cssWideKeywords = /* @__PURE__ */ (() => ['revert', 'revert-layer'].map((label) => ({ label, type: 'keyword' })))();
3
+ import { sliceDoc, getCompletions } from './util.js';
4
+ const cssWideKeywords = /* @__PURE__ */ getCompletions(['revert', 'revert-layer']);
5
5
  /**
6
6
  * CSS completion source with dialect-specific adjustments.
7
7
  * @param dialect 是否是sanitized-css
package/dist/escape.js CHANGED
@@ -60,13 +60,12 @@ escapeWiki = async (view, lsp) => {
60
60
  }
61
61
  view.dispatch(state.changeByRange(range => {
62
62
  const insert = replacements.get(range);
63
- if (insert === undefined) {
64
- return { range };
65
- }
66
- return {
67
- range: EditorSelection.range(range.from, range.from + insert.length),
68
- changes: { from: range.from, to: range.to, insert },
69
- };
63
+ return insert === undefined
64
+ ? { range }
65
+ : {
66
+ range: EditorSelection.range(range.from, range.from + insert.length),
67
+ changes: { from: range.from, to: range.to, insert },
68
+ };
70
69
  }));
71
70
  };
72
71
  const escapeWikiCommand = (view, getConfig) => {
package/dist/fold.d.ts CHANGED
@@ -3,10 +3,7 @@ import { RangeSet } from '@codemirror/state';
3
3
  import type { BlockInfo, Command } from '@codemirror/view';
4
4
  import type { EditorState, StateEffect, Extension } from '@codemirror/state';
5
5
  import type { SyntaxNode, Tree } from '@lezer/common';
6
- export interface DocRange {
7
- from: number;
8
- to: number;
9
- }
6
+ import type { DocRange } from './util';
10
7
  declare type AnchorUpdate = (pos: number, range: DocRange) => number;
11
8
  export declare const updateSelection: AnchorUpdate, updateAll: AnchorUpdate;
12
9
  /**
@@ -1,7 +1,7 @@
1
1
  import type { Extension, EditorState } from '@codemirror/state';
2
2
  import type { DecorationSet } from '@codemirror/view';
3
3
  import type { Tree } from '@lezer/common';
4
- import type { DocRange } from './fold';
4
+ import type { DocRange } from './util';
5
5
  import type { CodeMirror6 } from './codemirror';
6
6
  export declare const jsCompletion: Extension;
7
7
  /**
package/dist/json.js CHANGED
@@ -1,25 +1,15 @@
1
- const tokenNumber = (stream, state) => {
1
+ import { inComment } from './util.js';
2
+ const eatNumber = (stream, state) => {
2
3
  if (stream.match(/^\d+(?:\.\d+)?(?:e[+-]?\d+)?/iu)) {
3
4
  state.wb = false;
4
- return 'number';
5
+ return /* #164 */ 'number';
5
6
  }
6
7
  state.wb = true;
7
8
  return '';
8
9
  };
9
10
  const mkJson = (jsoncMode) => {
10
11
  // Tokenizer
11
- const tokenComment = (stream, state) => {
12
- if (stream.skipTo('*/')) {
13
- stream.next();
14
- stream.next();
15
- state.tokenize = tokenBase;
16
- }
17
- else {
18
- stream.skipToEnd();
19
- }
20
- return 'comment';
21
- };
22
- const tokenBase = (stream, state) => {
12
+ const inBase = (stream, state) => {
23
13
  if (stream.eatSpace()) {
24
14
  state.wb = true;
25
15
  return '';
@@ -43,11 +33,11 @@ const mkJson = (jsoncMode) => {
43
33
  if (jsoncMode) {
44
34
  if (stream.eat('/')) {
45
35
  stream.skipToEnd();
46
- return 'comment';
36
+ return /* #940 */ 'comment';
47
37
  }
48
38
  else if (stream.eat('*')) {
49
- state.tokenize = tokenComment;
50
- return tokenComment(stream, state);
39
+ state.tokenize = inJsoncComment;
40
+ return 'comment';
51
41
  }
52
42
  }
53
43
  return '';
@@ -61,39 +51,42 @@ const mkJson = (jsoncMode) => {
61
51
  escaped = !escaped && next === '\\';
62
52
  next = stream.next();
63
53
  }
64
- return stream.match(/^\s*:/u, false) ? 'propertyName.definition' : 'string';
54
+ return stream.match(/^\s*:/u, false)
55
+ ? /* #00c */ 'propertyName.definition'
56
+ : /* #a11 */ 'string';
65
57
  }
66
58
  case '-':
67
59
  if (state.wb) {
68
- return tokenNumber(stream, state);
60
+ return eatNumber(stream, state);
69
61
  }
70
62
  state.wb = true;
71
63
  return '';
72
64
  default:
73
65
  if (state.wb) {
74
- if (ch >= '0' && ch <= '9') {
66
+ if (/\d/u.test(ch)) {
75
67
  stream.backUp(1);
76
- return tokenNumber(stream, state);
68
+ return eatNumber(stream, state);
77
69
  }
78
70
  else if (ch === 'n' && stream.match(/^ull\b/u)) {
79
71
  state.wb = false;
80
- return 'null';
72
+ return /* #708 */ 'null';
81
73
  }
82
74
  else if (ch === 't' && stream.match(/^rue\b/u)
83
75
  || ch === 'f' && stream.match(/^alse\b/u)) {
84
76
  state.wb = false;
85
- return 'bool';
77
+ return /* #219 */ 'bool';
86
78
  }
87
79
  }
88
80
  state.wb = !/[\w$]/u.test(ch);
89
81
  return '';
90
82
  }
91
83
  };
84
+ const inJsoncComment = inComment(inBase, '*/');
92
85
  // Interface
93
86
  return {
94
87
  startState() {
95
88
  return {
96
- tokenize: tokenBase,
89
+ tokenize: inBase,
97
90
  wb: true,
98
91
  };
99
92
  },
package/dist/keymap.d.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import type { KeyBinding } from '@codemirror/view';
2
+ import type { EditorState } from '@codemirror/state';
3
+ import type { Tree } from '@lezer/common';
2
4
  import type { KeymapConfig } from './keybindings';
5
+ /**
6
+ * @ignore
7
+ * @test
8
+ */
9
+ export declare const getExtNames: (state: EditorState, tree: Tree, pos: number, side: 1 | -1) => string[];
3
10
  /**
4
11
  * 生成keymap
5
12
  * @param opt 快捷键设置
package/dist/keymap.js CHANGED
@@ -1,7 +1,50 @@
1
1
  import { EditorSelection } from '@codemirror/state';
2
2
  import { syntaxTree } from '@codemirror/language';
3
3
  import { keybindings, encapsulateLines } from './keybindings.js';
4
- const reKartographer = /(?:^|_)mw-tag-map(?:link|frame)(?:$|_)/u;
4
+ import { getTag } from './matchTag.js';
5
+ import { sliceDoc, getExtTags } from './util.js';
6
+ /**
7
+ * @ignore
8
+ * @test
9
+ */
10
+ export const getExtNames = (state, tree, pos, side) => {
11
+ const node = tree.resolveInner(pos, side), { name } = node;
12
+ if (name === 'Document') {
13
+ const { doc } = state, end = side === 1 ? 'to' : 'from';
14
+ let line = doc.lineAt(pos);
15
+ if (line[end] === pos) {
16
+ const { lines } = doc;
17
+ for (let { number } = line; number > 0 && number <= lines; number -= side) {
18
+ line = doc.line(number);
19
+ if (line.length > 0) {
20
+ return getExtNames(state, tree, line[end], -side);
21
+ }
22
+ }
23
+ }
24
+ return [];
25
+ }
26
+ const ext = name.includes('mw-tag-') ? getExtTags(name.split('_')) : [];
27
+ if (name.includes('mw-exttag-bracket')) {
28
+ const bracket = sliceDoc(state, node), { from } = node;
29
+ // `<score>`、`<maplink>`和`<mapfram>`内部均不可包含其他扩展标签,所以可以省略一些情形
30
+ if (side === 1 ? bracket === '</' && from === pos : bracket === '>') {
31
+ // 在扩展标签旁,如 `・</score>` 或 `<maplink>・`
32
+ const sibling = node[side === 1 ? 'nextSibling' : 'prevSibling'], tag = sibling && getTag(state, sibling);
33
+ if (tag && (side === 1 || !tag.closing)) {
34
+ ext.push(tag.name);
35
+ }
36
+ }
37
+ else if (bracket === '></' && from + 1 === pos) {
38
+ // 扩展标签内尚无内容,如 `<score>・</score>`
39
+ const { prevSibling } = node, tag = prevSibling && getTag(state, prevSibling);
40
+ if (tag) {
41
+ ext.push(tag.name);
42
+ }
43
+ }
44
+ }
45
+ return ext;
46
+ };
47
+ const isExtRange = (from, to, empty, names) => names.some(name => empty ? from.includes(name) || to.includes(name) : from.includes(name) && to.includes(name));
5
48
  /**
6
49
  * 生成keymap
7
50
  * @param opt 快捷键设置
@@ -15,30 +58,54 @@ export const getWikiKeymap = ({ key, pre = '', post = '', splitlines }) => ({
15
58
  key,
16
59
  run(view) {
17
60
  const { state } = view, tree = syntaxTree(state);
18
- view.dispatch(state.changeByRange(({ from, to }) => {
19
- if (key === 'Mod-/'
20
- && reKartographer.test(tree.resolveInner(from, 1).name)
21
- && reKartographer.test(tree.resolveInner(to, -1).name)) {
22
- // JSONC comment
23
- if (from === to) {
24
- pre = '//';
25
- post = '';
61
+ view.dispatch(state.changeByRange(({ from, to, empty }) => {
62
+ let before = pre, after = post;
63
+ if (key === 'Mod-/') {
64
+ const fromExt = getExtNames(state, tree, from, 1), toExt = getExtNames(state, tree, to, -1);
65
+ if (isExtRange(fromExt, toExt, empty, ['maplink', 'mapframe'])) {
66
+ // JSONC comment
67
+ if (empty) {
68
+ before = '//';
69
+ after = '';
70
+ }
71
+ else {
72
+ before = '/* ';
73
+ after = ' */';
74
+ }
75
+ }
76
+ else if (isExtRange(fromExt, toExt, empty, ['score-scheme'])) {
77
+ // LilyPond scheme comment
78
+ if (empty) {
79
+ before = ';';
80
+ after = '';
81
+ }
82
+ else {
83
+ before = '#! ';
84
+ after = ' !#';
85
+ }
26
86
  }
27
- else {
28
- pre = '/*';
29
- post = '*/';
87
+ else if (isExtRange(fromExt, toExt, empty, ['score'])) {
88
+ // LilyPond comment
89
+ if (empty) {
90
+ before = '%';
91
+ after = '';
92
+ }
93
+ else {
94
+ before = '%{ ';
95
+ after = ' %}';
96
+ }
30
97
  }
31
98
  }
32
99
  if (splitlines) {
33
- const start = state.doc.lineAt(from).from, end = state.doc.lineAt(to).to, insert = encapsulateLines(state.sliceDoc(start, end), pre, post);
100
+ const start = state.doc.lineAt(from).from, end = state.doc.lineAt(to).to, insert = encapsulateLines(state.sliceDoc(start, end), before, after);
34
101
  return {
35
102
  range: EditorSelection.range(start, start + insert.length),
36
103
  changes: { from: start, to: end, insert },
37
104
  };
38
105
  }
39
- const insert = pre + state.sliceDoc(from, to) + post, head = from + insert.length;
106
+ const insert = before + state.sliceDoc(from, to) + after, head = from + insert.length;
40
107
  return {
41
- range: EditorSelection.cursor(from === to ? from + pre.length : head),
108
+ range: EditorSelection.cursor(empty ? from + before.length : head),
42
109
  changes: { from, to, insert },
43
110
  };
44
111
  }));
@@ -0,0 +1,14 @@
1
+ import type { StreamParser, StringStream } from '@codemirror/language';
2
+ declare interface State {
3
+ tokenize: Tokenizer;
4
+ /** 只用于Scheme */
5
+ parens: number;
6
+ /** 只用于歌词 */
7
+ braces: number;
8
+ /** 只用于歌词 */
9
+ spaced: boolean;
10
+ lyrics: boolean;
11
+ }
12
+ declare type Tokenizer = (stream: StringStream, state: State) => string;
13
+ export declare const lilypond: StreamParser<State>;
14
+ export {};
@@ -0,0 +1,240 @@
1
+ import { inComment, getCompletions } from './util.js';
2
+ import { extData, extCompletion } from './constants.js';
3
+ let scoreFetch;
4
+ const inString = (parent) => (stream, state) => {
5
+ let escaped = false, next = stream.next();
6
+ while (next) {
7
+ if (!escaped && next === '"') {
8
+ state.tokenize = parent;
9
+ return /* #a11 */ 'string';
10
+ }
11
+ escaped = !escaped && next === '\\';
12
+ next = stream.next();
13
+ }
14
+ return /* #a11 */ 'string';
15
+ };
16
+ const inScheme = (parent) => {
17
+ const style = 'mw-tag-score-scheme';
18
+ const tokenizer = (stream, state) => {
19
+ if (stream.eatSpace()) {
20
+ return style;
21
+ }
22
+ const ch = stream.next();
23
+ switch (ch) {
24
+ case '(':
25
+ state.parens++;
26
+ return style;
27
+ case ')':
28
+ state.parens--;
29
+ if (state.parens === 0) {
30
+ state.tokenize = parent;
31
+ return 'separator';
32
+ }
33
+ return style;
34
+ case '"':
35
+ state.tokenize = inString(tokenizer);
36
+ return /* #a11 */ `string ${style}`;
37
+ case ';':
38
+ stream.skipToEnd();
39
+ return /* #940 */ `comment ${style}`;
40
+ case '#':
41
+ if (stream.eat('!')) {
42
+ state.tokenize = inComment(tokenizer, '!#');
43
+ return /* #940 */ `comment ${style}`;
44
+ }
45
+ // fall through
46
+ default:
47
+ return style;
48
+ }
49
+ };
50
+ return tokenizer;
51
+ };
52
+ const eatHash = (stream, state, ch, parent) => {
53
+ if (stream.match(/^#[tf]/u)) {
54
+ return /* #219 */ 'bool';
55
+ }
56
+ else if (ch === '#' && stream.match(/^(?:\d+|#x[\da-f]*)/iu)) {
57
+ return /* #a11 */ 'character';
58
+ }
59
+ else if (stream.eat('(')) {
60
+ state.tokenize = inScheme(parent);
61
+ state.parens = 1;
62
+ return 'separator';
63
+ }
64
+ return stream.match(/^\s*[-_a-z][-\w]*/iu) ? 'variableName.local' : 'operator';
65
+ };
66
+ const eatQuote = (state, parent) => {
67
+ state.tokenize = inString(parent);
68
+ return /* #a11 */ 'string';
69
+ };
70
+ const eatPercent = (stream, state, parent) => {
71
+ if (stream.eat('{')) {
72
+ state.tokenize = inComment(parent, '%}');
73
+ return /* #940 */ 'comment';
74
+ }
75
+ stream.skipToEnd();
76
+ return /* #940 */ 'comment';
77
+ };
78
+ const lyricsCommands = new Set(['addlyrics', 'lyricmode', 'lyrics', 'lyricsto']), setCommands = new Set(['set', 'override']), unsetCommands = new Set(['unset', 'revert', 'tweak']), newCommands = new Set(['new', 'context']);
79
+ const eatCommand = (stream, state, parent, base) => {
80
+ const mt = stream.match(/^[a-z](?:[a-z]|-+(?=[a-z]))*/iu), cmd = mt?.[0], isUnset = unsetCommands.has(cmd), isNew = newCommands.has(cmd);
81
+ if (base && lyricsCommands.has(cmd)) {
82
+ state.lyrics = true;
83
+ }
84
+ else if (isUnset || isNew || setCommands.has(cmd)) {
85
+ state.tokenize = inAssignment(parent, isUnset ? -1 : 1, isNew);
86
+ }
87
+ return mt && extData['score']?.has(`\\${cmd}`) !== false ? /* #708 */ 'keyword' : '';
88
+ };
89
+ const inAssignment = (parent, step, cls) => (stream, state) => {
90
+ if (stream.eatSpace()) {
91
+ return '';
92
+ }
93
+ else if (step === 0) {
94
+ stream.eat('=');
95
+ state.tokenize = parent;
96
+ return 'operator';
97
+ }
98
+ stream.match(/^[a-z][-\w.]*/iu);
99
+ state.tokenize = step === 1 ? inAssignment(parent, 0) : parent;
100
+ return cls ? /* #167 */ 'className' : /* #00f */ 'variableName.definition';
101
+ };
102
+ const inBase = (stream, state) => {
103
+ if (stream.eatSpace()) {
104
+ return '';
105
+ }
106
+ const ch = stream.next();
107
+ switch (ch) {
108
+ case '-':
109
+ return stream.eat(/[->.+_!^]/u) ? 'operator' : 'punctuation';
110
+ case '#':
111
+ case '$':
112
+ return eatHash(stream, state, ch, inBase);
113
+ case '"':
114
+ return eatQuote(state, inBase);
115
+ case '%':
116
+ return eatPercent(stream, state, inBase);
117
+ case '/':
118
+ stream.eat('+');
119
+ return 'punctuation';
120
+ case '\\':
121
+ if (stream.eat(/[-<>!]/u)) {
122
+ return 'operator';
123
+ }
124
+ else if (stream.eat(/[()[\]]/u)) {
125
+ return 'squareBracket';
126
+ }
127
+ return stream.eat(/[\\=]/u) ? 'punctuation' : eatCommand(stream, state, inBase, true);
128
+ case '}':
129
+ state.lyrics = false;
130
+ return 'squareBracket';
131
+ case '{':
132
+ if (state.lyrics) {
133
+ state.lyrics = false;
134
+ state.braces = 1;
135
+ state.spaced = true;
136
+ state.tokenize = inLyrics;
137
+ }
138
+ return 'squareBracket';
139
+ default:
140
+ if (/[<>()[\]]/u.test(ch)) {
141
+ return 'squareBracket';
142
+ }
143
+ else if (/[:|~^_=]/u.test(ch)) {
144
+ return 'punctuation';
145
+ }
146
+ else if (/[',.!?]/u.test(ch)) {
147
+ return 'operator';
148
+ }
149
+ else if (/\d/u.test(ch)) {
150
+ stream.match(/^\d*(?:[./]\d+)?/u);
151
+ return /* #164 */ 'number';
152
+ }
153
+ else if (/[a-z]/iu.test(ch)) {
154
+ stream.match(/^(?:[a-z]|[-_\d]+(?=[a-z]))+/iu);
155
+ return /^(?:[rs]|[a-g](?:is)*(?:ih)*|[a-g]?(?:es)*(?:eh)*)$/u.test(stream.current())
156
+ ? ''
157
+ : /* #219 */ 'atom';
158
+ }
159
+ return '';
160
+ }
161
+ };
162
+ const inLyrics = (stream, state) => {
163
+ if (stream.eatSpace()) {
164
+ state.spaced = true;
165
+ return '';
166
+ }
167
+ else if (stream.sol()) {
168
+ state.spaced = true;
169
+ }
170
+ const ch = stream.next();
171
+ switch (ch) {
172
+ case '-':
173
+ if (state.spaced && stream.match(/^-(?=\s)/u)) {
174
+ return 'punctuation';
175
+ }
176
+ state.spaced = false;
177
+ return 'string';
178
+ case '_':
179
+ case '~':
180
+ case '|':
181
+ state.spaced = false;
182
+ return 'punctuation';
183
+ case '#':
184
+ case '$':
185
+ state.spaced = false;
186
+ return eatHash(stream, state, ch, inLyrics);
187
+ case '"':
188
+ state.spaced = true;
189
+ return eatQuote(state, inLyrics);
190
+ case '%':
191
+ state.spaced = true;
192
+ return eatPercent(stream, state, inLyrics);
193
+ case '\\':
194
+ if (stream.eat(/[<>!\\]/u)) {
195
+ state.spaced = true;
196
+ return '';
197
+ }
198
+ state.spaced = false;
199
+ return eatCommand(stream, state, inLyrics);
200
+ case '{':
201
+ case '}':
202
+ state.braces += ch === '{' ? 1 : -1;
203
+ if (state.braces) {
204
+ state.spaced = true;
205
+ }
206
+ else {
207
+ state.tokenize = inBase;
208
+ }
209
+ return 'squareBracket';
210
+ default:
211
+ state.spaced = false;
212
+ if (/\d/u.test(ch)) {
213
+ stream.eatWhile(/\d/u);
214
+ return /* #164 */ 'number';
215
+ }
216
+ stream.eatWhile(/[^\s\d_~{}#$"%\\]/u);
217
+ return /* #a11 */ 'string';
218
+ }
219
+ };
220
+ export const lilypond = {
221
+ startState() {
222
+ if (typeof wikiparse === 'object') {
223
+ scoreFetch ??= (async () => {
224
+ const data = await (await fetch(`${wikiparse.CDN}/data/ext/score.json`)).json();
225
+ extData['score'] = new Set(data.flatMap(item => item.split('.')));
226
+ extCompletion['score'] = getCompletions(data.filter(s => s.startsWith('\\')), 'keyword');
227
+ })();
228
+ }
229
+ return {
230
+ tokenize: inBase,
231
+ parens: 0,
232
+ braces: 0,
233
+ lyrics: false,
234
+ spaced: false,
235
+ };
236
+ },
237
+ token(stream, state) {
238
+ return state.tokenize(stream, state);
239
+ },
240
+ };
@@ -3,7 +3,7 @@ import type { Text, EditorState } from '@codemirror/state';
3
3
  import type { Language } from '@codemirror/language';
4
4
  import type { Diagnostic, Action } from '@codemirror/lint';
5
5
  import type { Option, LiveOption } from './linter';
6
- import type { DocRange } from './fold';
6
+ import type { DocRange } from './util';
7
7
  export type LintSource<T = unknown> = ((state: EditorState) => readonly Diagnostic[] | Promise<readonly Diagnostic[]>) & {
8
8
  config?: T;
9
9
  fixer?: (doc: Text, rule?: string) => string | Promise<string>;
package/dist/lua.d.ts CHANGED
@@ -3,7 +3,7 @@ import { LanguageSupport } from '@codemirror/language';
3
3
  import type { ViewUpdate, DecorationSet } from '@codemirror/view';
4
4
  import type { EditorState } from '@codemirror/state';
5
5
  import type { Tree } from '@lezer/common';
6
- import type { DocRange } from './fold';
6
+ import type { DocRange } from './util';
7
7
  /**
8
8
  * 高亮显示LDoc标签
9
9
  * @ignore