wikiparser-node 1.16.2 → 1.16.4
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/bundle/bundle.es7.js +26 -26
- package/bundle/bundle.lsp.js +38 -0
- package/bundle/bundle.min.js +35 -0
- package/coverage/badge.svg +1 -1
- package/data/signatures.json +43 -0
- package/dist/addon/token.js +107 -107
- package/dist/lib/element.d.ts +46 -1
- package/dist/lib/element.js +95 -1
- package/dist/lib/lsp.d.ts +16 -10
- package/dist/lib/lsp.js +331 -268
- package/dist/lib/node.d.ts +1 -1
- package/dist/lib/node.js +59 -27
- package/dist/lib/title.d.ts +5 -2
- package/dist/lib/title.js +25 -12
- package/dist/mixin/attributesParent.js +18 -18
- package/dist/parser/selector.js +1 -1
- package/dist/src/heading.js +7 -7
- package/dist/src/html.d.ts +1 -5
- package/dist/src/html.js +1 -5
- package/dist/src/imageParameter.d.ts +5 -2
- package/dist/src/imageParameter.js +6 -3
- package/dist/src/index.d.ts +1 -45
- package/dist/src/index.js +0 -93
- package/dist/src/link/base.js +8 -7
- package/dist/src/link/category.d.ts +2 -2
- package/dist/src/link/index.d.ts +2 -2
- package/dist/src/link/redirectTarget.d.ts +1 -1
- package/dist/src/magicLink.d.ts +5 -2
- package/dist/src/magicLink.js +22 -17
- package/dist/src/nowiki/listBase.js +1 -1
- package/dist/src/table/base.js +1 -1
- package/dist/src/tagPair/ext.js +1 -2
- package/dist/src/transclude.d.ts +5 -0
- package/dist/src/transclude.js +27 -5
- package/dist/util/html.js +5 -1
- package/extensions/dist/base.js +286 -0
- package/extensions/dist/codejar.js +56 -0
- package/extensions/dist/editor.js +159 -0
- package/extensions/dist/highlight.js +30 -0
- package/extensions/dist/lint.js +79 -0
- package/extensions/dist/lsp.js +74 -0
- package/extensions/editor.css +59 -0
- package/extensions/es7/base.js +1 -1
- package/extensions/ui.css +162 -0
- package/package.json +4 -4
package/dist/lib/lsp.js
CHANGED
|
@@ -5,17 +5,32 @@ const path = require("path");
|
|
|
5
5
|
const common_1 = require("@bhsd/common");
|
|
6
6
|
const sharable_1 = require("../util/sharable");
|
|
7
7
|
const lint_1 = require("../util/lint");
|
|
8
|
+
const string_1 = require("../util/string");
|
|
8
9
|
const index_1 = require("../index");
|
|
9
|
-
const element_1 = require("../lib/element");
|
|
10
10
|
/* NOT FOR BROWSER */
|
|
11
11
|
const constants_1 = require("../util/constants");
|
|
12
|
+
/* NOT FOR BROWSER ONLY END */
|
|
12
13
|
exports.tasks = new WeakMap();
|
|
13
|
-
const refTags = new Set(['ref']), referencesTags = new Set(['ref', 'references']), nameAttrs = new Set(['name', 'extends', 'follow']), groupAttrs = new Set(['group'])
|
|
14
|
+
const refTags = new Set(['ref']), referencesTags = new Set(['ref', 'references']), nameAttrs = new Set(['name', 'extends', 'follow']), groupAttrs = new Set(['group']), renameTypes = new Set([
|
|
15
|
+
'arg-name',
|
|
16
|
+
'template-name',
|
|
17
|
+
'magic-word-name',
|
|
18
|
+
'link-target',
|
|
19
|
+
'parameter-key',
|
|
20
|
+
]), referenceTypes = new Set([
|
|
21
|
+
'ext',
|
|
22
|
+
'html',
|
|
23
|
+
'attr-key',
|
|
24
|
+
'image-parameter',
|
|
25
|
+
'heading-title',
|
|
26
|
+
'heading',
|
|
27
|
+
...renameTypes,
|
|
28
|
+
]), plainTypes = new Set(['text', 'comment', 'noinclude', 'include']);
|
|
14
29
|
/**
|
|
15
30
|
* Check if all child nodes are plain text or comments.
|
|
16
31
|
* @param childNodes child nodes
|
|
17
32
|
*/
|
|
18
|
-
const isPlain = (childNodes) => childNodes.every(({ type }) =>
|
|
33
|
+
const isPlain = (childNodes) => childNodes.every(({ type }) => plainTypes.has(type));
|
|
19
34
|
/**
|
|
20
35
|
* Get the position of a character in the document.
|
|
21
36
|
* @param root root token
|
|
@@ -54,8 +69,9 @@ const createNodeRange = (token) => {
|
|
|
54
69
|
* @param pos position
|
|
55
70
|
* @param pos.line line number
|
|
56
71
|
* @param pos.character character number
|
|
72
|
+
* @param extra extra text
|
|
57
73
|
*/
|
|
58
|
-
const getCompletion = (words, kind, mt, { line, character }) => [...new Set(words)].map((w) => ({
|
|
74
|
+
const getCompletion = (words, kind, mt, { line, character }, extra) => [...new Set(words)].map((w) => ({
|
|
59
75
|
label: w,
|
|
60
76
|
kind,
|
|
61
77
|
textEdit: {
|
|
@@ -63,38 +79,19 @@ const getCompletion = (words, kind, mt, { line, character }) => [...new Set(word
|
|
|
63
79
|
start: { line, character: character - mt.length },
|
|
64
80
|
end: { line, character },
|
|
65
81
|
},
|
|
66
|
-
newText: w,
|
|
82
|
+
newText: w + (extra ?? ''),
|
|
67
83
|
},
|
|
68
84
|
}));
|
|
69
85
|
/**
|
|
70
|
-
*
|
|
71
|
-
* @param page page name
|
|
72
|
-
* @param ns namespace
|
|
73
|
-
* @throws `RangeError` Invalid page name.
|
|
74
|
-
* @throws `Error` Article path is not set.
|
|
75
|
-
*/
|
|
76
|
-
const getUrl = (page, ns) => {
|
|
77
|
-
const { title, fragment, valid } = index_1.default.normalizeTitle(page, ns), { articlePath } = index_1.default.getConfig();
|
|
78
|
-
/* istanbul ignore next */
|
|
79
|
-
if (!valid) {
|
|
80
|
-
throw new RangeError('Invalid page name.');
|
|
81
|
-
}
|
|
82
|
-
else if (!articlePath) {
|
|
83
|
-
throw new Error('Article path is not set.');
|
|
84
|
-
}
|
|
85
|
-
const encoded = encodeURIComponent(title) + (fragment === undefined ? '' : `#${encodeURIComponent(fragment)}`);
|
|
86
|
-
return articlePath.includes('$1')
|
|
87
|
-
? articlePath.replace('$1', encoded)
|
|
88
|
-
: articlePath + (articlePath.endsWith('/') ? '' : '/') + encoded;
|
|
89
|
-
};
|
|
90
|
-
/**
|
|
91
|
-
* Get the token at the position from a word.
|
|
86
|
+
* Get the caret position at the position from a word.
|
|
92
87
|
* @param root root token
|
|
93
88
|
* @param pos position
|
|
89
|
+
* @param pos.line line number
|
|
90
|
+
* @param pos.character character number
|
|
94
91
|
*/
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
return root.
|
|
92
|
+
const caretPositionFromWord = (root, { line, character }) => {
|
|
93
|
+
const index = root.indexFromPos(line, character);
|
|
94
|
+
return root.caretPositionFromIndex(index + Number(/\w/u.test(root.toString().charAt(index))));
|
|
98
95
|
};
|
|
99
96
|
/**
|
|
100
97
|
* Get the attribute of a `<ref>` tag.
|
|
@@ -116,6 +113,15 @@ const getRefName = (token) => getRefAttr(token, refTags, nameAttrs);
|
|
|
116
113
|
* @param token `group` attribute token
|
|
117
114
|
*/
|
|
118
115
|
const getRefGroup = (token) => getRefAttr(token, referencesTags, groupAttrs);
|
|
116
|
+
/**
|
|
117
|
+
* Get the attribute of a `<ref>` tag.
|
|
118
|
+
* @param token extension token
|
|
119
|
+
* @param target attribute name
|
|
120
|
+
*/
|
|
121
|
+
const getRefTagAttr = (token, target) => {
|
|
122
|
+
const attr = token?.getAttr(target);
|
|
123
|
+
return attr !== true && attr || false;
|
|
124
|
+
};
|
|
119
125
|
/**
|
|
120
126
|
* Get the effective name of a token.
|
|
121
127
|
* @param token
|
|
@@ -138,6 +144,18 @@ const getName = (token) => {
|
|
|
138
144
|
}
|
|
139
145
|
};
|
|
140
146
|
/* NOT FOR BROWSER ONLY */
|
|
147
|
+
/**
|
|
148
|
+
* Get the quick fix data.
|
|
149
|
+
* @param root root token
|
|
150
|
+
* @param fix lint error fix
|
|
151
|
+
* @param preferred whether it is a preferred fix
|
|
152
|
+
*/
|
|
153
|
+
const getQuickFix = (root, fix, preferred = false) => ({
|
|
154
|
+
range: createRange(root, ...fix.range),
|
|
155
|
+
newText: fix.text,
|
|
156
|
+
title: `${preferred ? 'Fix' : 'Suggestion'}: ${fix.desc}`,
|
|
157
|
+
fix: preferred,
|
|
158
|
+
});
|
|
141
159
|
/**
|
|
142
160
|
* Get the end position of a section.
|
|
143
161
|
* @param section section
|
|
@@ -180,7 +198,7 @@ class LanguageService {
|
|
|
180
198
|
* - 否则开始新的解析
|
|
181
199
|
*/
|
|
182
200
|
async #queue(text) {
|
|
183
|
-
text =
|
|
201
|
+
text = (0, string_1.tidy)(text);
|
|
184
202
|
if (this.#text === text && this.#config === index_1.default.config && !this.#running) {
|
|
185
203
|
return this.#done;
|
|
186
204
|
}
|
|
@@ -237,7 +255,7 @@ class LanguageService {
|
|
|
237
255
|
if (type !== 'attr-value' && !isPlain(childNodes)) {
|
|
238
256
|
return [];
|
|
239
257
|
}
|
|
240
|
-
return childNodes.filter((child) => child.type === 'text')
|
|
258
|
+
return childNodes.filter((child) => child.type === 'text').reverse()
|
|
241
259
|
.flatMap(child => {
|
|
242
260
|
const parts = (0, common_1.splitColors)(child.data, hsl).filter(([, , , isColor]) => isColor);
|
|
243
261
|
if (parts.length === 0) {
|
|
@@ -277,7 +295,7 @@ class LanguageService {
|
|
|
277
295
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
|
|
278
296
|
/(?:<\/?(\w*)|(\{{2,4}|\[\[)\s*([^|{}<>[\]\s][^|{}<>[\]#]*)?|(__(?:(?!__)[\p{L}\d_])*)|(?<!\[)\[([a-z:/]*)|\[\[\s*(?:file|image)\s*:[^[\]{}<>]+\|([^[\]{}<>|=]*)|<(\w+)(?:\s(?:[^<>{}|=\s]+(?:\s*=\s*(?:[^\s"']\S*|(["']).*?\8))?(?=\s))*)?\s(\w*))$/iu;
|
|
279
297
|
const re = new RegExp('(?:' // eslint-disable-line prefer-template
|
|
280
|
-
+ String.raw
|
|
298
|
+
+ String.raw `<(\/?\w*)` // tag
|
|
281
299
|
+ '|'
|
|
282
300
|
+ String.raw `(\{{2,4}|\[\[)\s*([^|{}<>[\]\s][^|{}<>[\]#]*)?` // braces and brackets
|
|
283
301
|
+ '|'
|
|
@@ -315,9 +333,10 @@ class LanguageService {
|
|
|
315
333
|
*/
|
|
316
334
|
async provideCompletionItems(text, position) {
|
|
317
335
|
this.#checkSignature();
|
|
318
|
-
const { re, allTags, functions, switches, protocols, params, tags, ext } = this.#prepareCompletionConfig(), { line, character } = position,
|
|
336
|
+
const { re, allTags, functions, switches, protocols, params, tags, ext } = this.#prepareCompletionConfig(), { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], mt = re.exec(curLine?.slice(0, character) ?? '');
|
|
319
337
|
if (mt?.[1] !== undefined) { // tag
|
|
320
|
-
|
|
338
|
+
const closing = mt[1].startsWith('/');
|
|
339
|
+
return getCompletion(allTags, 'Class', mt[1].slice(closing ? 1 : 0), position, closing && !curLine?.slice(character).trim().startsWith('>') ? '>' : '');
|
|
321
340
|
}
|
|
322
341
|
else if (mt?.[4]) { // behavior switch
|
|
323
342
|
return getCompletion(switches, 'Constant', mt[4], position);
|
|
@@ -326,34 +345,53 @@ class LanguageService {
|
|
|
326
345
|
return getCompletion(protocols, 'Reference', mt[5], position);
|
|
327
346
|
}
|
|
328
347
|
const root = await this.#queue(text);
|
|
348
|
+
let cur;
|
|
329
349
|
if (mt?.[2]) {
|
|
350
|
+
cur = root.elementFromPoint(mt.index + mt[2].length - 1, line);
|
|
330
351
|
const match = mt[3] ?? '';
|
|
331
352
|
if (mt[2] === '{{{') { // argument
|
|
332
|
-
return getCompletion(root.querySelectorAll('arg').
|
|
353
|
+
return getCompletion(root.querySelectorAll('arg').filter(token => token.name && token !== cur)
|
|
354
|
+
.map(({ name }) => name), 'Variable', match, position);
|
|
333
355
|
}
|
|
334
356
|
const colon = match.startsWith(':'), str = colon ? match.slice(1).trimStart() : match;
|
|
335
357
|
return mt[2] === '[['
|
|
336
358
|
? getCompletion(// link
|
|
337
|
-
root.querySelectorAll('link,file,category,redirect-target').map(({ name }) => name), 'Folder', str, position)
|
|
359
|
+
root.querySelectorAll('link,file,category,redirect-target').filter(token => token !== cur).map(({ name }) => name), 'Folder', str, position)
|
|
338
360
|
: [
|
|
339
361
|
...getCompletion(functions, 'Function', match, position),
|
|
340
362
|
...match.startsWith('#')
|
|
341
363
|
? []
|
|
342
|
-
: getCompletion(root.querySelectorAll('template')
|
|
343
|
-
.map(
|
|
364
|
+
: getCompletion(root.querySelectorAll('template').filter(token => token !== cur)
|
|
365
|
+
.map(token => {
|
|
366
|
+
const { name } = token;
|
|
367
|
+
if (colon) {
|
|
368
|
+
return name;
|
|
369
|
+
}
|
|
370
|
+
const { ns } = token.getAttribute('title');
|
|
371
|
+
if (ns === 0) {
|
|
372
|
+
return `:${name}`;
|
|
373
|
+
}
|
|
374
|
+
return ns === 10 ? name.slice(9) : name;
|
|
375
|
+
}), 'Folder', str, position),
|
|
344
376
|
];
|
|
345
377
|
}
|
|
346
|
-
|
|
378
|
+
let type, parentNode;
|
|
379
|
+
if (mt?.[7] === undefined) {
|
|
380
|
+
cur = root.elementFromPoint(character, line);
|
|
381
|
+
({ type, parentNode } = cur);
|
|
382
|
+
}
|
|
347
383
|
if (mt?.[6] !== undefined || type === 'image-parameter') { // image parameter
|
|
348
|
-
const match = mt?.[6]?.trimStart()
|
|
349
|
-
?? this.#text.slice(
|
|
384
|
+
const index = root.indexFromPos(line, character), match = mt?.[6]?.trimStart()
|
|
385
|
+
?? this.#text.slice(cur.getAbsoluteIndex(), index).trimStart(), equal = this.#text.charAt(index) === '=';
|
|
350
386
|
return [
|
|
351
|
-
...getCompletion(params, 'Property', match, position)
|
|
352
|
-
|
|
387
|
+
...getCompletion(params, 'Property', match, position)
|
|
388
|
+
.filter(({ label }) => !equal || !/[= ]$/u.test(label)),
|
|
389
|
+
...getCompletion(root.querySelectorAll('image-parameter#width').filter(token => token !== cur)
|
|
390
|
+
.map(width => width.text()), 'Unit', match, position),
|
|
353
391
|
];
|
|
354
392
|
}
|
|
355
393
|
else if (mt?.[7] !== undefined || type === 'attr-key') { // attribute key
|
|
356
|
-
const tag = mt?.[7]?.toLowerCase() ?? parentNode.tag, key = mt?.[9] ??
|
|
394
|
+
const tag = mt?.[7]?.toLowerCase() ?? parentNode.tag, key = mt?.[9] ?? cur.toString();
|
|
357
395
|
if (!tags.has(tag)) {
|
|
358
396
|
return undefined;
|
|
359
397
|
}
|
|
@@ -372,12 +410,27 @@ class LanguageService {
|
|
|
372
410
|
...getCompletion(['xmlns:'], 'Interface', key, position),
|
|
373
411
|
];
|
|
374
412
|
}
|
|
375
|
-
else if (
|
|
376
|
-
|
|
377
|
-
const
|
|
413
|
+
else if (type === 'parameter-key' || type === 'parameter-value' && parentNode.anon) {
|
|
414
|
+
// parameter key
|
|
415
|
+
const transclusion = parentNode.parentNode;
|
|
416
|
+
if (transclusion.type === 'magic-word' && transclusion.name !== 'invoke') {
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
const key = cur.toString().trimStart(), [module, func] = transclusion.type === 'magic-word' ? transclusion.getModule() : [];
|
|
378
420
|
return key
|
|
379
|
-
? getCompletion(root.querySelectorAll('parameter').filter(
|
|
380
|
-
|
|
421
|
+
? getCompletion(root.querySelectorAll('parameter').filter(token => {
|
|
422
|
+
if (token === parentNode
|
|
423
|
+
|| token.anon
|
|
424
|
+
|| token.parentNode.type !== transclusion.type
|
|
425
|
+
|| token.parentNode.name !== transclusion.name) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
else if (transclusion.type === 'template') {
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
const [m, f] = token.parentNode.getModule();
|
|
432
|
+
return m === module && f === func;
|
|
433
|
+
}).map(({ name }) => name), 'Variable', key, position, type === 'parameter-value' ? '=' : '')
|
|
381
434
|
: undefined;
|
|
382
435
|
}
|
|
383
436
|
return undefined;
|
|
@@ -400,86 +453,41 @@ class LanguageService {
|
|
|
400
453
|
source: 'WikiLint',
|
|
401
454
|
code: rule,
|
|
402
455
|
message,
|
|
456
|
+
/* NOT FOR BROWSER ONLY */
|
|
403
457
|
data: [
|
|
404
|
-
...fix
|
|
405
|
-
|
|
406
|
-
{
|
|
407
|
-
range: createRange(root, ...fix.range),
|
|
408
|
-
newText: fix.text,
|
|
409
|
-
title: `Fix: ${fix.desc}`,
|
|
410
|
-
fix: true,
|
|
411
|
-
},
|
|
412
|
-
]
|
|
413
|
-
: [],
|
|
414
|
-
...suggestions
|
|
415
|
-
? suggestions.map(({ range, text, desc }) => ({
|
|
416
|
-
range: createRange(root, ...range),
|
|
417
|
-
newText: text,
|
|
418
|
-
title: `Suggestion: ${desc}`,
|
|
419
|
-
fix: false,
|
|
420
|
-
}))
|
|
421
|
-
: [],
|
|
458
|
+
...fix ? [getQuickFix(root, fix, true)] : [],
|
|
459
|
+
...suggestions ? suggestions.map(suggestion => getQuickFix(root, suggestion)) : [],
|
|
422
460
|
],
|
|
423
461
|
}));
|
|
424
462
|
}
|
|
425
|
-
|
|
463
|
+
/**
|
|
464
|
+
* 提供折叠范围
|
|
465
|
+
* @param text 源代码
|
|
466
|
+
*/
|
|
467
|
+
async provideFoldingRanges(text) {
|
|
426
468
|
this.#checkSignature();
|
|
427
|
-
const ranges = [],
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
root = await this.#queue(text), lines = root.getLines(), { length } = lines, levels = new Array(6), tokens = root.querySelectorAll(fold ? 'heading-title,table,template,magic-word' : 'heading-title');
|
|
469
|
+
const root = await this.#queue(text), { length } = root.getLines(), ranges = [], levels = new Array(6), tokens = root.querySelectorAll('heading-title,table,template,magic-word');
|
|
470
|
+
for (const token of [...tokens].reverse()) { // 提高 getBoundingClientRect 的性能
|
|
471
|
+
token.getRelativeIndex();
|
|
472
|
+
}
|
|
432
473
|
for (const token of tokens) {
|
|
433
|
-
const { top, height
|
|
434
|
-
/* NOT FOR BROWSER ONLY */
|
|
435
|
-
left, width, } = token.getBoundingClientRect();
|
|
474
|
+
const { top, height } = token.getBoundingClientRect();
|
|
436
475
|
if (token.type === 'heading-title') {
|
|
437
476
|
const { level } = token.parentNode;
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
levels[i] = undefined;
|
|
477
|
+
for (let i = level - 1; i < 6; i++) {
|
|
478
|
+
const startLine = levels[i];
|
|
479
|
+
if (startLine !== undefined && startLine < top - 1) {
|
|
480
|
+
ranges.push({
|
|
481
|
+
startLine,
|
|
482
|
+
endLine: top - 1,
|
|
483
|
+
kind: 'region',
|
|
484
|
+
});
|
|
449
485
|
}
|
|
450
|
-
levels[
|
|
451
|
-
/* NOT FOR BROWSER ONLY */
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
for (let i = level - 1; i < 6; i++) {
|
|
455
|
-
getSectionEnd(sections[i], lines, top - 1);
|
|
456
|
-
sections[i] = undefined;
|
|
457
|
-
}
|
|
458
|
-
const section = token.text().trim() || ' ', name = names.has(section)
|
|
459
|
-
? new Array(names.size).fill('').map((_, i) => `${section.trim()}_${i + 2}`)
|
|
460
|
-
.find(s => !names.has(s))
|
|
461
|
-
: section, container = sections.slice(0, level - 1).reverse().find(Boolean), selectionRange = {
|
|
462
|
-
start: { line: top, character: left - level },
|
|
463
|
-
end: (0, lint_1.getEndPos)(top, left, height, width + level),
|
|
464
|
-
}, info = {
|
|
465
|
-
name,
|
|
466
|
-
kind: 15,
|
|
467
|
-
range: { start: selectionRange.start },
|
|
468
|
-
selectionRange,
|
|
469
|
-
};
|
|
470
|
-
names.add(name);
|
|
471
|
-
sections[level - 1] = info;
|
|
472
|
-
if (container) {
|
|
473
|
-
container.children ??= [];
|
|
474
|
-
container.children.push(info);
|
|
475
|
-
}
|
|
476
|
-
else {
|
|
477
|
-
symbols.push(info);
|
|
478
|
-
}
|
|
479
|
-
/* NOT FOR BROWSER ONLY END */
|
|
486
|
+
levels[i] = undefined;
|
|
480
487
|
}
|
|
488
|
+
levels[level - 1] = top + height - 1; // 从标题的最后一行开始折叠
|
|
481
489
|
}
|
|
482
|
-
else if (
|
|
490
|
+
else if (height > 2) {
|
|
483
491
|
ranges.push({
|
|
484
492
|
startLine: top, // 从表格或模板的第一行开始折叠
|
|
485
493
|
endLine: top + height - 2,
|
|
@@ -487,32 +495,16 @@ class LanguageService {
|
|
|
487
495
|
});
|
|
488
496
|
}
|
|
489
497
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
/* NOT FOR BROWSER ONLY */
|
|
501
|
-
}
|
|
502
|
-
else {
|
|
503
|
-
for (const section of sections) {
|
|
504
|
-
getSectionEnd(section, lines, length - 1);
|
|
498
|
+
for (const startLine of levels) {
|
|
499
|
+
if (startLine !== undefined && startLine < length - 1) {
|
|
500
|
+
ranges.push({
|
|
501
|
+
startLine,
|
|
502
|
+
endLine: length - 1,
|
|
503
|
+
kind: 'region',
|
|
504
|
+
});
|
|
505
505
|
}
|
|
506
|
-
/* NOT FOR BROWSER ONLY END */
|
|
507
506
|
}
|
|
508
|
-
return
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* 提供折叠范围
|
|
512
|
-
* @param text 源代码
|
|
513
|
-
*/
|
|
514
|
-
async provideFoldingRanges(text) {
|
|
515
|
-
return this.#provideFoldingRangesOrDocumentSymbols(text);
|
|
507
|
+
return ranges;
|
|
516
508
|
}
|
|
517
509
|
/**
|
|
518
510
|
* 提供链接
|
|
@@ -521,109 +513,79 @@ class LanguageService {
|
|
|
521
513
|
async provideLinks(text) {
|
|
522
514
|
this.#checkSignature();
|
|
523
515
|
/^(?:http:\/\/|\/\/)/iu; // eslint-disable-line @typescript-eslint/no-unused-expressions
|
|
524
|
-
const protocolRegex = new RegExp(`^(?:${
|
|
525
|
-
|
|
526
|
-
|
|
516
|
+
const { articlePath, protocol } = index_1.default.getConfig(), absolute = articlePath?.includes('//'), protocolRegex = new RegExp(`^(?:${protocol}|//)`, 'iu');
|
|
517
|
+
return (await this.#queue(text))
|
|
518
|
+
.querySelectorAll(`magic-link,ext-link-url,free-ext-link,attr-value,image-parameter#link${absolute ? ',link-target,template-name,invoke-module' : ''}`).reverse()
|
|
519
|
+
.map((token) => {
|
|
527
520
|
const { type, parentNode, firstChild, lastChild, childNodes } = token, { name, tag } = parentNode;
|
|
528
521
|
if (!(type !== 'attr-value'
|
|
529
522
|
|| name === 'src' && ['templatestyles', 'img'].includes(tag)
|
|
530
523
|
|| name === 'cite' && ['blockquote', 'del', 'ins', 'q'].includes(tag))
|
|
531
524
|
|| !isPlain(childNodes)) {
|
|
532
|
-
return
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
let target = childNodes.filter((node) => node.type === 'text')
|
|
528
|
+
.map(({ data }) => data).join('').trim();
|
|
529
|
+
if (!target) {
|
|
530
|
+
return false;
|
|
533
531
|
}
|
|
534
|
-
let target = type === 'image-parameter'
|
|
535
|
-
? element_1.AstElement.prototype.toString.call(token, true).trim()
|
|
536
|
-
: token.toString(true).trim();
|
|
537
532
|
try {
|
|
538
|
-
if (
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
533
|
+
if (token.is('magic-link')
|
|
534
|
+
|| token.is('ext-link-url')
|
|
535
|
+
|| token.is('free-ext-link')) {
|
|
536
|
+
target = token.getUrl(articlePath);
|
|
537
|
+
}
|
|
538
|
+
else if (type === 'link-target' && (parentNode.is('link')
|
|
539
|
+
|| parentNode.is('redirect-target')
|
|
540
|
+
|| parentNode.is('category'))) {
|
|
541
|
+
if (target.startsWith('/')) {
|
|
542
|
+
return false;
|
|
546
543
|
}
|
|
544
|
+
target = parentNode.link.getUrl(articlePath);
|
|
547
545
|
}
|
|
548
|
-
else if (
|
|
546
|
+
else if (type === 'template-name') {
|
|
547
|
+
target = parentNode.getAttribute('title').getUrl(articlePath);
|
|
548
|
+
}
|
|
549
|
+
else if (['link-target', 'invoke-module'].includes(type)
|
|
549
550
|
|| type === 'attr-value' && name === 'src' && tag === 'templatestyles'
|
|
550
551
|
|| type === 'image-parameter' && !protocolRegex.test(target)) {
|
|
551
|
-
if (target.startsWith('/')) {
|
|
552
|
-
return
|
|
552
|
+
if (!absolute || target.startsWith('/')) {
|
|
553
|
+
return false;
|
|
553
554
|
}
|
|
554
555
|
let ns = 0;
|
|
555
|
-
if (type === '
|
|
556
|
+
if (type === 'attr-value') {
|
|
556
557
|
ns = 10;
|
|
557
558
|
}
|
|
558
559
|
else if (type === 'invoke-module') {
|
|
559
560
|
ns = 828;
|
|
560
561
|
}
|
|
561
|
-
|
|
562
|
+
const title = index_1.default.normalizeTitle(target, ns);
|
|
563
|
+
/* istanbul ignore if */
|
|
564
|
+
if (!title.valid) {
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
target = title.getUrl();
|
|
562
568
|
}
|
|
563
|
-
if (target.startsWith('//')) {
|
|
569
|
+
if (typeof target === 'string' && target.startsWith('//')) {
|
|
564
570
|
target = `https:${target}`;
|
|
565
571
|
}
|
|
566
572
|
target = new URL(target).href;
|
|
567
573
|
if (type === 'image-parameter') {
|
|
568
|
-
const
|
|
569
|
-
return
|
|
570
|
-
{
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
end: (0, lint_1.getEndPos)(top, left, height, width),
|
|
574
|
-
},
|
|
575
|
-
target,
|
|
574
|
+
const { top, left, height, width } = lastChild.getBoundingClientRect(), rect = firstChild.getBoundingClientRect();
|
|
575
|
+
return {
|
|
576
|
+
range: {
|
|
577
|
+
start: { line: rect.top, character: rect.left },
|
|
578
|
+
end: (0, lint_1.getEndPos)(top, left, height, width),
|
|
576
579
|
},
|
|
577
|
-
|
|
580
|
+
target,
|
|
581
|
+
};
|
|
578
582
|
}
|
|
579
|
-
return
|
|
583
|
+
return { range: createNodeRange(token), target };
|
|
580
584
|
}
|
|
581
585
|
catch {
|
|
582
|
-
return
|
|
583
|
-
}
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
async #provideReferencesOrDefinition(text, position, usage) {
|
|
587
|
-
this.#checkSignature();
|
|
588
|
-
const renameTypes = [
|
|
589
|
-
'arg-name',
|
|
590
|
-
'template-name',
|
|
591
|
-
'magic-word-name',
|
|
592
|
-
'link-target',
|
|
593
|
-
'parameter-key',
|
|
594
|
-
], types = [
|
|
595
|
-
'ext',
|
|
596
|
-
'html',
|
|
597
|
-
'attr-key',
|
|
598
|
-
'image-parameter',
|
|
599
|
-
'heading-title',
|
|
600
|
-
'heading',
|
|
601
|
-
...renameTypes,
|
|
602
|
-
], root = await this.#queue(text), node = elementFromWord(root, position), { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
|
|
603
|
-
if (usage === 2 && type === 'parameter-key' && /^[1-9]\d*$/u.test(node.parentNode.name)
|
|
604
|
-
|| !refName && (usage === 1
|
|
605
|
-
|| !refGroup && (usage === 0
|
|
606
|
-
? !types.includes(type)
|
|
607
|
-
: !renameTypes.includes(type)
|
|
608
|
-
|| type === 'link-target' && !['link', 'redirect-target'].includes(node.parentNode.type)))) {
|
|
609
|
-
return undefined;
|
|
610
|
-
}
|
|
611
|
-
else if (usage === 2) {
|
|
612
|
-
return createNodeRange(node);
|
|
613
|
-
}
|
|
614
|
-
const name = getName(node), refs = root.querySelectorAll(type === 'heading-title' ? 'heading' : type).filter(token => {
|
|
615
|
-
const { name: n, parentNode } = token.parentNode;
|
|
616
|
-
if (usage === 1) {
|
|
617
|
-
return getRefName(token) === refName
|
|
618
|
-
&& n === 'name' && parentNode.parentNode.innerText;
|
|
586
|
+
return false;
|
|
619
587
|
}
|
|
620
|
-
|
|
621
|
-
? getRefName(token) === refName || getRefGroup(token) === refGroup
|
|
622
|
-
: getName(token) === name;
|
|
623
|
-
}).map((token) => ({
|
|
624
|
-
range: createNodeRange(token.type === 'parameter-key' ? token.parentNode : token),
|
|
625
|
-
}));
|
|
626
|
-
return refs.length === 0 ? undefined : refs;
|
|
588
|
+
}).filter(Boolean);
|
|
627
589
|
}
|
|
628
590
|
/**
|
|
629
591
|
* 提供引用
|
|
@@ -631,53 +593,87 @@ class LanguageService {
|
|
|
631
593
|
* @param position 位置
|
|
632
594
|
*/
|
|
633
595
|
async provideReferences(text, position) {
|
|
634
|
-
|
|
596
|
+
this.#checkSignature();
|
|
597
|
+
const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, position), element = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, node = offset === 0 && (element.type === 'ext-attr-dirty' || element.type === 'html-attr-dirty')
|
|
598
|
+
? element.parentNode.parentNode
|
|
599
|
+
: element, { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
|
|
600
|
+
if (!refName && !refGroup && !referenceTypes.has(type)) {
|
|
601
|
+
return undefined;
|
|
602
|
+
}
|
|
603
|
+
const name = getName(node), refs = root.querySelectorAll(type === 'heading-title' ? 'heading' : type).filter(token => type === 'attr-value'
|
|
604
|
+
? getRefName(token) === refName || getRefGroup(token) === refGroup
|
|
605
|
+
: getName(token) === name).map((token) => ({
|
|
606
|
+
range: createNodeRange(token.type === 'parameter-key' ? token.parentNode : token),
|
|
607
|
+
}));
|
|
608
|
+
return refs.length === 0 ? undefined : refs;
|
|
635
609
|
}
|
|
636
610
|
/**
|
|
637
611
|
* 提供定义
|
|
638
612
|
* @param text 源代码
|
|
639
|
-
* @param
|
|
613
|
+
* @param pos 位置
|
|
614
|
+
* @param pos.line 行号
|
|
615
|
+
* @param pos.character 列号
|
|
640
616
|
*/
|
|
641
|
-
async provideDefinition(text,
|
|
642
|
-
|
|
617
|
+
async provideDefinition(text, { line, character }) {
|
|
618
|
+
this.#checkSignature();
|
|
619
|
+
const root = await this.#queue(text), node = root.elementFromPoint(character, line), ext = node.is('ext') && node.name === 'ref' ? node : node.closest('ext#ref'), refName = getRefTagAttr(ext, 'name');
|
|
620
|
+
if (!refName) {
|
|
621
|
+
return undefined;
|
|
622
|
+
}
|
|
623
|
+
const refGroup = getRefTagAttr(ext, 'group'), refs = root.querySelectorAll('ext#ref').filter(token => token.innerText
|
|
624
|
+
&& getRefTagAttr(token, 'name') === refName
|
|
625
|
+
&& getRefTagAttr(token, 'group') === refGroup).map(({ lastChild }) => ({
|
|
626
|
+
range: createNodeRange(lastChild),
|
|
627
|
+
}));
|
|
628
|
+
return refs.length === 0 ? undefined : refs;
|
|
643
629
|
}
|
|
644
630
|
/**
|
|
645
631
|
* 提供变量更名准备
|
|
646
632
|
* @param text 源代码
|
|
647
|
-
* @param
|
|
633
|
+
* @param pos 位置
|
|
634
|
+
* @param pos.line 行号
|
|
635
|
+
* @param pos.character 列号
|
|
648
636
|
*/
|
|
649
|
-
async resolveRenameLocation(text,
|
|
650
|
-
|
|
637
|
+
async resolveRenameLocation(text, { line, character }) {
|
|
638
|
+
this.#checkSignature();
|
|
639
|
+
const root = await this.#queue(text), node = root.elementFromPoint(character, line), { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
|
|
640
|
+
return !refName && !refGroup && (!renameTypes.has(type)
|
|
641
|
+
|| type === 'parameter-key' && /^[1-9]\d*$/u.test(node.parentNode.name)
|
|
642
|
+
|| type === 'link-target' && !['link', 'redirect-target'].includes(node.parentNode.type))
|
|
643
|
+
? undefined
|
|
644
|
+
: createNodeRange(node);
|
|
651
645
|
}
|
|
652
646
|
/**
|
|
653
647
|
* 变量更名
|
|
654
648
|
* @param text 源代码
|
|
655
|
-
* @param
|
|
649
|
+
* @param pos 位置
|
|
650
|
+
* @param pos.line 行号
|
|
651
|
+
* @param pos.character 列号
|
|
656
652
|
* @param newName 新名称
|
|
657
653
|
*/
|
|
658
|
-
async provideRenameEdits(text,
|
|
654
|
+
async provideRenameEdits(text, { line, character }, newName) {
|
|
659
655
|
this.#checkSignature();
|
|
660
|
-
const root = await this.#queue(text), node =
|
|
661
|
-
const name = getName(node), refs = root.querySelectorAll(type).filter(token => {
|
|
656
|
+
const root = await this.#queue(text), node = root.elementFromPoint(character, line), { type } = node, refName = getRefName(node), refNameGroup = refName && getRefTagAttr(node.parentNode.parentNode, 'group'), refGroup = getRefGroup(node), name = getName(node), refs = root.querySelectorAll(type).filter(token => {
|
|
662
657
|
const { type: t } = token.parentNode;
|
|
663
658
|
if (type === 'link-target' && t !== 'link' && t !== 'redirect-target') {
|
|
664
659
|
return false;
|
|
665
660
|
}
|
|
666
661
|
return type === 'attr-value'
|
|
667
|
-
?
|
|
662
|
+
? getRefGroup(token) === refGroup
|
|
663
|
+
|| getRefName(token) === refName
|
|
664
|
+
&& getRefTagAttr(token.parentNode.parentNode, 'group') === refNameGroup
|
|
668
665
|
: getName(token) === name;
|
|
669
666
|
});
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
};
|
|
667
|
+
return refs.length === 0
|
|
668
|
+
? undefined
|
|
669
|
+
: {
|
|
670
|
+
changes: {
|
|
671
|
+
'': refs.map((ref) => ({
|
|
672
|
+
range: createNodeRange(ref),
|
|
673
|
+
newText: newName,
|
|
674
|
+
})),
|
|
675
|
+
},
|
|
676
|
+
};
|
|
681
677
|
}
|
|
682
678
|
/**
|
|
683
679
|
* 检索解析器函数
|
|
@@ -697,14 +693,33 @@ class LanguageService {
|
|
|
697
693
|
return undefined;
|
|
698
694
|
}
|
|
699
695
|
this.#checkSignature();
|
|
700
|
-
const
|
|
701
|
-
let info, f;
|
|
696
|
+
const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, position), token = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, { type, parentNode, length, name } = token;
|
|
697
|
+
let info, f, range;
|
|
702
698
|
if (token.is('double-underscore')) {
|
|
699
|
+
if (offset === 0 && token.getBoundingClientRect().left > position.character) {
|
|
700
|
+
return undefined;
|
|
701
|
+
}
|
|
703
702
|
info = this.data.behaviorSwitches.find(({ aliases }) => aliases.includes(token.innerText.toLowerCase()));
|
|
704
703
|
}
|
|
705
|
-
else if (
|
|
706
|
-
info = this.#getParserFunction(
|
|
707
|
-
f = token.
|
|
704
|
+
else if (type === 'magic-word-name') {
|
|
705
|
+
info = this.#getParserFunction(parentNode.name);
|
|
706
|
+
f = token.toString(true).trim();
|
|
707
|
+
}
|
|
708
|
+
else if (token.is('magic-word') && length === 1 && !token.modifier) {
|
|
709
|
+
info = this.#getParserFunction(name);
|
|
710
|
+
f = token.firstChild.toString(true).trim();
|
|
711
|
+
}
|
|
712
|
+
else if ((token.is('magic-word') || token.is('template'))
|
|
713
|
+
&& token.modifier && offset >= 2 && token.getRelativeIndex(0) > offset) {
|
|
714
|
+
f = token.modifier.trim().slice(0, -1);
|
|
715
|
+
info = this.#getParserFunction(f.toLowerCase());
|
|
716
|
+
if (info) {
|
|
717
|
+
const aIndex = token.getAbsoluteIndex();
|
|
718
|
+
range = {
|
|
719
|
+
start: positionAt(root, aIndex + 2),
|
|
720
|
+
end: positionAt(root, aIndex + token.modifier.trimEnd().length + 1),
|
|
721
|
+
};
|
|
722
|
+
}
|
|
708
723
|
}
|
|
709
724
|
return info && {
|
|
710
725
|
contents: {
|
|
@@ -714,7 +729,7 @@ class LanguageService {
|
|
|
714
729
|
: '')
|
|
715
730
|
+ info.description,
|
|
716
731
|
},
|
|
717
|
-
range: createNodeRange(token),
|
|
732
|
+
range: range ?? createNodeRange(token),
|
|
718
733
|
};
|
|
719
734
|
}
|
|
720
735
|
/**
|
|
@@ -732,32 +747,41 @@ class LanguageService {
|
|
|
732
747
|
throw new Error('This is a regular language server!');
|
|
733
748
|
}
|
|
734
749
|
this.#signature = true;
|
|
735
|
-
const { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], { lastChild } = await this.#queue(`${curLine.slice(0, character + /^[^{}<]*/u.exec(curLine.slice(character))[0].length)}}}`)
|
|
736
|
-
if (
|
|
750
|
+
const { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], { lastChild } = await this.#queue(`${curLine.slice(0, character + /^[^{}<]*/u.exec(curLine.slice(character))[0].length)}}}`);
|
|
751
|
+
if (!lastChild.is('magic-word') || lastChild.length === 1) {
|
|
737
752
|
return undefined;
|
|
738
753
|
}
|
|
739
|
-
const info = this.#getParserFunction(name);
|
|
754
|
+
const { name, childNodes, firstChild } = lastChild, info = this.#getParserFunction(name);
|
|
740
755
|
if (!info?.signatures) {
|
|
741
756
|
return undefined;
|
|
742
757
|
}
|
|
743
|
-
const
|
|
744
|
-
let activeParameter = childNodes.findIndex(child => child.getRelativeIndex() > character - start) - 2;
|
|
745
|
-
if (activeParameter === -3) {
|
|
746
|
-
activeParameter = n - 1;
|
|
747
|
-
}
|
|
748
|
-
const signatures = info.signatures.filter(params => (params.length >= n || params[params.length - 1]?.rest)
|
|
758
|
+
const n = childNodes.length - 1, candidates = info.signatures.filter(params => (params.length >= n || params[params.length - 1]?.rest)
|
|
749
759
|
&& params.every(({ label, const: c }, i) => {
|
|
750
|
-
const p = c && i < n && childNodes[i + 1]?.
|
|
751
|
-
return !p || label.
|
|
752
|
-
}))
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
760
|
+
const p = c && i < n && childNodes[i + 1]?.toString(true).trim();
|
|
761
|
+
return !p || label.toLowerCase().includes(p.toLowerCase());
|
|
762
|
+
}));
|
|
763
|
+
if (candidates.length === 0) {
|
|
764
|
+
return undefined;
|
|
765
|
+
}
|
|
766
|
+
let j = -1;
|
|
767
|
+
for (let cur = lastChild.getAbsoluteIndex() + lastChild.getAttribute('padding'); j < n; j++) {
|
|
768
|
+
cur += childNodes[j + 1].toString().length + 1;
|
|
769
|
+
if (cur > character) {
|
|
770
|
+
break;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
const f = firstChild.toString(true).trim();
|
|
774
|
+
return {
|
|
775
|
+
signatures: candidates.map((params) => ({
|
|
776
|
+
label: `{{${f}${params.length === 0 ? '' : ':'}${params.map(({ label }) => label).join('|')}}}`,
|
|
777
|
+
parameters: params.map(({ label, const: c }) => ({
|
|
778
|
+
label,
|
|
779
|
+
...c ? { documentation: 'Predefined parameter' } : undefined,
|
|
780
|
+
})),
|
|
781
|
+
...params.length < n ? { activeParameter: Math.min(j, params.length - 1) } : undefined,
|
|
757
782
|
})),
|
|
758
|
-
|
|
759
|
-
}
|
|
760
|
-
return { signatures, activeParameter };
|
|
783
|
+
activeParameter: j,
|
|
784
|
+
};
|
|
761
785
|
}
|
|
762
786
|
/**
|
|
763
787
|
* 提供 CodeLens
|
|
@@ -769,7 +793,7 @@ class LanguageService {
|
|
|
769
793
|
for (const template of root.querySelectorAll('template,magic-word#invoke')) {
|
|
770
794
|
const { type, childNodes } = template;
|
|
771
795
|
hints.push(...childNodes.slice(type === 'template' ? 1 : 3).filter(({ anon }) => anon)
|
|
772
|
-
.map((parameter) => ({
|
|
796
|
+
.reverse().map((parameter) => ({
|
|
773
797
|
position: positionAt(root, parameter.getAbsoluteIndex()),
|
|
774
798
|
label: `${parameter.name}=`,
|
|
775
799
|
kind: 2,
|
|
@@ -796,7 +820,46 @@ class LanguageService {
|
|
|
796
820
|
* @param text 源代码
|
|
797
821
|
*/
|
|
798
822
|
async provideDocumentSymbols(text) {
|
|
799
|
-
|
|
823
|
+
this.#checkSignature();
|
|
824
|
+
const root = await this.#queue(text), lines = root.getLines(), { length } = lines, symbols = [], names = new Set(), sections = new Array(6), tokens = root.querySelectorAll('heading-title');
|
|
825
|
+
for (const token of [...tokens].reverse()) { // 提高 getBoundingClientRect 的性能
|
|
826
|
+
token.getRelativeIndex();
|
|
827
|
+
}
|
|
828
|
+
for (const token of tokens) {
|
|
829
|
+
const { top, height, left, width } = token.getBoundingClientRect();
|
|
830
|
+
if (token.type === 'heading-title') {
|
|
831
|
+
const { level } = token.parentNode;
|
|
832
|
+
for (let i = level - 1; i < 6; i++) {
|
|
833
|
+
getSectionEnd(sections[i], lines, top - 1);
|
|
834
|
+
sections[i] = undefined;
|
|
835
|
+
}
|
|
836
|
+
const section = token.text().trim() || ' ', name = names.has(section)
|
|
837
|
+
? new Array(names.size).fill('').map((_, i) => `${section.trim()}_${i + 2}`)
|
|
838
|
+
.find(s => !names.has(s))
|
|
839
|
+
: section, container = sections.slice(0, level - 1).reverse().find(Boolean), selectionRange = {
|
|
840
|
+
start: { line: top, character: left - level },
|
|
841
|
+
end: (0, lint_1.getEndPos)(top, left, height, width + level),
|
|
842
|
+
}, info = {
|
|
843
|
+
name,
|
|
844
|
+
kind: 15,
|
|
845
|
+
range: { start: selectionRange.start },
|
|
846
|
+
selectionRange,
|
|
847
|
+
};
|
|
848
|
+
names.add(name);
|
|
849
|
+
sections[level - 1] = info;
|
|
850
|
+
if (container) {
|
|
851
|
+
container.children ??= [];
|
|
852
|
+
container.children.push(info);
|
|
853
|
+
}
|
|
854
|
+
else {
|
|
855
|
+
symbols.push(info);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
for (const section of sections) {
|
|
860
|
+
getSectionEnd(section, lines, length - 1);
|
|
861
|
+
}
|
|
862
|
+
return symbols;
|
|
800
863
|
}
|
|
801
864
|
}
|
|
802
865
|
exports.LanguageService = LanguageService;
|