wikilint 2.16.4 → 2.16.6
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/base.d.mts +84 -27
- package/dist/base.d.ts +84 -27
- package/dist/bin/cli.js +2 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +55 -11
- package/dist/lib/element.d.ts +42 -16
- package/dist/lib/element.js +45 -17
- package/dist/lib/lsp.d.ts +64 -35
- package/dist/lib/lsp.js +208 -159
- package/dist/lib/node.d.ts +50 -18
- package/dist/lib/node.js +66 -27
- package/dist/lib/text.d.ts +8 -2
- package/dist/lib/text.js +10 -3
- package/dist/lib/title.d.ts +19 -10
- package/dist/lib/title.js +28 -22
- package/dist/mixin/attributesParent.d.ts +4 -4
- package/dist/mixin/attributesParent.js +0 -2
- package/dist/mixin/hidden.d.ts +0 -2
- package/dist/mixin/hidden.js +0 -2
- package/dist/parser/braces.js +52 -20
- package/dist/parser/commentAndExt.js +17 -4
- package/dist/parser/links.js +8 -7
- package/dist/parser/list.js +3 -1
- package/dist/parser/quotes.js +2 -1
- package/dist/parser/redirect.js +4 -1
- package/dist/src/arg.d.ts +4 -2
- package/dist/src/arg.js +8 -4
- package/dist/src/atom.d.ts +5 -1
- package/dist/src/atom.js +5 -1
- package/dist/src/attribute.d.ts +9 -3
- package/dist/src/attribute.js +9 -3
- package/dist/src/attributes.d.ts +12 -4
- package/dist/src/attributes.js +12 -4
- package/dist/src/converter.d.ts +3 -1
- package/dist/src/converter.js +8 -5
- package/dist/src/converterFlags.d.ts +13 -3
- package/dist/src/converterFlags.js +13 -3
- package/dist/src/converterRule.d.ts +3 -1
- package/dist/src/converterRule.js +3 -1
- package/dist/src/extLink.d.ts +2 -0
- package/dist/src/extLink.js +2 -0
- package/dist/src/gallery.d.ts +3 -1
- package/dist/src/gallery.js +7 -5
- package/dist/src/heading.d.ts +3 -1
- package/dist/src/heading.js +4 -2
- package/dist/src/hidden.d.ts +5 -1
- package/dist/src/hidden.js +5 -1
- package/dist/src/html.d.ts +6 -2
- package/dist/src/html.js +6 -2
- package/dist/src/imageParameter.d.ts +11 -3
- package/dist/src/imageParameter.js +12 -4
- package/dist/src/imagemap.d.ts +1 -1
- package/dist/src/imagemap.js +5 -4
- package/dist/src/imagemapLink.d.ts +2 -0
- package/dist/src/imagemapLink.js +2 -0
- package/dist/src/index.d.ts +5 -3
- package/dist/src/index.js +28 -18
- package/dist/src/link/base.d.ts +4 -2
- package/dist/src/link/base.js +12 -6
- package/dist/src/link/category.d.ts +2 -0
- package/dist/src/link/category.js +2 -0
- package/dist/src/link/file.d.ts +17 -7
- package/dist/src/link/file.js +28 -14
- package/dist/src/link/galleryImage.d.ts +5 -1
- package/dist/src/link/galleryImage.js +9 -5
- package/dist/src/link/index.d.ts +2 -0
- package/dist/src/link/index.js +2 -0
- package/dist/src/link/redirectTarget.d.ts +2 -1
- package/dist/src/link/redirectTarget.js +4 -2
- package/dist/src/magicLink.d.ts +8 -4
- package/dist/src/magicLink.js +16 -9
- package/dist/src/nested.d.ts +3 -1
- package/dist/src/nested.js +7 -4
- package/dist/src/nowiki/base.d.ts +3 -1
- package/dist/src/nowiki/base.js +3 -1
- package/dist/src/nowiki/comment.d.ts +5 -1
- package/dist/src/nowiki/comment.js +5 -1
- package/dist/src/nowiki/doubleUnderscore.d.ts +5 -1
- package/dist/src/nowiki/doubleUnderscore.js +5 -1
- package/dist/src/nowiki/index.d.ts +5 -1
- package/dist/src/nowiki/index.js +5 -1
- package/dist/src/nowiki/list.d.ts +5 -1
- package/dist/src/nowiki/list.js +5 -1
- package/dist/src/nowiki/noinclude.d.ts +5 -1
- package/dist/src/nowiki/noinclude.js +5 -1
- package/dist/src/nowiki/quote.d.ts +5 -1
- package/dist/src/nowiki/quote.js +5 -1
- package/dist/src/onlyinclude.d.ts +3 -1
- package/dist/src/onlyinclude.js +3 -1
- package/dist/src/paramTag/index.d.ts +1 -1
- package/dist/src/paramTag/index.js +1 -1
- package/dist/src/parameter.d.ts +3 -1
- package/dist/src/parameter.js +3 -1
- package/dist/src/pre.d.ts +1 -1
- package/dist/src/pre.js +1 -1
- package/dist/src/redirect.d.ts +2 -0
- package/dist/src/redirect.js +2 -0
- package/dist/src/syntax.d.ts +5 -1
- package/dist/src/syntax.js +5 -1
- package/dist/src/table/base.js +3 -1
- package/dist/src/table/index.d.ts +20 -15
- package/dist/src/table/index.js +22 -23
- package/dist/src/table/td.d.ts +9 -3
- package/dist/src/table/td.js +9 -3
- package/dist/src/table/tr.d.ts +3 -1
- package/dist/src/table/tr.js +4 -2
- package/dist/src/table/trBase.d.ts +9 -9
- package/dist/src/table/trBase.js +13 -18
- package/dist/src/tagPair/ext.d.ts +3 -1
- package/dist/src/tagPair/ext.js +3 -1
- package/dist/src/tagPair/include.d.ts +2 -0
- package/dist/src/tagPair/include.js +2 -0
- package/dist/src/tagPair/index.d.ts +6 -2
- package/dist/src/tagPair/index.js +6 -2
- package/dist/src/transclude.d.ts +34 -10
- package/dist/src/transclude.js +47 -17
- package/dist/util/debug.js +2 -16
- package/dist/util/string.js +2 -0
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/package.json +2 -2
package/dist/lib/lsp.js
CHANGED
|
@@ -170,18 +170,24 @@ const getSectionEnd = (section, lines, line) => {
|
|
|
170
170
|
/** VSCode-style language service */
|
|
171
171
|
class LanguageService {
|
|
172
172
|
#text;
|
|
173
|
+
#text2;
|
|
173
174
|
#running;
|
|
175
|
+
#running2;
|
|
174
176
|
#done;
|
|
177
|
+
#done2;
|
|
175
178
|
#config;
|
|
179
|
+
#config2;
|
|
176
180
|
#completionConfig;
|
|
177
|
-
#signature;
|
|
178
181
|
/** @private */
|
|
179
182
|
data;
|
|
180
183
|
/** @param uri 任务标识 */
|
|
181
184
|
constructor(uri) {
|
|
182
185
|
exports.tasks.set(uri, this);
|
|
183
186
|
/* NOT FOR BROWSER ONLY */
|
|
184
|
-
|
|
187
|
+
Object.defineProperty(this, 'data', {
|
|
188
|
+
value: require(path.join('..', '..', 'data', 'signatures')),
|
|
189
|
+
enumerable: false,
|
|
190
|
+
});
|
|
185
191
|
}
|
|
186
192
|
/** @implements */
|
|
187
193
|
destroy() {
|
|
@@ -191,7 +197,7 @@ class LanguageService {
|
|
|
191
197
|
* 提交解析任务
|
|
192
198
|
* @param text 源代码
|
|
193
199
|
* @description
|
|
194
|
-
* -
|
|
200
|
+
* - 总是更新`#text`以便`#parse`完成时可以判断是否需要重新解析
|
|
195
201
|
* - 如果已有进行中或已完成的解析,则返回该解析的结果
|
|
196
202
|
* - 否则开始新的解析
|
|
197
203
|
*/
|
|
@@ -207,48 +213,71 @@ class LanguageService {
|
|
|
207
213
|
/**
|
|
208
214
|
* 执行解析
|
|
209
215
|
* @description
|
|
210
|
-
* -
|
|
216
|
+
* - 完成后会检查`#text`是否已更新,如果是则重新解析
|
|
211
217
|
* - 总是返回最新的解析结果
|
|
212
218
|
*/
|
|
213
219
|
async #parse() {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
220
|
+
const config = index_1.default.getConfig();
|
|
221
|
+
this.#config = index_1.default.config;
|
|
222
|
+
const text = this.#text, root = await index_1.default.partialParse(text, () => this.#text, true, config);
|
|
223
|
+
if (this.#text === text && this.#config === index_1.default.config) {
|
|
224
|
+
this.#done = root;
|
|
225
|
+
this.#running = undefined;
|
|
226
|
+
return root;
|
|
227
|
+
}
|
|
228
|
+
/* istanbul ignore next */
|
|
229
|
+
this.#running = this.#parse();
|
|
230
|
+
/* istanbul ignore next */
|
|
231
|
+
return this.#running;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* 提交签名解析任务
|
|
235
|
+
* @param text 源代码
|
|
236
|
+
* @description
|
|
237
|
+
* - 总是更新`#text2`以便`#parseSignature`完成时可以判断是否需要重新解析
|
|
238
|
+
* - 如果已有进行中或已完成的解析,则返回该解析的结果
|
|
239
|
+
* - 否则开始新的解析
|
|
240
|
+
*/
|
|
241
|
+
async #queueSignature(text) {
|
|
242
|
+
text = (0, string_1.tidy)(text);
|
|
243
|
+
if (this.#text2 === text && this.#config2 === index_1.default.config && !this.#running2) {
|
|
244
|
+
return this.#done2;
|
|
245
|
+
}
|
|
246
|
+
this.#text2 = text;
|
|
247
|
+
this.#running2 ??= this.#parseSignature(); // 不要提交多个解析任务
|
|
248
|
+
return this.#running2;
|
|
231
249
|
}
|
|
232
250
|
/**
|
|
233
|
-
*
|
|
234
|
-
* @
|
|
251
|
+
* 执行签名解析
|
|
252
|
+
* @description
|
|
253
|
+
* - 完成后会检查`#text2`是否已更新,如果是则重新解析
|
|
254
|
+
* - 总是返回最新的解析结果
|
|
235
255
|
*/
|
|
236
|
-
#
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
256
|
+
async #parseSignature() {
|
|
257
|
+
const config = index_1.default.getConfig();
|
|
258
|
+
this.#config2 = index_1.default.config;
|
|
259
|
+
const text = this.#text2, root = await index_1.default.partialParse(text, () => this.#text2, true, config);
|
|
260
|
+
if (this.#text2 === text && this.#config2 === index_1.default.config) {
|
|
261
|
+
this.#done2 = root;
|
|
262
|
+
this.#running2 = undefined;
|
|
263
|
+
return root;
|
|
240
264
|
}
|
|
265
|
+
/* istanbul ignore next */
|
|
266
|
+
this.#running2 = this.#parseSignature();
|
|
267
|
+
/* istanbul ignore next */
|
|
268
|
+
return this.#running2;
|
|
241
269
|
}
|
|
242
270
|
/**
|
|
271
|
+
* Provide color decorators
|
|
272
|
+
*
|
|
243
273
|
* 提供颜色指示
|
|
244
|
-
* @param rgba 颜色解析函数
|
|
245
|
-
* @param text 源代码
|
|
246
|
-
* @param hsl 是否允许HSL颜色
|
|
274
|
+
* @param rgba color parser / 颜色解析函数
|
|
275
|
+
* @param text source Wikitext / 源代码
|
|
276
|
+
* @param hsl whether HSL colors are treated / 是否允许HSL颜色
|
|
247
277
|
*/
|
|
248
278
|
async provideDocumentColors(rgba, text, hsl = true) {
|
|
249
|
-
this.#checkSignature();
|
|
250
279
|
const root = await this.#queue(text);
|
|
251
|
-
return root.querySelectorAll('attr-value,parameter-value,arg-default')
|
|
280
|
+
return root.querySelectorAll('attr-value,parameter-value,arg-default').reverse()
|
|
252
281
|
.flatMap(({ type, childNodes }) => {
|
|
253
282
|
if (type !== 'attr-value' && !isPlain(childNodes)) {
|
|
254
283
|
return [];
|
|
@@ -275,10 +304,15 @@ class LanguageService {
|
|
|
275
304
|
});
|
|
276
305
|
});
|
|
277
306
|
}
|
|
278
|
-
/**
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
307
|
+
/**
|
|
308
|
+
* Provide color pickers
|
|
309
|
+
*
|
|
310
|
+
* 颜色选择器
|
|
311
|
+
* @param color color information / 颜色信息
|
|
312
|
+
*/
|
|
313
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
314
|
+
provideColorPresentations(color) {
|
|
315
|
+
const { color: { red, green, blue, alpha }, range } = color, newText = `#${(0, common_1.numToHex)(red)}${(0, common_1.numToHex)(green)}${(0, common_1.numToHex)(blue)}${alpha < 1 ? (0, common_1.numToHex)(alpha) : ''}`;
|
|
282
316
|
return [
|
|
283
317
|
{
|
|
284
318
|
label: newText,
|
|
@@ -323,12 +357,13 @@ class LanguageService {
|
|
|
323
357
|
return this.#completionConfig;
|
|
324
358
|
}
|
|
325
359
|
/**
|
|
360
|
+
* Provide auto-completion
|
|
361
|
+
*
|
|
326
362
|
* 提供自动补全
|
|
327
|
-
* @param text 源代码
|
|
363
|
+
* @param text source Wikitext / 源代码
|
|
328
364
|
* @param position 位置
|
|
329
365
|
*/
|
|
330
366
|
async provideCompletionItems(text, position) {
|
|
331
|
-
this.#checkSignature();
|
|
332
367
|
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) ?? '');
|
|
333
368
|
if (mt?.[1] !== undefined) { // tag
|
|
334
369
|
const closing = mt[1].startsWith('/');
|
|
@@ -382,7 +417,8 @@ class LanguageService {
|
|
|
382
417
|
return [
|
|
383
418
|
...getCompletion(params, 'Property', match, position)
|
|
384
419
|
.filter(({ label }) => !equal || !/[= ]$/u.test(label)),
|
|
385
|
-
...getCompletion(root.querySelectorAll('image-parameter#width')
|
|
420
|
+
...getCompletion(root.querySelectorAll('image-parameter#width')
|
|
421
|
+
.filter(token => token !== cur)
|
|
386
422
|
.map(width => width.text()), 'Unit', match, position),
|
|
387
423
|
];
|
|
388
424
|
}
|
|
@@ -408,20 +444,20 @@ class LanguageService {
|
|
|
408
444
|
}
|
|
409
445
|
else if (type === 'parameter-key' || type === 'parameter-value' && parentNode.anon) {
|
|
410
446
|
// parameter key
|
|
411
|
-
const transclusion = parentNode.parentNode;
|
|
412
|
-
if (
|
|
447
|
+
const transclusion = parentNode.parentNode, { type: t, name: n } = transclusion;
|
|
448
|
+
if (t === 'magic-word' && n !== 'invoke') {
|
|
413
449
|
return undefined;
|
|
414
450
|
}
|
|
415
|
-
const key = cur.toString().trimStart(), [module, func] =
|
|
451
|
+
const key = cur.toString().trimStart(), [module, func] = t === 'magic-word' ? transclusion.getModule() : [];
|
|
416
452
|
return key
|
|
417
453
|
? getCompletion(root.querySelectorAll('parameter').filter(token => {
|
|
418
454
|
if (token === parentNode
|
|
419
455
|
|| token.anon
|
|
420
|
-
|| token.parentNode.type !==
|
|
421
|
-
|| token.parentNode.name !==
|
|
456
|
+
|| token.parentNode.type !== t
|
|
457
|
+
|| token.parentNode.name !== n) {
|
|
422
458
|
return false;
|
|
423
459
|
}
|
|
424
|
-
else if (
|
|
460
|
+
else if (t === 'template') {
|
|
425
461
|
return true;
|
|
426
462
|
}
|
|
427
463
|
const [m, f] = token.parentNode.getModule();
|
|
@@ -432,13 +468,14 @@ class LanguageService {
|
|
|
432
468
|
return undefined;
|
|
433
469
|
}
|
|
434
470
|
/**
|
|
435
|
-
*
|
|
436
|
-
*
|
|
437
|
-
*
|
|
471
|
+
* Provide grammar check
|
|
472
|
+
*
|
|
473
|
+
* 提供语法检查
|
|
474
|
+
* @param text source Wikitext / 源代码
|
|
475
|
+
* @param warning whether to include warnings / 是否包含警告
|
|
438
476
|
*/
|
|
439
|
-
async provideDiagnostics(
|
|
440
|
-
this.#
|
|
441
|
-
const root = await this.#queue(wikitext), errors = root.lint();
|
|
477
|
+
async provideDiagnostics(text, warning = true) {
|
|
478
|
+
const root = await this.#queue(text), errors = root.lint();
|
|
442
479
|
return (warning ? errors : errors.filter(({ severity }) => severity === 'error'))
|
|
443
480
|
.map(({ startLine, startCol, endLine, endCol, severity, rule, message, fix, suggestions }) => ({
|
|
444
481
|
range: {
|
|
@@ -457,38 +494,42 @@ class LanguageService {
|
|
|
457
494
|
}));
|
|
458
495
|
}
|
|
459
496
|
/**
|
|
497
|
+
* Provide folding ranges
|
|
498
|
+
*
|
|
460
499
|
* 提供折叠范围
|
|
461
|
-
* @param text 源代码
|
|
500
|
+
* @param text source Wikitext / 源代码
|
|
462
501
|
*/
|
|
463
502
|
async provideFoldingRanges(text) {
|
|
464
|
-
this.#checkSignature();
|
|
465
503
|
const root = await this.#queue(text), { length } = root.getLines(), ranges = [], levels = new Array(6), tokens = root.querySelectorAll('heading-title,table,template,magic-word');
|
|
466
504
|
for (const token of [...tokens].reverse()) { // 提高 getBoundingClientRect 的性能
|
|
467
505
|
token.getRelativeIndex();
|
|
468
506
|
}
|
|
469
507
|
for (const token of tokens) {
|
|
470
|
-
const {
|
|
471
|
-
if (token.type === 'heading-title') {
|
|
472
|
-
const {
|
|
473
|
-
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
508
|
+
const { offsetHeight } = token;
|
|
509
|
+
if (token.type === 'heading-title' || offsetHeight > 2) {
|
|
510
|
+
const { top } = token.getBoundingClientRect();
|
|
511
|
+
if (token.type === 'heading-title') {
|
|
512
|
+
const { level } = token.parentNode;
|
|
513
|
+
for (let i = level - 1; i < 6; i++) {
|
|
514
|
+
const startLine = levels[i];
|
|
515
|
+
if (startLine !== undefined && startLine < top - 1) {
|
|
516
|
+
ranges.push({
|
|
517
|
+
startLine,
|
|
518
|
+
endLine: top - 1,
|
|
519
|
+
kind: 'region',
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
levels[i] = undefined;
|
|
481
523
|
}
|
|
482
|
-
levels[
|
|
524
|
+
levels[level - 1] = top + offsetHeight - 1; // 从标题的最后一行开始折叠
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
ranges.push({
|
|
528
|
+
startLine: top, // 从表格或模板的第一行开始折叠
|
|
529
|
+
endLine: top + offsetHeight - 2,
|
|
530
|
+
kind: 'region',
|
|
531
|
+
});
|
|
483
532
|
}
|
|
484
|
-
levels[level - 1] = top + height - 1; // 从标题的最后一行开始折叠
|
|
485
|
-
}
|
|
486
|
-
else if (height > 2) {
|
|
487
|
-
ranges.push({
|
|
488
|
-
startLine: top, // 从表格或模板的第一行开始折叠
|
|
489
|
-
endLine: top + height - 2,
|
|
490
|
-
kind: 'region',
|
|
491
|
-
});
|
|
492
533
|
}
|
|
493
534
|
}
|
|
494
535
|
for (const startLine of levels) {
|
|
@@ -503,16 +544,18 @@ class LanguageService {
|
|
|
503
544
|
return ranges;
|
|
504
545
|
}
|
|
505
546
|
/**
|
|
547
|
+
* Provide links
|
|
548
|
+
*
|
|
506
549
|
* 提供链接
|
|
507
|
-
* @param text 源代码
|
|
550
|
+
* @param text source Wikitext / 源代码
|
|
508
551
|
*/
|
|
509
552
|
async provideLinks(text) {
|
|
510
|
-
this.#checkSignature();
|
|
511
553
|
const { articlePath, protocol } = index_1.default.getConfig(), absolute = articlePath?.includes('//'), protocolRegex = new RegExp(`^(?:${protocol}|//)`, 'iu');
|
|
512
554
|
return (await this.#queue(text))
|
|
513
|
-
.querySelectorAll(`magic-link,ext-link-url,free-ext-link,attr-value,image-parameter#link${absolute ? ',link-target,template-name,invoke-module' : ''}`)
|
|
555
|
+
.querySelectorAll(`magic-link,ext-link-url,free-ext-link,attr-value,image-parameter#link${absolute ? ',link-target,template-name,invoke-module' : ''}`)
|
|
556
|
+
.reverse()
|
|
514
557
|
.map((token) => {
|
|
515
|
-
const { type, parentNode, firstChild, lastChild, childNodes } = token, { name, tag } = parentNode;
|
|
558
|
+
const { type, parentNode, firstChild, lastChild, childNodes, length } = token, { name, tag } = parentNode;
|
|
516
559
|
if (!(type !== 'attr-value'
|
|
517
560
|
|| name === 'src' && ['templatestyles', 'img'].includes(tag)
|
|
518
561
|
|| name === 'cite' && ['blockquote', 'del', 'ins', 'q'].includes(tag))
|
|
@@ -520,7 +563,9 @@ class LanguageService {
|
|
|
520
563
|
return false;
|
|
521
564
|
}
|
|
522
565
|
let target = childNodes.filter((node) => node.type === 'text')
|
|
523
|
-
.map(({ data }) => data)
|
|
566
|
+
.map(({ data }) => data)
|
|
567
|
+
.join('')
|
|
568
|
+
.trim();
|
|
524
569
|
if (!target) {
|
|
525
570
|
return false;
|
|
526
571
|
}
|
|
@@ -554,7 +599,8 @@ class LanguageService {
|
|
|
554
599
|
else if (type === 'invoke-module') {
|
|
555
600
|
ns = 828;
|
|
556
601
|
}
|
|
557
|
-
const title = index_1.default
|
|
602
|
+
const title = index_1.default
|
|
603
|
+
.normalizeTitle(target, ns, false, undefined, true);
|
|
558
604
|
/* istanbul ignore if */
|
|
559
605
|
if (!title.valid) {
|
|
560
606
|
return false;
|
|
@@ -566,7 +612,7 @@ class LanguageService {
|
|
|
566
612
|
}
|
|
567
613
|
target = new URL(target).href;
|
|
568
614
|
if (type === 'image-parameter') {
|
|
569
|
-
const { top, left, height, width } =
|
|
615
|
+
const rect = firstChild.getBoundingClientRect(), { top, left, height, width } = length === 1 ? rect : lastChild.getBoundingClientRect();
|
|
570
616
|
return {
|
|
571
617
|
range: {
|
|
572
618
|
start: { line: rect.top, character: rect.left },
|
|
@@ -580,15 +626,17 @@ class LanguageService {
|
|
|
580
626
|
catch {
|
|
581
627
|
return false;
|
|
582
628
|
}
|
|
583
|
-
})
|
|
629
|
+
})
|
|
630
|
+
.filter(Boolean);
|
|
584
631
|
}
|
|
585
632
|
/**
|
|
633
|
+
* Provide references
|
|
634
|
+
*
|
|
586
635
|
* 提供引用
|
|
587
|
-
* @param text 源代码
|
|
636
|
+
* @param text source Wikitext / 源代码
|
|
588
637
|
* @param position 位置
|
|
589
638
|
*/
|
|
590
639
|
async provideReferences(text, position) {
|
|
591
|
-
this.#checkSignature();
|
|
592
640
|
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')
|
|
593
641
|
? element.parentNode.parentNode
|
|
594
642
|
: element, { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
|
|
@@ -597,41 +645,41 @@ class LanguageService {
|
|
|
597
645
|
}
|
|
598
646
|
const name = getName(node), refs = root.querySelectorAll(type === 'heading-title' ? 'heading' : type).filter(token => type === 'attr-value'
|
|
599
647
|
? getRefName(token) === refName || getRefGroup(token) === refGroup
|
|
600
|
-
: getName(token) === name).map((token) => ({
|
|
648
|
+
: getName(token) === name).reverse().map((token) => ({
|
|
601
649
|
range: createNodeRange(token.type === 'parameter-key' ? token.parentNode : token),
|
|
602
650
|
}));
|
|
603
651
|
return refs.length === 0 ? undefined : refs;
|
|
604
652
|
}
|
|
605
653
|
/**
|
|
654
|
+
* Provide definitions
|
|
655
|
+
*
|
|
606
656
|
* 提供定义
|
|
607
|
-
* @param text 源代码
|
|
608
|
-
* @param
|
|
609
|
-
* @param pos.line 行号
|
|
610
|
-
* @param pos.character 列号
|
|
657
|
+
* @param text source Wikitext / 源代码
|
|
658
|
+
* @param position 位置
|
|
611
659
|
*/
|
|
612
|
-
async provideDefinition(text,
|
|
613
|
-
this.#
|
|
614
|
-
|
|
660
|
+
async provideDefinition(text, position) {
|
|
661
|
+
const root = await this.#queue(text), node = root.elementFromPoint(position.character, position.line), ext = node.is('ext') && node.name === 'ref'
|
|
662
|
+
? node
|
|
663
|
+
: node.closest('ext#ref'), refName = getRefTagAttr(ext, 'name');
|
|
615
664
|
if (!refName) {
|
|
616
665
|
return undefined;
|
|
617
666
|
}
|
|
618
667
|
const refGroup = getRefTagAttr(ext, 'group'), refs = root.querySelectorAll('ext#ref').filter(token => token.innerText
|
|
619
668
|
&& getRefTagAttr(token, 'name') === refName
|
|
620
|
-
&& getRefTagAttr(token, 'group') === refGroup).map(({ lastChild }) => ({
|
|
669
|
+
&& getRefTagAttr(token, 'group') === refGroup).reverse().map(({ lastChild }) => ({
|
|
621
670
|
range: createNodeRange(lastChild),
|
|
622
671
|
}));
|
|
623
672
|
return refs.length === 0 ? undefined : refs;
|
|
624
673
|
}
|
|
625
674
|
/**
|
|
675
|
+
* Provide locations for renaming
|
|
676
|
+
*
|
|
626
677
|
* 提供变量更名准备
|
|
627
|
-
* @param text 源代码
|
|
628
|
-
* @param
|
|
629
|
-
* @param pos.line 行号
|
|
630
|
-
* @param pos.character 列号
|
|
678
|
+
* @param text source Wikitext / 源代码
|
|
679
|
+
* @param position 位置
|
|
631
680
|
*/
|
|
632
|
-
async resolveRenameLocation(text,
|
|
633
|
-
this.#
|
|
634
|
-
const root = await this.#queue(text), node = root.elementFromPoint(character, line), { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
|
|
681
|
+
async resolveRenameLocation(text, position) {
|
|
682
|
+
const root = await this.#queue(text), node = root.elementFromPoint(position.character, position.line), { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
|
|
635
683
|
return !refName && !refGroup && (!renameTypes.has(type)
|
|
636
684
|
|| type === 'parameter-key' && /^[1-9]\d*$/u.test(node.parentNode.name)
|
|
637
685
|
|| type === 'link-target' && !['link', 'redirect-target'].includes(node.parentNode.type))
|
|
@@ -639,16 +687,15 @@ class LanguageService {
|
|
|
639
687
|
: createNodeRange(node);
|
|
640
688
|
}
|
|
641
689
|
/**
|
|
690
|
+
* Provide rename edits
|
|
691
|
+
*
|
|
642
692
|
* 变量更名
|
|
643
|
-
* @param text 源代码
|
|
644
|
-
* @param
|
|
645
|
-
* @param
|
|
646
|
-
* @param pos.character 列号
|
|
647
|
-
* @param newName 新名称
|
|
693
|
+
* @param text source Wikitext / 源代码
|
|
694
|
+
* @param position 位置
|
|
695
|
+
* @param newName new name / 新名称
|
|
648
696
|
*/
|
|
649
|
-
async provideRenameEdits(text,
|
|
650
|
-
this.#
|
|
651
|
-
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 => {
|
|
697
|
+
async provideRenameEdits(text, position, newName) {
|
|
698
|
+
const root = await this.#queue(text), node = root.elementFromPoint(position.character, position.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 => {
|
|
652
699
|
const { type: t } = token.parentNode;
|
|
653
700
|
if (type === 'link-target' && t !== 'link' && t !== 'redirect-target') {
|
|
654
701
|
return false;
|
|
@@ -663,7 +710,7 @@ class LanguageService {
|
|
|
663
710
|
? undefined
|
|
664
711
|
: {
|
|
665
712
|
changes: {
|
|
666
|
-
'': refs.map((ref) => ({
|
|
713
|
+
'': refs.reverse().map((ref) => ({
|
|
667
714
|
range: createNodeRange(ref),
|
|
668
715
|
newText: newName,
|
|
669
716
|
})),
|
|
@@ -675,11 +722,14 @@ class LanguageService {
|
|
|
675
722
|
* @param name 函数名
|
|
676
723
|
*/
|
|
677
724
|
#getParserFunction(name) {
|
|
678
|
-
return this.data.parserFunctions
|
|
725
|
+
return this.data.parserFunctions
|
|
726
|
+
.find(({ aliases }) => aliases.some(alias => alias.replace(/^#/u, '') === name));
|
|
679
727
|
}
|
|
680
728
|
/**
|
|
729
|
+
* Provide hover information
|
|
730
|
+
*
|
|
681
731
|
* 提供悬停信息
|
|
682
|
-
* @param text 源代码
|
|
732
|
+
* @param text source Wikitext / 源代码
|
|
683
733
|
* @param position 位置
|
|
684
734
|
*/
|
|
685
735
|
async provideHover(text, position) {
|
|
@@ -687,20 +737,17 @@ class LanguageService {
|
|
|
687
737
|
if (!this.data) {
|
|
688
738
|
return undefined;
|
|
689
739
|
}
|
|
690
|
-
this.#checkSignature();
|
|
691
740
|
const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, position), token = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, { type, parentNode, length, name } = token;
|
|
692
741
|
let info, f, range;
|
|
693
|
-
if (token.is('double-underscore')) {
|
|
694
|
-
if (offset === 0 && token.getBoundingClientRect().left > position.character) {
|
|
695
|
-
return undefined;
|
|
696
|
-
}
|
|
742
|
+
if (token.is('double-underscore') && offset > 0) {
|
|
697
743
|
info = this.data.behaviorSwitches.find(({ aliases }) => aliases.includes(token.innerText.toLowerCase()));
|
|
698
744
|
}
|
|
699
745
|
else if (type === 'magic-word-name') {
|
|
700
746
|
info = this.#getParserFunction(parentNode.name);
|
|
701
747
|
f = token.toString(true).trim();
|
|
702
748
|
}
|
|
703
|
-
else if (token.is('magic-word') && length === 1
|
|
749
|
+
else if (token.is('magic-word') && !token.modifier && length === 1
|
|
750
|
+
&& (offset > 0 || token.getBoundingClientRect().left === position.character)) {
|
|
704
751
|
info = this.#getParserFunction(name);
|
|
705
752
|
f = token.firstChild.toString(true).trim();
|
|
706
753
|
}
|
|
@@ -728,21 +775,18 @@ class LanguageService {
|
|
|
728
775
|
};
|
|
729
776
|
}
|
|
730
777
|
/**
|
|
778
|
+
* Provide signature help for magic words
|
|
779
|
+
*
|
|
731
780
|
* 提供魔术字帮助
|
|
732
|
-
* @param text 源代码
|
|
781
|
+
* @param text source Wikitext / 源代码
|
|
733
782
|
* @param position 位置
|
|
734
783
|
*/
|
|
735
784
|
async provideSignatureHelp(text, position) {
|
|
736
785
|
/* istanbul ignore next */
|
|
737
786
|
if (!this.data) {
|
|
738
787
|
return undefined;
|
|
739
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
740
788
|
}
|
|
741
|
-
|
|
742
|
-
throw new Error('This is a regular language server!');
|
|
743
|
-
}
|
|
744
|
-
this.#signature = true;
|
|
745
|
-
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)}}}`);
|
|
789
|
+
const { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], { lastChild } = await this.#queueSignature(`${curLine.slice(0, character + /^[^{}<]*/u.exec(curLine.slice(character))[0].length)}}}`);
|
|
746
790
|
if (!lastChild.is('magic-word') || lastChild.length === 1) {
|
|
747
791
|
return undefined;
|
|
748
792
|
}
|
|
@@ -779,16 +823,18 @@ class LanguageService {
|
|
|
779
823
|
};
|
|
780
824
|
}
|
|
781
825
|
/**
|
|
826
|
+
* Provide CodeLens
|
|
827
|
+
*
|
|
782
828
|
* 提供 CodeLens
|
|
783
|
-
* @param text 源代码
|
|
829
|
+
* @param text source Wikitext / 源代码
|
|
784
830
|
*/
|
|
785
831
|
async provideInlayHints(text) {
|
|
786
|
-
this.#checkSignature();
|
|
787
832
|
const hints = [], root = await this.#queue(text);
|
|
788
|
-
for (const
|
|
789
|
-
const { type, childNodes } =
|
|
833
|
+
for (const token of root.querySelectorAll('template,magic-word#invoke').reverse()) {
|
|
834
|
+
const { type, childNodes } = token;
|
|
790
835
|
hints.push(...childNodes.slice(type === 'template' ? 1 : 3).filter(({ anon }) => anon)
|
|
791
|
-
.reverse()
|
|
836
|
+
.reverse()
|
|
837
|
+
.map((parameter) => ({
|
|
792
838
|
position: positionAt(root, parameter.getAbsoluteIndex()),
|
|
793
839
|
label: `${parameter.name}=`,
|
|
794
840
|
kind: 2,
|
|
@@ -797,7 +843,12 @@ class LanguageService {
|
|
|
797
843
|
return hints;
|
|
798
844
|
}
|
|
799
845
|
/* NOT FOR BROWSER ONLY */
|
|
800
|
-
/**
|
|
846
|
+
/**
|
|
847
|
+
* Provide quick fixes
|
|
848
|
+
*
|
|
849
|
+
* 提供快速修复建议
|
|
850
|
+
* @param diagnostics grammar diagnostics / 语法诊断信息
|
|
851
|
+
*/
|
|
801
852
|
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
802
853
|
provideCodeAction(diagnostics) {
|
|
803
854
|
return diagnostics.flatMap(diagnostic => diagnostic.data.map((data) => ({
|
|
@@ -811,44 +862,42 @@ class LanguageService {
|
|
|
811
862
|
})));
|
|
812
863
|
}
|
|
813
864
|
/**
|
|
865
|
+
* Provide document sections
|
|
866
|
+
*
|
|
814
867
|
* 提供章节
|
|
815
|
-
* @param text 源代码
|
|
868
|
+
* @param text source Wikitext / 源代码
|
|
816
869
|
*/
|
|
817
870
|
async provideDocumentSymbols(text) {
|
|
818
|
-
this.#checkSignature();
|
|
819
871
|
const root = await this.#queue(text), lines = root.getLines(), { length } = lines, symbols = [], names = new Set(), sections = new Array(6), tokens = root.querySelectorAll('heading-title');
|
|
820
872
|
for (const token of [...tokens].reverse()) { // 提高 getBoundingClientRect 的性能
|
|
821
873
|
token.getRelativeIndex();
|
|
822
874
|
}
|
|
823
875
|
for (const token of tokens) {
|
|
824
|
-
const { top, height, left, width } = token.getBoundingClientRect();
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
else {
|
|
850
|
-
symbols.push(info);
|
|
851
|
-
}
|
|
876
|
+
const { top, height, left, width } = token.getBoundingClientRect(), { level } = token.parentNode;
|
|
877
|
+
for (let i = level - 1; i < 6; i++) {
|
|
878
|
+
getSectionEnd(sections[i], lines, top - 1);
|
|
879
|
+
sections[i] = undefined;
|
|
880
|
+
}
|
|
881
|
+
const section = token.text().trim() || ' ', name = names.has(section)
|
|
882
|
+
? new Array(names.size).fill('').map((_, i) => `${section.trim()}_${i + 2}`)
|
|
883
|
+
.find(s => !names.has(s))
|
|
884
|
+
: section, container = sections.slice(0, level - 1).reverse().find(Boolean), selectionRange = {
|
|
885
|
+
start: { line: top, character: left - level },
|
|
886
|
+
end: (0, lint_1.getEndPos)(top, left, height, width + level),
|
|
887
|
+
}, info = {
|
|
888
|
+
name,
|
|
889
|
+
kind: 15,
|
|
890
|
+
range: { start: selectionRange.start },
|
|
891
|
+
selectionRange,
|
|
892
|
+
};
|
|
893
|
+
names.add(name);
|
|
894
|
+
sections[level - 1] = info;
|
|
895
|
+
if (container) {
|
|
896
|
+
container.children ??= [];
|
|
897
|
+
container.children.push(info);
|
|
898
|
+
}
|
|
899
|
+
else {
|
|
900
|
+
symbols.push(info);
|
|
852
901
|
}
|
|
853
902
|
}
|
|
854
903
|
for (const section of sections) {
|