@bhsd/codemirror-mediawiki 3.12.0 → 3.12.2

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/keymap.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { EditorSelection } from '@codemirror/state';
2
+ import { syntaxTree } from '@codemirror/language';
2
3
  import { keybindings, encapsulateLines } from './keybindings.js';
4
+ const reKartographer = /(?:^|_)mw-tag-map(?:link|frame)(?:$|_)/u;
3
5
  /**
4
6
  * 生成keymap
5
7
  * @param opt 快捷键设置
@@ -9,11 +11,24 @@ import { keybindings, encapsulateLines } from './keybindings.js';
9
11
  * @param opt.splitlines 是否分行
10
12
  * @test
11
13
  */
12
- export const getKeymap = ({ key, pre = '', post = '', splitlines }) => ({
14
+ export const getWikiKeymap = ({ key, pre = '', post = '', splitlines }) => ({
13
15
  key,
14
16
  run(view) {
15
- const { state } = view;
17
+ const { state } = view, tree = syntaxTree(state);
16
18
  view.dispatch(state.changeByRange(({ from, to }) => {
19
+ if (key === 'Mod-/'
20
+ && reKartographer.test(tree.resolveInner(from, 1).name)
21
+ && reKartographer.test(tree.resolveInner(to, -1).name)) {
22
+ // JSONC comment
23
+ if (from === to) {
24
+ pre = '//';
25
+ post = '';
26
+ }
27
+ else {
28
+ pre = '/*';
29
+ post = '*/';
30
+ }
31
+ }
17
32
  if (splitlines) {
18
33
  const start = state.doc.lineAt(from).from, end = state.doc.lineAt(to).to, insert = encapsulateLines(state.sliceDoc(start, end), pre, post);
19
34
  return {
@@ -31,4 +46,4 @@ export const getKeymap = ({ key, pre = '', post = '', splitlines }) => ({
31
46
  },
32
47
  preventDefault: true,
33
48
  });
34
- export default keybindings.map(getKeymap);
49
+ export default keybindings.map(getWikiKeymap);
package/dist/lint.js CHANGED
@@ -1,4 +1,4 @@
1
- const findDiagnostic = (deco, head, anchor = head) => {
1
+ const myFindDiagnostic = (deco, head, anchor = head) => {
2
2
  let found;
3
3
  deco.between(head, Infinity, (_, __, { spec: { diagnostics } }) => {
4
4
  const next = diagnostics.sort((a, b) => a.from - b.from || a.to - b.to)
@@ -16,7 +16,7 @@ const findDiagnostic = (deco, head, anchor = head) => {
16
16
  * @param cm CodeMirror6 实例
17
17
  */
18
18
  export const nextDiagnostic = (cm) => {
19
- const view = cm.view, { state } = view, { diagnostics } = state.field(cm.getLintExtension()[2][0]), { from, to } = state.selection.main, next = findDiagnostic(diagnostics, from, to) ?? findDiagnostic(diagnostics, 0);
19
+ const view = cm.view, { state } = view, { diagnostics } = state.field(cm.getLintExtension()[2][0]), { from, to } = state.selection.main, next = myFindDiagnostic(diagnostics, from, to) ?? myFindDiagnostic(diagnostics, 0);
20
20
  if (!next || next.from === from && next.to === to) {
21
21
  return false;
22
22
  }
@@ -4,7 +4,7 @@ import { javascriptLanguage } from '@codemirror/lang-javascript';
4
4
  import { sanitizeInlineStyle, lintJSON } from '@bhsd/common';
5
5
  import { getWikiLinter, getJsLinter, getCssLinter, getLuaLinter, stylelintRepo, eslintRepo, luacheckRepo, isStylelintConfig, } from './linter.js';
6
6
  import { posToIndex, toConfigGetter, } from './util.js';
7
- import { base } from './constants.js';
7
+ import { baseData } from './constants.js';
8
8
  import { vue } from './javascript-globals.js';
9
9
  /**
10
10
  * 获取Linter选项
@@ -67,7 +67,7 @@ const wikiLintSource = async (wikiLint, text, opt, doc, f = 0, t) => (await wiki
67
67
  * @test
68
68
  */
69
69
  export const getWikiLintSource = (articlePath) => async (opt, v) => {
70
- const options = { ...await getOpt(opt), cdn: base.CDN };
70
+ const options = { ...await getOpt(opt), cdn: baseData.CDN };
71
71
  if (articlePath) {
72
72
  options.getConfig = toConfigGetter(options.getConfig, articlePath);
73
73
  }
@@ -113,7 +113,7 @@ const jsLintSource = (esLint, code, opt, doc, f = 0, t) => esLint(code, opt)
113
113
  * @test
114
114
  */
115
115
  export const getJsLintSource = async (opt) => {
116
- const { CDN } = base, esLint = await getJsLinter(CDN && `${CDN}/${eslintRepo}`);
116
+ const { CDN } = baseData, esLint = await getJsLinter(CDN && `${CDN}/${eslintRepo}`);
117
117
  const lintSource = async ({ doc }) => jsLintSource(esLint, doc.toString(), await getOpt(opt), doc);
118
118
  lintSource.fixer = (doc, rule) => esLint.fixer(doc.toString(), rule);
119
119
  Object.defineProperty(lintSource, 'config', {
@@ -156,7 +156,7 @@ const cssLintSource = async (styleLint, code, opt, doc, f = 0, t) => {
156
156
  * @test
157
157
  */
158
158
  export const getCssLintSource = async (opt) => {
159
- const { CDN } = base, styleLint = await getCssLinter(CDN && `${CDN}/${stylelintRepo}`);
159
+ const { CDN } = baseData, styleLint = await getCssLinter(CDN && `${CDN}/${stylelintRepo}`);
160
160
  const lintSource = async ({ doc }) => cssLintSource(styleLint, doc.toString(), await getOpt(opt), doc);
161
161
  lintSource.fixer = async (doc, rule) => styleLint.fixer(doc.toString(), rule);
162
162
  Object.defineProperty(lintSource, 'config', {
@@ -180,7 +180,7 @@ const stylelintConfigVue = /* #__PURE__ */ (() => ({
180
180
  }))();
181
181
  /** @implements */
182
182
  const getVueOrHtmlLintSource = (rules, globals) => async (opt) => {
183
- const { CDN } = base, styleLint = await getCssLinter(CDN && `${CDN}/${stylelintRepo}`), esLint = await getJsLinter(CDN && `${CDN}/${eslintRepo}`);
183
+ const { CDN } = baseData, styleLint = await getCssLinter(CDN && `${CDN}/${stylelintRepo}`), esLint = await getJsLinter(CDN && `${CDN}/${eslintRepo}`);
184
184
  const lintSource = async (state) => {
185
185
  const { doc } = state, option = await getOpt(opt, true) ?? {};
186
186
  let js = option['js'], css = option['css'];
@@ -228,7 +228,7 @@ export const getVueLintSource = /* #__PURE__ */ getVueOrHtmlLintSource(stylelint
228
228
  * @test
229
229
  */
230
230
  export const getHTMLLintSource = async (opt, view, language) => {
231
- const vueLintSource = await getVueOrHtmlLintSource()(opt), wikiLint = await getWikiLinter({ include: false, ...await getOpt(opt), cdn: base.CDN }, view);
231
+ const vueLintSource = await getVueOrHtmlLintSource()(opt), wikiLint = await getWikiLinter({ include: false, ...await getOpt(opt), cdn: baseData.CDN }, view);
232
232
  const lintSource = async (state) => {
233
233
  const { doc } = state, option = await getOpt(opt, true) ?? {}, wiki = option['wiki'];
234
234
  return [
@@ -255,7 +255,7 @@ export const getJsonLintSource = () => ({ doc }) => lintJSON(doc.toString())
255
255
  * @test
256
256
  */
257
257
  export const getLuaLintSource = async () => {
258
- const { CDN } = base, luaLint = await getLuaLinter(CDN && `${CDN}/${luacheckRepo}`);
258
+ const { CDN } = baseData, luaLint = await getLuaLinter(CDN && `${CDN}/${luacheckRepo}`);
259
259
  return async ({ doc }) => (await luaLint(doc.toString()))
260
260
  .map(({ line, column, end_column, msg: message, severity }) => ({
261
261
  source: 'Luacheck',
package/dist/lua.d.ts CHANGED
@@ -1,3 +1,19 @@
1
+ import { ViewPlugin } from '@codemirror/view';
1
2
  import { LanguageSupport } from '@codemirror/language';
3
+ import type { ViewUpdate, DecorationSet } from '@codemirror/view';
4
+ import type { EditorState } from '@codemirror/state';
5
+ import type { Tree } from '@lezer/common';
6
+ import type { DocRange } from './fold';
7
+ /**
8
+ * 高亮显示LDoc标签
9
+ * @ignore
10
+ * @test
11
+ */
12
+ export declare const markDocTag: (tree: Tree, visibleRanges: readonly DocRange[], state: EditorState) => DecorationSet;
13
+ export declare const markDocTagPlugin: ViewPlugin<{
14
+ tree: Tree;
15
+ decorations: DecorationSet;
16
+ update({ docChanged, viewportChanged, state, view: { visibleRanges } }: ViewUpdate): void;
17
+ }, undefined>;
2
18
  declare const _default: () => LanguageSupport;
3
19
  export default _default;
package/dist/lua.js CHANGED
@@ -1,9 +1,10 @@
1
1
  /* eslint-disable no-template-curly-in-string */
2
2
  import { lua } from '@codemirror/legacy-modes/mode/lua';
3
+ import { ViewPlugin, Decoration } from '@codemirror/view';
3
4
  import { syntaxTree, LanguageSupport, StreamLanguage, foldService, HighlightStyle, syntaxHighlighting, } from '@codemirror/language';
4
5
  import { snippetCompletion } from '@codemirror/autocomplete';
5
6
  import { tags } from '@lezer/highlight';
6
- import { leadingSpaces, sliceDoc } from './util.js';
7
+ import { leadingSpaces, sliceDoc, markDocTagType } from './util.js';
7
8
  import { lightHighlightStyle } from './theme.js';
8
9
  const map = {
9
10
  1: 'constant',
@@ -217,7 +218,7 @@ const map = {
217
218
  },
218
219
  ext: 4,
219
220
  },
220
- }, builtin = ['false', 'nil', 'true'], builtins = builtin.map(label => ({ label, type: 'constant' })), tables = [
221
+ }, luaBuiltin = ['false', 'nil', 'true'], luaBuiltins = luaBuiltin.map(label => ({ label, type: 'constant' })), tables = [
221
222
  '_G',
222
223
  ...Object.keys(globals),
223
224
  ].map(label => ({ label, type: 'namespace' })), constants = [
@@ -267,7 +268,7 @@ const map = {
267
268
  'do',
268
269
  'until',
269
270
  'goto',
270
- ].map(label => ({ label, type: 'keyword' })), keywords = [
271
+ ].map(label => ({ label, type: 'keyword' })), luaKeywords = [
271
272
  ...[
272
273
  'if',
273
274
  'while',
@@ -305,14 +306,14 @@ const map = {
305
306
  detail: 'in loop',
306
307
  type: 'keyword',
307
308
  }),
308
- ], types = new Set(['variableName', 'variableName.standard', 'keyword']), lang = StreamLanguage.define(lua);
309
+ ], excludedTypes = new Set(['variableName', 'variableName.standard', 'keyword']), lang = StreamLanguage.define(lua);
309
310
  /**
310
311
  * @implements
311
312
  * @test
312
313
  */
313
314
  const source = context => {
314
315
  const { state, pos } = context, node = syntaxTree(state).resolveInner(pos, -1);
315
- if (!types.has(node.name)) {
316
+ if (!excludedTypes.has(node.name)) {
316
317
  return null;
317
318
  }
318
319
  const match = context.matchBefore(/(?:(?:^|\S|\.\.)\s+|^|[^\w\s]|\.\.)\w+$|\.{1,2}$/u);
@@ -381,7 +382,7 @@ const source = context => {
381
382
  case ',':
382
383
  return {
383
384
  from,
384
- options: [...builtins, ...constants, ...tables, ...unary],
385
+ options: [...luaBuiltins, ...constants, ...tables, ...unary],
385
386
  validFor,
386
387
  };
387
388
  case '}':
@@ -396,7 +397,7 @@ const source = context => {
396
397
  case '':
397
398
  return {
398
399
  from,
399
- options: [...keywords, ...blocks, ...unary, ...constants, ...tables, ...builtins],
400
+ options: [...luaKeywords, ...blocks, ...unary, ...constants, ...tables, ...luaBuiltins],
400
401
  validFor,
401
402
  };
402
403
  default:
@@ -405,9 +406,9 @@ const source = context => {
405
406
  return {
406
407
  from,
407
408
  options: prevSibling?.name !== 'keyword'
408
- || builtin.includes(sliceDoc(state, prevSibling))
409
+ || luaBuiltin.includes(sliceDoc(state, prevSibling))
409
410
  ? [...binary, ...blocks]
410
- : [...builtins, ...constants, ...tables, ...unary, ...blocks],
411
+ : [...luaBuiltins, ...constants, ...tables, ...unary, ...blocks],
411
412
  validFor,
412
413
  };
413
414
  }
@@ -438,10 +439,65 @@ const fold = ({ doc, tabSize }, start, from) => {
438
439
  }
439
440
  return empty || j === number ? null : { from, to: doc.line(j).to };
440
441
  };
442
+ /**
443
+ * 高亮显示LDoc标签
444
+ * @ignore
445
+ * @test
446
+ */
447
+ export const markDocTag = (tree, visibleRanges, state) => {
448
+ const decorations = [];
449
+ for (const { from, to } of visibleRanges) {
450
+ let node = tree.resolveInner(from, 1);
451
+ while (node && node.from < to) {
452
+ if (node.name === 'comment') {
453
+ const firstLine = sliceDoc(state, node), block = firstLine.startsWith('--[[--');
454
+ if (block
455
+ || firstLine.startsWith('---')
456
+ && !(firstLine.endsWith('--') && /[^-]/u.test(firstLine))) {
457
+ while (node.name === 'comment') {
458
+ const comment = sliceDoc(state, node), mt = /^\s*(?:-{2,}\s*)?(@[a-z]+)(\s+\{)?/diu.exec(comment);
459
+ if (mt) {
460
+ markDocTagType(decorations, node.from, mt, 1);
461
+ }
462
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
463
+ const { nextSibling } = node;
464
+ if (!nextSibling || (block
465
+ ? comment.endsWith(']]')
466
+ : state.sliceDoc(node.to, nextSibling.from)
467
+ .split('\n', 3).length > 2)) {
468
+ break;
469
+ }
470
+ node = nextSibling;
471
+ }
472
+ }
473
+ }
474
+ node = node.nextSibling;
475
+ }
476
+ }
477
+ return Decoration.set(decorations);
478
+ };
479
+ export const markDocTagPlugin = ViewPlugin.fromClass(class {
480
+ constructor({ state, visibleRanges }) {
481
+ this.tree = syntaxTree(state);
482
+ this.decorations = markDocTag(this.tree, visibleRanges, state);
483
+ }
484
+ update({ docChanged, viewportChanged, state, view: { visibleRanges } }) {
485
+ const tree = syntaxTree(state);
486
+ if (docChanged || viewportChanged || tree !== this.tree) {
487
+ this.tree = tree;
488
+ this.decorations = markDocTag(tree, visibleRanges, state);
489
+ }
490
+ }
491
+ }, {
492
+ decorations(v) {
493
+ return v.decorations;
494
+ },
495
+ });
441
496
  const support = [
442
497
  lightHighlightStyle,
443
498
  syntaxHighlighting(HighlightStyle.define([{ tag: tags.standard(tags.variableName), class: 'cm-globals' }])),
444
499
  lang.data.of({ autocomplete: source }),
445
500
  foldService.of(fold),
501
+ markDocTagPlugin,
446
502
  ];
447
503
  export default () => new LanguageSupport(lang, support);