@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.
Files changed (67) hide show
  1. package/README.md +147 -87
  2. package/dist/bidi.d.ts +9 -8
  3. package/dist/bidi.js +38 -23
  4. package/dist/codemirror.d.ts +7 -0
  5. package/dist/codemirror.js +22 -9
  6. package/dist/color.d.ts +8 -5
  7. package/dist/color.js +5 -1
  8. package/dist/config.d.ts +1 -0
  9. package/dist/config.js +1 -0
  10. package/dist/constants.d.ts +3 -2
  11. package/dist/constants.js +3 -2
  12. package/dist/css.d.ts +5 -0
  13. package/dist/css.js +14 -6
  14. package/dist/escape.d.ts +22 -2
  15. package/dist/escape.js +44 -25
  16. package/dist/fold.d.ts +57 -5
  17. package/dist/fold.js +149 -58
  18. package/dist/hover.d.ts +16 -3
  19. package/dist/hover.js +84 -67
  20. package/dist/html.js +17 -12
  21. package/dist/indent.d.ts +7 -0
  22. package/dist/indent.js +7 -1
  23. package/dist/index.d.ts +54 -16
  24. package/dist/index.js +91 -38
  25. package/dist/inlay.d.ts +1 -1
  26. package/dist/inlay.js +26 -25
  27. package/dist/javascript.d.ts +10 -1
  28. package/dist/javascript.js +50 -2
  29. package/dist/keybindings.d.ts +1 -0
  30. package/dist/keybindings.js +1 -0
  31. package/dist/keymap.d.ts +11 -0
  32. package/dist/keymap.js +3 -4
  33. package/dist/linter.d.ts +31 -2
  34. package/dist/linter.js +10 -3
  35. package/dist/lintsource.d.ts +47 -3
  36. package/dist/lintsource.js +50 -11
  37. package/dist/lua.d.ts +0 -2
  38. package/dist/lua.js +27 -10
  39. package/dist/main.min.js +31 -29
  40. package/dist/matchBrackets.d.ts +16 -0
  41. package/dist/matchBrackets.js +16 -0
  42. package/dist/matchTag.d.ts +5 -2
  43. package/dist/matchTag.js +11 -7
  44. package/dist/mediawiki.d.ts +15 -2
  45. package/dist/mediawiki.js +59 -45
  46. package/dist/mw.min.js +33 -37
  47. package/dist/mwConfig.js +2 -2
  48. package/dist/openLinks.d.ts +12 -2
  49. package/dist/openLinks.js +64 -54
  50. package/dist/ref.d.ts +16 -2
  51. package/dist/ref.js +110 -95
  52. package/dist/signature.d.ts +7 -1
  53. package/dist/signature.js +53 -49
  54. package/dist/static.d.ts +4 -0
  55. package/dist/static.js +4 -0
  56. package/dist/statusBar.js +9 -8
  57. package/dist/theme.d.ts +1 -0
  58. package/dist/theme.js +8 -0
  59. package/dist/token.d.ts +29 -7
  60. package/dist/token.js +33 -18
  61. package/dist/util.d.ts +25 -2
  62. package/dist/util.js +47 -1
  63. package/dist/wiki.min.js +32 -36
  64. package/i18n/en.json +2 -2
  65. package/i18n/zh-hans.json +2 -2
  66. package/i18n/zh-hant.json +2 -2
  67. 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
- + state.sliceDoc(nextSibling.from, nextSibling.to)
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 <= end) {
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
- export const foldableLine = ({ state, viewport: { to: end }, viewportLineBlocks }, { from: f, to: t }) => {
241
- const tree = syntaxTree(state);
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 line = state.sliceDoc(from, to), bracket = /^\s*(?:(?::+\s*)?\{\||\|\})/u.exec(line)?.[0];
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
- const { name } = tree.resolve(from + bracket.length, -1);
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
- for (const { from } of viewportLineBlocks) {
268
- if (from > f && getLevel(from) <= level) {
269
- return t < from - 1 && { from: t, to: from - 1 };
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
- for (const { from, to } of viewportLineBlocks) {
276
- if (from > f) {
277
- const bracket = getTable(from, to);
278
- if (bracket === -1) {
279
- return t < from - 1 && { from: t, to: from - 1 };
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
- const buildMarkers = (view) => {
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 = [], anchor = traverse(state, tree, effects, tree.topNode.firstChild, Infinity, getAnchor(state), updateAll, refOnly);
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 mediaWikiFold = /* @__PURE__ */ (() => [
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(view) {
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 folded = findFold(view, line);
446
- if (folded) {
447
- view.dispatch({ effects: unfoldEffect.of(folded) });
541
+ const effects = unfoldCode(view, line);
542
+ if (effects) {
543
+ view.dispatch({ effects });
448
544
  return true;
449
545
  }
450
- const range = foldableLine(view, line);
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 { CodeMirror6 } from './codemirror.js';
3
- declare const _default: (cm: CodeMirror6) => Extension;
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
- export default (cm) => [
9
- hoverTooltip(async (view, pos, side) => {
10
- const { state } = view, { doc } = state;
11
- const { paramSuggest, tags } = cm.langConfig;
12
- let hover = await getLSP(view, false, cm.getWikiConfig, base.CDN)
13
- ?.provideHover(doc.toString(), indexToPos(doc, pos));
14
- if (!hover && paramSuggest && 'templatedata' in tags) {
15
- const node = ensureSyntaxTree(state, pos + Math.max(side, 0))?.resolve(pos, side);
16
- if (node?.name.includes(tokens.templateName)) {
17
- const result = await paramSuggest(state.sliceDoc(node.from, node.to), false), { description, length } = result;
18
- if (description || length > 0) {
19
- // eslint-disable-next-line require-atomic-updates
20
- hover = {
21
- contents: {
22
- kind: 'plaintext',
23
- value: (description ? `<p>${escHTML(description)}</p>` : '') + (length === 0
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
- pos,
38
- end: posToIndex(doc, end),
39
- above: true,
40
- create() {
41
- const { kind, value } = hover.contents;
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
- return null;
47
- }),
48
- EditorView.theme({
49
- [hoverSelector]: {
50
- padding: '2px 5px',
51
- width: 'max-content',
52
- maxWidth: '60vw',
53
- overflowY: 'auto',
54
- },
55
- [`${hoverSelector} *`]: {
56
- marginTop: '0!important',
57
- marginBottom: '0!important',
58
- },
59
- [`${hoverSelector}>div`]: {
60
- fontSize: '90%',
61
- lineHeight: 1.4,
62
- },
63
- [code]: {
64
- color: 'inherit',
65
- padding: '.1em .4em',
66
- borderRadius: '.4em',
67
- },
68
- }),
69
- EditorView.baseTheme({
70
- [`&light ${code}`]: {
71
- backgroundColor: '#e0e6eb',
72
- },
73
- [`&dark ${code}`]: {
74
- backgroundColor: bgDark,
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, syntaxHighlighting, defaultHighlightStyle, HighlightStyle } from '@codemirror/language';
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), lang = new LanguageSupport(htmlLanguage.configure({
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
- htmlLanguage.data.of({
18
- autocomplete: htmlCompletionSourceWith({
19
- extraTags: {
20
- noinclude: { globalAttrs: false },
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
- syntaxHighlighting(HighlightStyle.define(defaultHighlightStyle.specs, { themeType: 'light' })),
33
+ getLightHighlightStyle(),
29
34
  ]);
30
- Object.assign(lang, { nestedMWLanguage: language });
31
- return lang;
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
- const getLines = (text) => text.children?.flatMap(getLines) ?? text.text;
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)) {