@bhsd/codemirror-mediawiki 3.9.2 → 3.10.1
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/README.md +147 -87
- package/dist/bidi.d.ts +9 -8
- package/dist/bidi.js +38 -23
- package/dist/codemirror.d.ts +7 -0
- package/dist/codemirror.js +22 -9
- package/dist/color.d.ts +8 -5
- package/dist/color.js +5 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -0
- package/dist/constants.d.ts +3 -2
- package/dist/constants.js +3 -2
- package/dist/css.d.ts +5 -0
- package/dist/css.js +14 -6
- package/dist/escape.d.ts +22 -2
- package/dist/escape.js +44 -25
- package/dist/fold.d.ts +57 -5
- package/dist/fold.js +149 -58
- package/dist/hover.d.ts +16 -3
- package/dist/hover.js +84 -67
- package/dist/html.js +17 -12
- package/dist/indent.d.ts +7 -0
- package/dist/indent.js +7 -1
- package/dist/index.d.ts +54 -16
- package/dist/index.js +91 -38
- package/dist/inlay.d.ts +1 -1
- package/dist/inlay.js +26 -25
- package/dist/javascript.d.ts +10 -1
- package/dist/javascript.js +50 -2
- package/dist/keybindings.d.ts +1 -0
- package/dist/keybindings.js +1 -0
- package/dist/keymap.d.ts +11 -0
- package/dist/keymap.js +3 -4
- package/dist/linter.d.ts +31 -2
- package/dist/linter.js +10 -3
- package/dist/lintsource.d.ts +47 -3
- package/dist/lintsource.js +50 -11
- package/dist/lua.d.ts +0 -2
- package/dist/lua.js +27 -10
- package/dist/main.min.js +31 -29
- package/dist/matchBrackets.d.ts +16 -0
- package/dist/matchBrackets.js +16 -0
- package/dist/matchTag.d.ts +5 -2
- package/dist/matchTag.js +11 -7
- package/dist/mediawiki.d.ts +15 -2
- package/dist/mediawiki.js +59 -45
- package/dist/mw.min.js +33 -37
- package/dist/mwConfig.js +2 -2
- package/dist/openLinks.d.ts +12 -2
- package/dist/openLinks.js +64 -54
- package/dist/ref.d.ts +16 -2
- package/dist/ref.js +110 -95
- package/dist/signature.d.ts +7 -1
- package/dist/signature.js +53 -49
- package/dist/static.d.ts +4 -0
- package/dist/static.js +4 -0
- package/dist/statusBar.js +9 -8
- package/dist/theme.d.ts +1 -0
- package/dist/theme.js +8 -0
- package/dist/token.d.ts +29 -7
- package/dist/token.js +33 -18
- package/dist/util.d.ts +25 -2
- package/dist/util.js +47 -1
- package/dist/wiki.min.js +32 -36
- package/i18n/en.json +2 -2
- package/i18n/zh-hans.json +2 -2
- package/i18n/zh-hant.json +2 -2
- package/package.json +15 -13
package/dist/fold.js
CHANGED
|
@@ -6,9 +6,9 @@ import elt from 'crelt';
|
|
|
6
6
|
import { tokens } from './config.js';
|
|
7
7
|
import { bgDark } from './constants.js';
|
|
8
8
|
import { matchTag, getTag } from './matchTag.js';
|
|
9
|
-
import { braceStackUpdate } from './util.js';
|
|
9
|
+
import { braceStackUpdate, sliceDoc } from './util.js';
|
|
10
10
|
const getExtRegex = /* @__PURE__ */ getRegex(tag => new RegExp(`mw-tag-${tag}(?![a-z])`, 'u'));
|
|
11
|
-
const updateSelection = (pos, { to }) => Math.max(pos, to), updateAll = (pos, { from, to }) => from <= pos && to > pos ? to : pos;
|
|
11
|
+
export const updateSelection = (pos, { to }) => Math.max(pos, to), updateAll = (pos, { from, to }) => from <= pos && to > pos ? to : pos;
|
|
12
12
|
/**
|
|
13
13
|
* Check if a SyntaxNode is among the specified components
|
|
14
14
|
* @param keys The keys of the tokens to check
|
|
@@ -45,6 +45,7 @@ const refNames = new Set(['ref', 'references']);
|
|
|
45
45
|
* @param posOrNode 字符位置或语法树节点
|
|
46
46
|
* @param tree 语法树
|
|
47
47
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
48
|
+
* @test
|
|
48
49
|
*/
|
|
49
50
|
export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
50
51
|
if (typeof posOrNode === 'number') {
|
|
@@ -98,7 +99,7 @@ export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
|
98
99
|
if (stack <= 0) {
|
|
99
100
|
// The closing bracket of the current template
|
|
100
101
|
to = nextSibling.from
|
|
101
|
-
+
|
|
102
|
+
+ sliceDoc(state, nextSibling)
|
|
102
103
|
.split('}}').slice(0, stack - 1).join('}}').length;
|
|
103
104
|
break;
|
|
104
105
|
}
|
|
@@ -200,9 +201,12 @@ const getAnchor = (state) => Math.max(...state.selection.ranges.map(({ to }) =>
|
|
|
200
201
|
* @param anchor 光标位置
|
|
201
202
|
* @param update 更新光标位置
|
|
202
203
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
204
|
+
* @test
|
|
203
205
|
*/
|
|
204
|
-
const traverse = (state, tree, effects, node, end, anchor, update, refOnly) => {
|
|
205
|
-
while (node && node.from
|
|
206
|
+
export const traverse = (state, tree, effects, node, end, anchor, update, refOnly) => {
|
|
207
|
+
while (node && (node.from < end
|
|
208
|
+
|| node.from === end
|
|
209
|
+
&& !(isTemplateBracket(node) && sliceDoc(state, node).startsWith('}}')))) {
|
|
206
210
|
const range = foldable(state, node, tree, refOnly);
|
|
207
211
|
if (range) {
|
|
208
212
|
effects.push(foldEffect.of(range));
|
|
@@ -237,8 +241,13 @@ const findFold = ({ state }, line) => {
|
|
|
237
241
|
});
|
|
238
242
|
return found;
|
|
239
243
|
};
|
|
240
|
-
|
|
241
|
-
|
|
244
|
+
/**
|
|
245
|
+
* 寻找可折叠的行范围
|
|
246
|
+
* @ignore
|
|
247
|
+
* @test
|
|
248
|
+
*/
|
|
249
|
+
export const foldableLine = ({ state, viewportLineBlocks }, { from: f, to: t }) => {
|
|
250
|
+
const tree = syntaxTree(state), { doc } = state, { length } = viewportLineBlocks;
|
|
242
251
|
/**
|
|
243
252
|
* 获取标题层级
|
|
244
253
|
* @param pos 行首位置
|
|
@@ -253,40 +262,64 @@ export const foldableLine = ({ state, viewport: { to: end }, viewportLineBlocks
|
|
|
253
262
|
* @param to 行尾位置
|
|
254
263
|
*/
|
|
255
264
|
getTable = (from, to) => {
|
|
256
|
-
const
|
|
265
|
+
const node = tree.resolve(from, 1), { nextSibling } = node, bracket = node.name.includes(tokens.tableBracket)
|
|
266
|
+
? node
|
|
267
|
+
: node.to < to && nextSibling?.name.includes(tokens.tableBracket) && nextSibling;
|
|
257
268
|
if (bracket) {
|
|
258
|
-
|
|
259
|
-
if (name.includes(tokens.tableBracket)) {
|
|
260
|
-
return bracket.endsWith('|}') ? -1 : 1;
|
|
261
|
-
}
|
|
269
|
+
return /\|\}$|\{\{\s*!(?:\s*\}|\)\s*)\}\}$/u.test(sliceDoc(state, bracket)) ? -1 : 1;
|
|
262
270
|
}
|
|
263
271
|
return 0;
|
|
272
|
+
},
|
|
273
|
+
/**
|
|
274
|
+
* 逐行检查是否是折叠终点
|
|
275
|
+
* @param checkLine 检查函数
|
|
276
|
+
* @returns 折叠范围或是否继续查找
|
|
277
|
+
*/
|
|
278
|
+
loop = (checkLine) => {
|
|
279
|
+
let i = 0;
|
|
280
|
+
while (i <= doc.lines) {
|
|
281
|
+
const { from, to } = i < length ? viewportLineBlocks[i] : doc.line(i);
|
|
282
|
+
if (from >= tree.topNode.to) {
|
|
283
|
+
return from === doc.length;
|
|
284
|
+
}
|
|
285
|
+
else if (from > f) {
|
|
286
|
+
/** 折叠范围或是否继续查找 */
|
|
287
|
+
const result = checkLine(from, to);
|
|
288
|
+
if (result !== true) {
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
i++;
|
|
293
|
+
if (i === length) {
|
|
294
|
+
i = doc.lineAt(to).number + 1;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return true;
|
|
264
298
|
};
|
|
265
299
|
const level = getLevel(f);
|
|
266
300
|
if (level < 7) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return end === state.doc.length && end > t && { from: t, to: end };
|
|
301
|
+
const checkLine = from => getLevel(from) > level || t < from - 1 && { from: t, to: from - 1 };
|
|
302
|
+
const /** 折叠范围或是否继续查找 */ result = loop(checkLine);
|
|
303
|
+
return result === true
|
|
304
|
+
? t < doc.length && { from: t, to: doc.length }
|
|
305
|
+
: result;
|
|
273
306
|
}
|
|
274
307
|
else if (getTable(f, t) === 1) {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
else if (bracket === 1 || getLevel(from) < 7) {
|
|
282
|
-
break;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
308
|
+
const checkLine = (from, to) => {
|
|
309
|
+
const bracket = getTable(from, to);
|
|
310
|
+
return bracket === -1 ? t < from - 1 && { from: t, to: from - 1 } : bracket !== 1 && getLevel(from) === 7;
|
|
311
|
+
};
|
|
312
|
+
const /** 折叠范围或是否继续查找 */ result = loop(checkLine);
|
|
313
|
+
return typeof result === 'object' && result;
|
|
286
314
|
}
|
|
287
315
|
return false;
|
|
288
316
|
};
|
|
289
|
-
|
|
317
|
+
/**
|
|
318
|
+
* 生成行号旁的折叠标记
|
|
319
|
+
* @param view
|
|
320
|
+
* @test
|
|
321
|
+
*/
|
|
322
|
+
export const buildMarkers = (view) => {
|
|
290
323
|
const builder = new RangeSetBuilder();
|
|
291
324
|
for (const line of view.viewportLineBlocks) {
|
|
292
325
|
let mark;
|
|
@@ -320,9 +353,21 @@ const defaultFoldExtension = /* @__PURE__ */ (() => [foldGutter(), keymap.of(fol
|
|
|
320
353
|
/**
|
|
321
354
|
* 生成折叠命令
|
|
322
355
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
356
|
+
* @test
|
|
323
357
|
*/
|
|
324
|
-
const foldCommand = (refOnly) => view => {
|
|
325
|
-
const { state } = view, tree = ensureSyntaxTree(state, state.doc.length, 1e3) ?? syntaxTree(state), effects = []
|
|
358
|
+
export const foldCommand = (refOnly) => view => {
|
|
359
|
+
const { state } = view, tree = ensureSyntaxTree(state, state.doc.length, 1e3) ?? syntaxTree(state), effects = [];
|
|
360
|
+
let anchor = traverse(state, tree, effects, tree.topNode.firstChild, Infinity, getAnchor(state), updateAll, refOnly);
|
|
361
|
+
if (!refOnly) {
|
|
362
|
+
for (let pos = 0; pos < state.doc.length;) {
|
|
363
|
+
const line = view.lineBlockAt(pos), range = foldableLine(view, line);
|
|
364
|
+
if (range) {
|
|
365
|
+
effects.push(foldEffect.of(range));
|
|
366
|
+
anchor = updateAll(anchor, range);
|
|
367
|
+
}
|
|
368
|
+
pos = (range ? view.lineBlockAt(range.to) : line).to + 1;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
326
371
|
return execute(view, effects, anchor);
|
|
327
372
|
};
|
|
328
373
|
export const foldRef = /* @__PURE__ */ foldCommand(true);
|
|
@@ -340,6 +385,62 @@ export const unfoldRef = (view) => {
|
|
|
340
385
|
}
|
|
341
386
|
return false;
|
|
342
387
|
};
|
|
388
|
+
/**
|
|
389
|
+
* 获取所有光标所在的行
|
|
390
|
+
* @param view
|
|
391
|
+
* @test
|
|
392
|
+
*/
|
|
393
|
+
export const selectedLines = (view) => {
|
|
394
|
+
const lines = [];
|
|
395
|
+
for (const { head } of view.state.selection.ranges) {
|
|
396
|
+
if (lines.some(({ from, to }) => from <= head && to >= head)) {
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
lines.push(view.lineBlockAt(head));
|
|
400
|
+
}
|
|
401
|
+
return lines;
|
|
402
|
+
};
|
|
403
|
+
const foldCode = (view, line) => {
|
|
404
|
+
const range = foldableLine(view, line);
|
|
405
|
+
if (range) {
|
|
406
|
+
view.dispatch({ effects: foldEffect.of(range) });
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
return false;
|
|
410
|
+
};
|
|
411
|
+
const unfoldCode = (view, line) => {
|
|
412
|
+
const folded = findFold(view, line);
|
|
413
|
+
return folded && unfoldEffect.of(folded);
|
|
414
|
+
};
|
|
415
|
+
/**
|
|
416
|
+
* Fold the template at the selection/cursor
|
|
417
|
+
* @param view
|
|
418
|
+
* @test
|
|
419
|
+
*/
|
|
420
|
+
export const foldAt = view => {
|
|
421
|
+
const { state } = view, tree = syntaxTree(state), effects = [];
|
|
422
|
+
let anchor = getAnchor(state);
|
|
423
|
+
for (const { from, to, empty } of state.selection.ranges) {
|
|
424
|
+
let node;
|
|
425
|
+
if (empty) {
|
|
426
|
+
// No selection, try both sides of the cursor position
|
|
427
|
+
node = tree.resolve(from, -1);
|
|
428
|
+
}
|
|
429
|
+
if (!node || node.name === 'Document') {
|
|
430
|
+
node = tree.resolve(from, 1);
|
|
431
|
+
}
|
|
432
|
+
anchor = traverse(state, tree, effects, node, to, anchor, updateSelection);
|
|
433
|
+
}
|
|
434
|
+
if (effects.length > 0) {
|
|
435
|
+
return execute(view, effects, anchor);
|
|
436
|
+
}
|
|
437
|
+
for (const line of selectedLines(view)) {
|
|
438
|
+
if (foldCode(view, line)) {
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return false;
|
|
443
|
+
};
|
|
343
444
|
export default ((e = defaultFoldExtension) => [
|
|
344
445
|
e,
|
|
345
446
|
EditorView.theme({
|
|
@@ -348,7 +449,7 @@ export default ((e = defaultFoldExtension) => [
|
|
|
348
449
|
},
|
|
349
450
|
}),
|
|
350
451
|
]);
|
|
351
|
-
export const
|
|
452
|
+
export const mediawikiFold = /* @__PURE__ */ (() => [
|
|
352
453
|
codeFolding({
|
|
353
454
|
placeholderDOM(view) {
|
|
354
455
|
const element = elt('span', { 'aria-label': 'folded code', title: view.state.phrase('unfold'), class: 'cm-foldPlaceholder' }, '…');
|
|
@@ -382,22 +483,7 @@ export const mediaWikiFold = /* @__PURE__ */ (() => [
|
|
|
382
483
|
// Fold the template at the selection/cursor
|
|
383
484
|
key: 'Ctrl-Shift-[',
|
|
384
485
|
mac: 'Cmd-Alt-[',
|
|
385
|
-
run
|
|
386
|
-
const { state } = view, tree = syntaxTree(state), effects = [];
|
|
387
|
-
let anchor = getAnchor(state);
|
|
388
|
-
for (const { from, to, empty } of state.selection.ranges) {
|
|
389
|
-
let node;
|
|
390
|
-
if (empty) {
|
|
391
|
-
// No selection, try both sides of the cursor position
|
|
392
|
-
node = tree.resolve(from, -1);
|
|
393
|
-
}
|
|
394
|
-
if (!node || node.name === 'Document') {
|
|
395
|
-
node = tree.resolve(from, 1);
|
|
396
|
-
}
|
|
397
|
-
anchor = traverse(state, tree, effects, node, to, anchor, updateSelection);
|
|
398
|
-
}
|
|
399
|
-
return execute(view, effects, anchor);
|
|
400
|
-
},
|
|
486
|
+
run: foldAt,
|
|
401
487
|
},
|
|
402
488
|
{
|
|
403
489
|
// Fold all templates in the document
|
|
@@ -426,6 +512,16 @@ export const mediaWikiFold = /* @__PURE__ */ (() => [
|
|
|
426
512
|
view.dispatch({ effects, selection });
|
|
427
513
|
return true;
|
|
428
514
|
}
|
|
515
|
+
for (const line of selectedLines(view)) {
|
|
516
|
+
const effect = unfoldCode(view, line);
|
|
517
|
+
if (effect) {
|
|
518
|
+
effects.push(effect);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (effects.length > 0) {
|
|
522
|
+
view.dispatch({ effects });
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
429
525
|
return false;
|
|
430
526
|
},
|
|
431
527
|
},
|
|
@@ -442,17 +538,12 @@ export const mediaWikiFold = /* @__PURE__ */ (() => [
|
|
|
442
538
|
},
|
|
443
539
|
domEventHandlers: {
|
|
444
540
|
click(view, line) {
|
|
445
|
-
const
|
|
446
|
-
if (
|
|
447
|
-
view.dispatch({ effects
|
|
541
|
+
const effects = unfoldCode(view, line);
|
|
542
|
+
if (effects) {
|
|
543
|
+
view.dispatch({ effects });
|
|
448
544
|
return true;
|
|
449
545
|
}
|
|
450
|
-
|
|
451
|
-
if (range) {
|
|
452
|
-
view.dispatch({ effects: foldEffect.of(range) });
|
|
453
|
-
return true;
|
|
454
|
-
}
|
|
455
|
-
return false;
|
|
546
|
+
return foldCode(view, line);
|
|
456
547
|
},
|
|
457
548
|
},
|
|
458
549
|
}),
|
package/dist/hover.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import type { Extension } from '@codemirror/state';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
1
|
+
import type { Extension, EditorState } from '@codemirror/state';
|
|
2
|
+
import type { Hover } from 'vscode-languageserver-types';
|
|
3
|
+
import type { CodeMirror6 } from './codemirror';
|
|
4
|
+
import type { CompletionSectionName, ApiSuggest } from './token';
|
|
5
|
+
/**
|
|
6
|
+
* @ignore
|
|
7
|
+
* @test
|
|
8
|
+
*/
|
|
9
|
+
export declare const getDoc: (section: CompletionSectionName, info?: string) => string;
|
|
10
|
+
/**
|
|
11
|
+
* 从TemplateData API获取hover信息
|
|
12
|
+
* @ignore
|
|
13
|
+
* @test
|
|
14
|
+
*/
|
|
15
|
+
export declare const getHoverFromApi: (state: EditorState, pos: number, side: 1 | -1, paramSuggest: ApiSuggest, templatedata?: boolean) => Promise<Hover | undefined>;
|
|
16
|
+
declare const _default: (articlePath?: string, templatedata?: boolean) => (cm: CodeMirror6) => Extension;
|
|
4
17
|
export default _default;
|
package/dist/hover.js
CHANGED
|
@@ -3,75 +3,92 @@ import { ensureSyntaxTree } from '@codemirror/language';
|
|
|
3
3
|
import { getLSP, loadScript, } from '@bhsd/browser';
|
|
4
4
|
import { tokens } from './config.js';
|
|
5
5
|
import { base, hoverSelector, bgDark } from './constants.js';
|
|
6
|
-
import { indexToPos, posToIndex, createTooltipView, escHTML, } from './util.js';
|
|
6
|
+
import { indexToPos, posToIndex, createTooltipView, toConfigGetter, escHTML, sliceDoc, findTemplateName, } from './util.js';
|
|
7
7
|
const code = `${hoverSelector} code`;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
? ''
|
|
25
|
-
: `<ul>${result.map(([key, details]) => `<li><code>${escHTML(key)}</code>${details ? ` — ${escHTML(details)}` : ''}</li>`).join('')}</ul>`),
|
|
26
|
-
},
|
|
27
|
-
range: { start: indexToPos(doc, node.from), end: indexToPos(doc, node.to) },
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
if (hover) {
|
|
33
|
-
const { CDN = '' } = base;
|
|
34
|
-
await loadScript(`${CDN}${CDN && '/'}npm/marked/lib/marked.umd.js`, 'marked', true);
|
|
35
|
-
const { end } = hover.range;
|
|
8
|
+
/**
|
|
9
|
+
* @ignore
|
|
10
|
+
* @test
|
|
11
|
+
*/
|
|
12
|
+
export const getDoc = (section, info = '') => escHTML(info)
|
|
13
|
+
+ (section === 'Optional' ? '' : `<br><b><i>@${section.toLowerCase()}</i></b>`);
|
|
14
|
+
/**
|
|
15
|
+
* 从TemplateData API获取hover信息
|
|
16
|
+
* @ignore
|
|
17
|
+
* @test
|
|
18
|
+
*/
|
|
19
|
+
export const getHoverFromApi = async (state, pos, side, paramSuggest, templatedata) => {
|
|
20
|
+
const node = ensureSyntaxTree(state, pos + Math.max(side, 0))?.resolve(pos, side), { doc } = state;
|
|
21
|
+
if (node?.name.includes(tokens.templateName)) {
|
|
22
|
+
const result = await paramSuggest(sliceDoc(state, node), templatedata), { description, length } = result;
|
|
23
|
+
if (description || length > 0) {
|
|
36
24
|
return {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return createTooltipView(view, kind === 'plaintext' ? value : marked.parse(value));
|
|
25
|
+
contents: {
|
|
26
|
+
kind: 'plaintext',
|
|
27
|
+
value: (description ? `<p>${escHTML(description)}</p>` : '') + (length === 0
|
|
28
|
+
? ''
|
|
29
|
+
: `<ul>${result.map(([keys, , info, section]) => `<li>${keys.map(key => `<code>${escHTML(key)}</code>`).join('/')}${info && ' - '}${getDoc(section, info)}</li>`).join('')}</ul>`),
|
|
43
30
|
},
|
|
31
|
+
range: { start: indexToPos(doc, node.from), end: indexToPos(doc, node.to) },
|
|
44
32
|
};
|
|
45
33
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
34
|
+
}
|
|
35
|
+
else if (node?.name.includes(tokens.templateArgumentName)) {
|
|
36
|
+
const name = findTemplateName(state, node);
|
|
37
|
+
if (name) {
|
|
38
|
+
const result = await paramSuggest(name, templatedata), param = sliceDoc(state, node).trim().slice(0, -1).trim(), [, , info, section] = result.find(([keys]) => keys.includes(param)) ?? [];
|
|
39
|
+
if (info || section && section !== 'Optional') {
|
|
40
|
+
return {
|
|
41
|
+
contents: {
|
|
42
|
+
kind: 'plaintext',
|
|
43
|
+
value: getDoc(section, info).replace(/^<br>/u, ''),
|
|
44
|
+
},
|
|
45
|
+
range: { start: indexToPos(doc, node.from), end: indexToPos(doc, node.to) },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
};
|
|
52
|
+
export default (articlePath, templatedata) => (cm) => {
|
|
53
|
+
return [
|
|
54
|
+
hoverTooltip(async (view, pos, side) => {
|
|
55
|
+
const { state } = view, { doc } = state;
|
|
56
|
+
const { paramSuggest, tags } = cm.langConfig;
|
|
57
|
+
let hover = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), base.CDN)?.provideHover(doc.toString(), indexToPos(doc, pos));
|
|
58
|
+
if (!hover && paramSuggest && 'templatedata' in tags) {
|
|
59
|
+
// eslint-disable-next-line require-atomic-updates
|
|
60
|
+
hover = await getHoverFromApi(state, pos, side, paramSuggest, templatedata);
|
|
61
|
+
}
|
|
62
|
+
if (hover) {
|
|
63
|
+
const { CDN = '' } = base;
|
|
64
|
+
await loadScript(`${CDN}${CDN && '/'}npm/marked/lib/marked.umd.js`, 'marked', true);
|
|
65
|
+
const { end } = hover.range;
|
|
66
|
+
return {
|
|
67
|
+
pos,
|
|
68
|
+
end: posToIndex(doc, end),
|
|
69
|
+
above: true,
|
|
70
|
+
create() {
|
|
71
|
+
const { kind, value } = hover.contents;
|
|
72
|
+
return createTooltipView(view, kind === 'plaintext' ? value : marked.parse(value));
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}),
|
|
78
|
+
EditorView.theme({
|
|
79
|
+
[code]: {
|
|
80
|
+
color: 'inherit',
|
|
81
|
+
padding: '.1em .4em',
|
|
82
|
+
borderRadius: '.4em',
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
EditorView.baseTheme({
|
|
86
|
+
[`&light ${code}`]: {
|
|
87
|
+
backgroundColor: '#e0e6eb',
|
|
88
|
+
},
|
|
89
|
+
[`&dark ${code}`]: {
|
|
90
|
+
backgroundColor: bgDark,
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
];
|
|
94
|
+
};
|
package/dist/html.js
CHANGED
|
@@ -2,31 +2,36 @@ import { configureNesting } from '@lezer/html';
|
|
|
2
2
|
import { htmlLanguage, htmlCompletionSourceWith } from '@codemirror/lang-html';
|
|
3
3
|
import { javascript, javascriptLanguage } from '@codemirror/lang-javascript';
|
|
4
4
|
import { cssLanguage } from '@codemirror/lang-css';
|
|
5
|
-
import { LanguageSupport
|
|
5
|
+
import { LanguageSupport } from '@codemirror/language';
|
|
6
6
|
import { cssCompletion } from './css.js';
|
|
7
7
|
import { jsCompletion } from './javascript.js';
|
|
8
8
|
import { mediawikiBase } from './mediawiki.js';
|
|
9
|
+
import { getLightHighlightStyle } from './theme.js';
|
|
9
10
|
export default (config) => {
|
|
10
|
-
const { language, support } = mediawikiBase(config),
|
|
11
|
+
const { language, support } = mediawikiBase(config),
|
|
12
|
+
/** @test */
|
|
13
|
+
lang = htmlLanguage.configure({
|
|
11
14
|
wrap: configureNesting([
|
|
12
15
|
{ tag: 'script', parser: javascriptLanguage.parser },
|
|
13
16
|
{ tag: 'style', parser: cssLanguage.parser },
|
|
14
17
|
{ tag: 'noinclude', parser: language.parser },
|
|
15
18
|
], [{ name: 'style', parser: cssLanguage.parser.configure({ top: 'Styles' }) }]),
|
|
16
|
-
}),
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
},
|
|
22
|
-
}
|
|
19
|
+
}),
|
|
20
|
+
/** @test */
|
|
21
|
+
autocomplete = htmlLanguage.data.of({
|
|
22
|
+
autocomplete: htmlCompletionSourceWith({
|
|
23
|
+
extraTags: {
|
|
24
|
+
noinclude: { globalAttrs: false },
|
|
25
|
+
},
|
|
23
26
|
}),
|
|
27
|
+
}), langSupport = new LanguageSupport(lang, [
|
|
28
|
+
autocomplete,
|
|
24
29
|
javascript().support,
|
|
25
30
|
jsCompletion,
|
|
26
31
|
cssCompletion(),
|
|
27
32
|
support,
|
|
28
|
-
|
|
33
|
+
getLightHighlightStyle(),
|
|
29
34
|
]);
|
|
30
|
-
Object.assign(
|
|
31
|
-
return
|
|
35
|
+
Object.assign(langSupport, { nestedMWLanguage: language });
|
|
36
|
+
return langSupport;
|
|
32
37
|
};
|
package/dist/indent.d.ts
CHANGED
|
@@ -3,10 +3,17 @@ export interface Text extends TextBase {
|
|
|
3
3
|
children: readonly Text[] | null;
|
|
4
4
|
text?: string[];
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* 获取逐行文本内容
|
|
8
|
+
* @param text
|
|
9
|
+
* @test
|
|
10
|
+
*/
|
|
11
|
+
export declare const getLines: (text: Text) => string[];
|
|
6
12
|
/**
|
|
7
13
|
* 检测文本的缩进方式
|
|
8
14
|
* @param text 文本内容
|
|
9
15
|
* @param defaultIndent 默认缩进方式
|
|
10
16
|
* @param lang 语言
|
|
17
|
+
* @test
|
|
11
18
|
*/
|
|
12
19
|
export declare const detectIndent: (text: string | Text, defaultIndent: string, lang: string) => string;
|
package/dist/indent.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { noDetectionLangs } from './constants.js';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* 获取逐行文本内容
|
|
4
|
+
* @param text
|
|
5
|
+
* @test
|
|
6
|
+
*/
|
|
7
|
+
export const getLines = (text) => text.children?.flatMap(getLines) ?? text.text;
|
|
3
8
|
/**
|
|
4
9
|
* 检测文本的缩进方式
|
|
5
10
|
* @param text 文本内容
|
|
6
11
|
* @param defaultIndent 默认缩进方式
|
|
7
12
|
* @param lang 语言
|
|
13
|
+
* @test
|
|
8
14
|
*/
|
|
9
15
|
export const detectIndent = (text, defaultIndent, lang) => {
|
|
10
16
|
if (noDetectionLangs.has(lang)) {
|