@bhsd/codemirror-mediawiki 3.12.1 → 3.12.3

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 (51) hide show
  1. package/dist/codemirror.d.ts +2 -1
  2. package/dist/codemirror.js +5 -5
  3. package/dist/constants.d.ts +2 -1
  4. package/dist/constants.js +1 -1
  5. package/dist/css.js +2 -2
  6. package/dist/escape.js +9 -10
  7. package/dist/fold.d.ts +5 -8
  8. package/dist/fold.js +18 -18
  9. package/dist/hover.js +3 -3
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/inlay.js +2 -2
  13. package/dist/javascript.d.ts +1 -1
  14. package/dist/javascript.js +8 -4
  15. package/dist/json.d.ts +8 -0
  16. package/dist/json.js +101 -0
  17. package/dist/keymap.d.ts +8 -1
  18. package/dist/keymap.js +89 -7
  19. package/dist/lilypond.d.ts +14 -0
  20. package/dist/lilypond.js +240 -0
  21. package/dist/lint.js +2 -2
  22. package/dist/lintsource.d.ts +1 -1
  23. package/dist/lintsource.js +7 -7
  24. package/dist/lua.d.ts +1 -1
  25. package/dist/lua.js +39 -63
  26. package/dist/main.min.js +32 -31
  27. package/dist/matchBrackets.d.ts +3 -11
  28. package/dist/matchBrackets.js +51 -39
  29. package/dist/matchTag.d.ts +5 -5
  30. package/dist/matchTag.js +4 -4
  31. package/dist/math.d.ts +3 -0
  32. package/dist/math.js +58 -0
  33. package/dist/mediawiki.d.ts +2 -3
  34. package/dist/mediawiki.js +34 -26
  35. package/dist/mw.min.js +33 -32
  36. package/dist/ref.d.ts +2 -2
  37. package/dist/ref.js +5 -5
  38. package/dist/signature.js +13 -13
  39. package/dist/static.d.ts +7 -0
  40. package/dist/static.js +7 -0
  41. package/dist/theme.d.ts +1 -1
  42. package/dist/theme.js +9 -3
  43. package/dist/token.d.ts +10 -6
  44. package/dist/token.js +54 -20
  45. package/dist/util.d.ts +35 -10
  46. package/dist/util.js +43 -15
  47. package/dist/wiki.min.js +33 -32
  48. package/i18n/en.json +1 -1
  49. package/i18n/zh-hans.json +1 -1
  50. package/i18n/zh-hant.json +1 -1
  51. package/package.json +8 -10
@@ -4,7 +4,8 @@ import type { Extension, StateField } from '@codemirror/state';
4
4
  import type { SyntaxNode } from '@lezer/common';
5
5
  import type { ConfigGetter } from '@bhsd/browser';
6
6
  import type { ConfigData } from 'wikiparser-node';
7
- import type { DocRange, foldHandler } from './fold';
7
+ import type { foldHandler } from './fold';
8
+ import type { DocRange } from './util';
8
9
  import type { detectIndent } from './indent';
9
10
  import type { Option, LiveOption } from './linter';
10
11
  import type { LintSource, LintSources, LintSourceGetter } from './lintsource';
@@ -5,7 +5,7 @@ import { defaultKeymap, historyKeymap, history, redo, indentWithTab, insertNewli
5
5
  import { search, searchKeymap } from '@codemirror/search';
6
6
  import { linter, lintGutter } from '@codemirror/lint';
7
7
  import elt from 'crelt';
8
- import { base, panelSelector, panelsSelector, diagnosticSelector, noDetectionLangs } from './constants.js';
8
+ import { baseData, panelSelector, panelsSelector, diagnosticSelector, noDetectionLangs } from './constants.js';
9
9
  import { light } from './theme.js';
10
10
  import { nextDiagnostic } from './lint.js';
11
11
  export const plain = () => [
@@ -62,10 +62,10 @@ export const replaceSelections = (view, func) => {
62
62
  /** CodeMirror 6 editor */
63
63
  export class CodeMirror6 {
64
64
  static get CDN() {
65
- return base.CDN;
65
+ return baseData.CDN;
66
66
  }
67
67
  static set CDN(url) {
68
- base.CDN = url;
68
+ baseData.CDN = url;
69
69
  }
70
70
  #textarea;
71
71
  #language = new Compartment();
@@ -301,10 +301,10 @@ export class CodeMirror6 {
301
301
  const diagnostics = (await source(state)).map((diagnostic) => ({
302
302
  ...diagnostic,
303
303
  renderMessage(view) {
304
- const span = elt('span', { class: diagnosticSelector.slice(1) }, diagnostic.renderMessage?.(view) ?? diagnostic.message);
304
+ const span = elt('span', { class: diagnosticSelector.slice(1) }, diagnostic.renderMessage?.call(this, view) ?? this.message);
305
305
  span.addEventListener('click', () => {
306
306
  view.dispatch({
307
- selection: { anchor: diagnostic.from, head: diagnostic.to },
307
+ selection: { anchor: this.from, head: this.to },
308
308
  });
309
309
  view.focus();
310
310
  });
@@ -1,4 +1,5 @@
1
1
  import { Decoration } from '@codemirror/view';
2
- export declare const base: Record<'CDN', string | undefined>, hoverSelector = ".cm-tooltip-hover-mw", diagnosticSelector = ".cm-diagnosticText-clickable", panelSelector = ".cm-panel", panelsSelector = ".cm-panels", actionSelector = ".cm-diagnosticAction", doctagMark: Decoration, typeMark: Decoration, noDetectionLangs: Set<string>, bgDark = "#4c566a", matchingCls = "cm-matchingTag", nonmatchingCls = "cm-nonmatchingTag";
2
+ import type { Completion } from '@codemirror/autocomplete';
3
+ export declare const baseData: Record<'CDN', string | undefined>, extData: Record<string, Set<string>>, extCompletion: Record<string, Completion[]>, hoverSelector = ".cm-tooltip-hover-mw", diagnosticSelector = ".cm-diagnosticText-clickable", panelSelector = ".cm-panel", panelsSelector = ".cm-panels", actionSelector = ".cm-diagnosticAction", doctagMark: Decoration, typeMark: Decoration, noDetectionLangs: Set<string>, bgDark = "#4c566a", matchingCls = "cm-matchingTag", nonmatchingCls = "cm-nonmatchingTag";
3
4
  export declare const isWMF: boolean;
4
5
  export declare const isMac: boolean;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Decoration } from '@codemirror/view';
2
2
  import { wmf } from '@bhsd/common';
3
- export const base = { CDN: undefined }, hoverSelector = '.cm-tooltip-hover-mw', diagnosticSelector = '.cm-diagnosticText-clickable', panelSelector = '.cm-panel', panelsSelector = '.cm-panels', actionSelector = '.cm-diagnosticAction', doctagMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag' }), typeMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag-type' }), noDetectionLangs = new Set(['plain', 'mediawiki']), bgDark = '#4c566a', matchingCls = 'cm-matchingTag', nonmatchingCls = 'cm-nonmatchingTag';
3
+ export const baseData = { CDN: undefined }, extData = {}, extCompletion = {}, hoverSelector = '.cm-tooltip-hover-mw', diagnosticSelector = '.cm-diagnosticText-clickable', panelSelector = '.cm-panel', panelsSelector = '.cm-panels', actionSelector = '.cm-diagnosticAction', doctagMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag' }), typeMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag-type' }), noDetectionLangs = new Set(['plain', 'mediawiki']), bgDark = '#4c566a', matchingCls = 'cm-matchingTag', nonmatchingCls = 'cm-nonmatchingTag';
4
4
  export const isWMF = /* @__PURE__ */ (() => typeof location === 'object'
5
5
  && new RegExp(String.raw `\.(?:${wmf})\.org$`, 'u').test(location.hostname))();
6
6
  export const isMac = /* @__PURE__ */ (() => {
package/dist/css.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { cssLanguage, cssCompletionSource } from '@codemirror/lang-css';
2
2
  import { LanguageSupport, syntaxTree } from '@codemirror/language';
3
- import { sliceDoc } from './util.js';
4
- const cssWideKeywords = /* @__PURE__ */ (() => ['revert', 'revert-layer'].map((label) => ({ label, type: 'keyword' })))();
3
+ import { sliceDoc, getCompletions } from './util.js';
4
+ const cssWideKeywords = /* @__PURE__ */ getCompletions(['revert', 'revert-layer']);
5
5
  /**
6
6
  * CSS completion source with dialect-specific adjustments.
7
7
  * @param dialect 是否是sanitized-css
package/dist/escape.js CHANGED
@@ -3,7 +3,7 @@ import { EditorSelection } from '@codemirror/state';
3
3
  import { indentMore, indentLess } from '@codemirror/commands';
4
4
  import { getLSP } from '@bhsd/browser';
5
5
  import elt from 'crelt';
6
- import { base } from './constants.js';
6
+ import { baseData } from './constants.js';
7
7
  import { replaceSelections, menuRegistry, } from './codemirror.js';
8
8
  import { sliceDoc, toConfigGetter, } from './util.js';
9
9
  const entity = { '"': 'quot', "'": 'apos', '<': 'lt', '>': 'gt', '&': 'amp', ' ': 'nbsp' };
@@ -60,17 +60,16 @@ escapeWiki = async (view, lsp) => {
60
60
  }
61
61
  view.dispatch(state.changeByRange(range => {
62
62
  const insert = replacements.get(range);
63
- if (insert === undefined) {
64
- return { range };
65
- }
66
- return {
67
- range: EditorSelection.range(range.from, range.from + insert.length),
68
- changes: { from: range.from, to: range.to, insert },
69
- };
63
+ return insert === undefined
64
+ ? { range }
65
+ : {
66
+ range: EditorSelection.range(range.from, range.from + insert.length),
67
+ changes: { from: range.from, to: range.to, insert },
68
+ };
70
69
  }));
71
70
  };
72
71
  const escapeWikiCommand = (view, getConfig) => {
73
- const lsp = getLSP(view, false, getConfig, base.CDN);
72
+ const lsp = getLSP(view, false, getConfig, baseData.CDN);
74
73
  if (lsp && 'provideRefactoringAction' in lsp && view.state.selection.ranges.some(({ empty }) => !empty)) {
75
74
  void escapeWiki(view, lsp);
76
75
  return true;
@@ -99,7 +98,7 @@ menuRegistry.push({
99
98
  handlerBase(view, e);
100
99
  });
101
100
  items = [btnHTML, btnURI];
102
- const lsp = getLSP(view, false, cm.getWikiConfig, base.CDN);
101
+ const lsp = getLSP(view, false, cm.getWikiConfig, baseData.CDN);
103
102
  if (lsp && 'provideRefactoringAction' in lsp) {
104
103
  const btnWiki = elt('div', 'Escape with magic words');
105
104
  btnWiki.addEventListener('click', e => {
package/dist/fold.d.ts CHANGED
@@ -3,10 +3,7 @@ import { RangeSet } from '@codemirror/state';
3
3
  import type { BlockInfo, Command } from '@codemirror/view';
4
4
  import type { EditorState, StateEffect, Extension } from '@codemirror/state';
5
5
  import type { SyntaxNode, Tree } from '@lezer/common';
6
- export interface DocRange {
7
- from: number;
8
- to: number;
9
- }
6
+ import type { DocRange } from './util';
10
7
  declare type AnchorUpdate = (pos: number, range: DocRange) => number;
11
8
  export declare const updateSelection: AnchorUpdate, updateAll: AnchorUpdate;
12
9
  /**
@@ -17,7 +14,7 @@ export declare const updateSelection: AnchorUpdate, updateAll: AnchorUpdate;
17
14
  * @param refOnly 是否仅检查`<ref>`标签
18
15
  * @test
19
16
  */
20
- export declare const foldable: (state: EditorState, posOrNode: number | SyntaxNode, tree?: Tree | null, refOnly?: boolean) => DocRange | false;
17
+ export declare const foldableInline: (state: EditorState, posOrNode: number | SyntaxNode, tree?: Tree | null, refOnly?: boolean) => DocRange | false;
21
18
  /**
22
19
  * 折叠所有模板
23
20
  * @param state
@@ -31,7 +28,7 @@ export declare const foldable: (state: EditorState, posOrNode: number | SyntaxNo
31
28
  * @test
32
29
  */
33
30
  export declare const traverse: (state: EditorState, tree: Tree, effects: StateEffect<DocRange>[], node: SyntaxNode | null, end: number, anchor: number, update: AnchorUpdate, refOnly?: boolean) => number;
34
- declare class FoldMarker extends GutterMarker {
31
+ declare class MyFoldMarker extends GutterMarker {
35
32
  readonly open: boolean;
36
33
  constructor(open: boolean);
37
34
  eq(other: this): boolean;
@@ -48,7 +45,7 @@ export declare const foldableLine: ({ state, viewportLineBlocks }: EditorView, {
48
45
  * @param view
49
46
  * @test
50
47
  */
51
- export declare const buildMarkers: (view: EditorView) => RangeSet<FoldMarker>;
48
+ export declare const buildMarkers: (view: EditorView) => RangeSet<MyFoldMarker>;
52
49
  /**
53
50
  * 生成折叠命令
54
51
  * @param refOnly 是否仅检查`<ref>`标签
@@ -62,7 +59,7 @@ export declare const unfoldRef: Command;
62
59
  * @param view
63
60
  * @test
64
61
  */
65
- export declare const selectedLines: (view: EditorView) => BlockInfo[];
62
+ export declare const mySelectedLines: (view: EditorView) => BlockInfo[];
66
63
  /**
67
64
  * Fold the template at the selection/cursor
68
65
  * @param view
package/dist/fold.js CHANGED
@@ -47,7 +47,7 @@ const refNames = new Set(['ref', 'references']);
47
47
  * @param refOnly 是否仅检查`<ref>`标签
48
48
  * @test
49
49
  */
50
- export const foldable = (state, posOrNode, tree, refOnly = false) => {
50
+ export const foldableInline = (state, posOrNode, tree, refOnly = false) => {
51
51
  if (typeof posOrNode === 'number') {
52
52
  tree = ensureSyntaxTree(state, posOrNode);
53
53
  }
@@ -141,7 +141,7 @@ const foldSelector = '.cm-tooltip-fold';
141
141
  * @param state
142
142
  */
143
143
  const create = (state) => {
144
- const { head } = state.selection.main, range = foldable(state, head);
144
+ const { head } = state.selection.main, range = foldableInline(state, head);
145
145
  if (range) {
146
146
  const { from, to } = range;
147
147
  let folded = false;
@@ -207,7 +207,7 @@ export const traverse = (state, tree, effects, node, end, anchor, update, refOnl
207
207
  while (node && (node.from < end
208
208
  || node.from === end
209
209
  && !(isTemplateBracket(node) && sliceDoc(state, node).startsWith('}}')))) {
210
- const range = foldable(state, node, tree, refOnly);
210
+ const range = foldableInline(state, node, tree, refOnly);
211
211
  if (range) {
212
212
  effects.push(foldEffect.of(range));
213
213
  node = tree.resolve(range.to, 1);
@@ -219,7 +219,7 @@ export const traverse = (state, tree, effects, node, end, anchor, update, refOnl
219
219
  }
220
220
  return anchor;
221
221
  };
222
- class FoldMarker extends GutterMarker {
222
+ class MyFoldMarker extends GutterMarker {
223
223
  constructor(open) {
224
224
  super();
225
225
  this.open = open;
@@ -231,8 +231,8 @@ class FoldMarker extends GutterMarker {
231
231
  return elt('span', { title: state.phrase(this.open ? 'Fold line' : 'Unfold line') }, this.open ? '⌄' : '›');
232
232
  }
233
233
  }
234
- const canFold = /* @__PURE__ */ new FoldMarker(true), canUnfold = /* @__PURE__ */ new FoldMarker(false);
235
- const findFold = ({ state }, line) => {
234
+ const canFold = /* @__PURE__ */ new MyFoldMarker(true), canUnfold = /* @__PURE__ */ new MyFoldMarker(false);
235
+ const myFindFold = ({ state }, line) => {
236
236
  let found;
237
237
  state.field(foldState, false)?.between(line.from, line.to, (from, to) => {
238
238
  if (!found && to === line.to) {
@@ -323,7 +323,7 @@ export const buildMarkers = (view) => {
323
323
  const builder = new RangeSetBuilder();
324
324
  for (const line of view.viewportLineBlocks) {
325
325
  let mark;
326
- if (findFold(view, line)) {
326
+ if (myFindFold(view, line)) {
327
327
  mark = canUnfold;
328
328
  }
329
329
  else if (foldableLine(view, line)) {
@@ -393,7 +393,7 @@ export const unfoldRef = (view) => {
393
393
  * @param view
394
394
  * @test
395
395
  */
396
- export const selectedLines = (view) => {
396
+ export const mySelectedLines = (view) => {
397
397
  const lines = [];
398
398
  for (const { head } of view.state.selection.ranges) {
399
399
  if (lines.some(({ from, to }) => from <= head && to >= head)) {
@@ -403,7 +403,7 @@ export const selectedLines = (view) => {
403
403
  }
404
404
  return lines;
405
405
  };
406
- const foldCode = (view, line) => {
406
+ const myFoldCode = (view, line) => {
407
407
  const range = foldableLine(view, line);
408
408
  if (range) {
409
409
  view.dispatch({ effects: foldEffect.of(range) });
@@ -411,8 +411,8 @@ const foldCode = (view, line) => {
411
411
  }
412
412
  return false;
413
413
  };
414
- const unfoldCode = (view, line) => {
415
- const folded = findFold(view, line);
414
+ const myUnfoldCode = (view, line) => {
415
+ const folded = myFindFold(view, line);
416
416
  return folded && unfoldEffect.of(folded);
417
417
  };
418
418
  /**
@@ -437,8 +437,8 @@ export const foldAt = view => {
437
437
  if (effects.length > 0) {
438
438
  return execute(view, effects, anchor);
439
439
  }
440
- for (const line of selectedLines(view)) {
441
- if (foldCode(view, line)) {
440
+ for (const line of mySelectedLines(view)) {
441
+ if (myFoldCode(view, line)) {
442
442
  return true;
443
443
  }
444
444
  }
@@ -515,8 +515,8 @@ export const mediawikiFold = /* @__PURE__ */ (() => [
515
515
  view.dispatch({ effects, selection });
516
516
  return true;
517
517
  }
518
- for (const line of selectedLines(view)) {
519
- const effect = unfoldCode(view, line);
518
+ for (const line of mySelectedLines(view)) {
519
+ const effect = myUnfoldCode(view, line);
520
520
  if (effect) {
521
521
  effects.push(effect);
522
522
  }
@@ -537,16 +537,16 @@ export const mediawikiFold = /* @__PURE__ */ (() => [
537
537
  return view.plugin(markers)?.markers ?? RangeSet.empty;
538
538
  },
539
539
  initialSpacer() {
540
- return new FoldMarker(false);
540
+ return new MyFoldMarker(false);
541
541
  },
542
542
  domEventHandlers: {
543
543
  click(view, line) {
544
- const effects = unfoldCode(view, line);
544
+ const effects = myUnfoldCode(view, line);
545
545
  if (effects) {
546
546
  view.dispatch({ effects });
547
547
  return true;
548
548
  }
549
- return foldCode(view, line);
549
+ return myFoldCode(view, line);
550
550
  },
551
551
  },
552
552
  }),
package/dist/hover.js CHANGED
@@ -2,7 +2,7 @@ import { hoverTooltip, EditorView } from '@codemirror/view';
2
2
  import { ensureSyntaxTree } from '@codemirror/language';
3
3
  import { getLSP, loadScript, } from '@bhsd/browser';
4
4
  import { tokens } from './config.js';
5
- import { base, hoverSelector, bgDark } from './constants.js';
5
+ import { baseData, hoverSelector, bgDark } from './constants.js';
6
6
  import { indexToPos, posToIndex, createTooltipView, toConfigGetter, escHTML, sliceDoc, findTemplateName, } from './util.js';
7
7
  const code = `${hoverSelector} code`;
8
8
  /**
@@ -58,13 +58,13 @@ export default (articlePath, templatedata) => (cm) => {
58
58
  hoverTooltip(async (view, pos, side) => {
59
59
  const { state } = view, { doc } = state;
60
60
  const { paramSuggest, tags } = cm.langConfig;
61
- let hover = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), base.CDN)?.provideHover(doc.toString(), indexToPos(doc, pos));
61
+ let hover = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), baseData.CDN)?.provideHover(doc.toString(), indexToPos(doc, pos));
62
62
  if (!hover && paramSuggest && 'templatedata' in tags) {
63
63
  // eslint-disable-next-line require-atomic-updates
64
64
  hover = await getHoverFromApi(state, pos, side, paramSuggest, templatedata);
65
65
  }
66
66
  if (hover) {
67
- const { CDN = '' } = base;
67
+ const { CDN = '' } = baseData;
68
68
  await loadScript(`${CDN}${CDN && '/'}npm/marked/lib/marked.umd.js`, 'marked', true);
69
69
  const { end } = hover.range;
70
70
  return {
package/dist/index.d.ts CHANGED
@@ -159,4 +159,4 @@ export declare const registerLanguage: (name: string, lang: (config?: unknown) =
159
159
  */
160
160
  export declare const registerLanguageCore: (name: string, lang: (config?: unknown) => LanguageSupport, lintSource?: LintSourceGetter) => void;
161
161
  export declare const registerTheme: (name: string, theme: Extension) => void;
162
- export { nord } from './theme.js';
162
+ export { nordDark as nord } from './theme.js';
package/dist/index.js CHANGED
@@ -422,4 +422,4 @@ export const registerLanguageCore = (name, lang, lintSource) => {
422
422
  export const registerTheme = (name, theme) => {
423
423
  themes[name] = theme;
424
424
  };
425
- export { nord } from './theme.js';
425
+ export { nordDark as nord } from './theme.js';
package/dist/inlay.js CHANGED
@@ -2,7 +2,7 @@ import { StateField, StateEffect } from '@codemirror/state';
2
2
  import { Decoration, EditorView, WidgetType, ViewPlugin } from '@codemirror/view';
3
3
  import { getLSP } from '@bhsd/browser';
4
4
  import elt from 'crelt';
5
- import { base } from './constants.js';
5
+ import { baseData } from './constants.js';
6
6
  import { posToIndex, toConfigGetter, } from './util.js';
7
7
  const cls = 'cm-inlay-hint';
8
8
  class InlayHintWidget extends WidgetType {
@@ -54,7 +54,7 @@ export default (articlePath) => (cm) => {
54
54
  field,
55
55
  ViewPlugin.define(view => {
56
56
  const timer = setInterval(() => {
57
- if (getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), base.CDN)) {
57
+ if (getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), baseData.CDN)) {
58
58
  clearInterval(timer);
59
59
  void update({ view, docChanged: true });
60
60
  }
@@ -1,7 +1,7 @@
1
1
  import type { Extension, EditorState } from '@codemirror/state';
2
2
  import type { DecorationSet } from '@codemirror/view';
3
3
  import type { Tree } from '@lezer/common';
4
- import type { DocRange } from './fold';
4
+ import type { DocRange } from './util';
5
5
  import type { CodeMirror6 } from './codemirror';
6
6
  export declare const jsCompletion: Extension;
7
7
  /**
@@ -6,7 +6,7 @@ import { builtin } from './javascript-globals.js';
6
6
  import { doctagMark } from './constants.js';
7
7
  import { markDocTagType, pushDecoration } from './util.js';
8
8
  export const jsCompletion = javascriptLanguage.data.of({ autocomplete: scopeCompletionSource(globalThis) });
9
- const globalsMark = Decoration.mark({ class: 'cm-globals' }), builtinGlobals = new Set(Object.keys(builtin));
9
+ const globalsMark = Decoration.mark({ class: 'cm-globals' }), varMark = Decoration.mark({ class: 'cm-doctag-var' }), builtinGlobals = new Set(Object.keys(builtin));
10
10
  /**
11
11
  * 忽略JavaScript正则表达式中的括号匹配
12
12
  * @param state
@@ -61,14 +61,18 @@ export const markGlobalsAndDocTag = (tree, visibleRanges, state, cm) => {
61
61
  }
62
62
  }
63
63
  else if (type.is('BlockComment') && /^\/\*{2}(?!\*)/u.test(name)) {
64
- const comment = name.slice(2), mtAll = comment.matchAll(/^[ \t]*\*\s*(@[a-z]+)(\s+\{(?!\}))?|\{(@[a-z]+)/dgimu);
64
+ const comment = name.slice(2), pos = f + 2, mtAll = comment.matchAll(/^[ \t]*\*\s*(@[a-z]+)(\s+\{)?|\{(@[a-z]+)/dgimu);
65
65
  for (const mt of mtAll) {
66
66
  if (mt[3]) {
67
67
  const [start, end] = mt.indices[3];
68
- pushDecoration(decorations, doctagMark, f + start + 2, f + end + 2);
68
+ pushDecoration(decorations, doctagMark, pos + start, pos + end);
69
69
  }
70
70
  else {
71
- markDocTagType(decorations, f + 2, mt);
71
+ const index = markDocTagType(decorations, pos, mt), m = /^\s+([a-z_]\w*)\s+-/diu.exec(comment.slice(index));
72
+ if (m) {
73
+ const [start, end] = m.indices[1];
74
+ pushDecoration(decorations, varMark, pos + index + start, pos + index + end);
75
+ }
72
76
  }
73
77
  }
74
78
  }
package/dist/json.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type { StreamParser, StringStream } from '@codemirror/language';
2
+ declare interface State {
3
+ tokenize: Tokenizer;
4
+ wb: boolean;
5
+ }
6
+ declare type Tokenizer = (stream: StringStream, state: State) => string;
7
+ export declare const jsonBasic: StreamParser<State>, jsonc: StreamParser<State>;
8
+ export {};
package/dist/json.js ADDED
@@ -0,0 +1,101 @@
1
+ import { inComment } from './util.js';
2
+ const eatNumber = (stream, state) => {
3
+ if (stream.match(/^\d+(?:\.\d+)?(?:e[+-]?\d+)?/iu)) {
4
+ state.wb = false;
5
+ return /* #164 */ 'number';
6
+ }
7
+ state.wb = true;
8
+ return '';
9
+ };
10
+ const mkJson = (jsoncMode) => {
11
+ // Tokenizer
12
+ const inBase = (stream, state) => {
13
+ if (stream.eatSpace()) {
14
+ state.wb = true;
15
+ return '';
16
+ }
17
+ const ch = stream.next();
18
+ switch (ch) {
19
+ case '{':
20
+ case '}':
21
+ state.wb = true;
22
+ return 'brace';
23
+ case '[':
24
+ case ']':
25
+ state.wb = true;
26
+ return 'squareBracket';
27
+ case ':':
28
+ case ',':
29
+ state.wb = true;
30
+ return 'separator';
31
+ case '/':
32
+ state.wb = true;
33
+ if (jsoncMode) {
34
+ if (stream.eat('/')) {
35
+ stream.skipToEnd();
36
+ return /* #940 */ 'comment';
37
+ }
38
+ else if (stream.eat('*')) {
39
+ state.tokenize = inJsoncComment;
40
+ return 'comment';
41
+ }
42
+ }
43
+ return '';
44
+ case '"': {
45
+ state.wb = true;
46
+ let escaped = false, next = stream.next();
47
+ while (next) {
48
+ if (!escaped && next === '"') {
49
+ break;
50
+ }
51
+ escaped = !escaped && next === '\\';
52
+ next = stream.next();
53
+ }
54
+ return stream.match(/^\s*:/u, false)
55
+ ? /* #00c */ 'propertyName.definition'
56
+ : /* #a11 */ 'string';
57
+ }
58
+ case '-':
59
+ if (state.wb) {
60
+ return eatNumber(stream, state);
61
+ }
62
+ state.wb = true;
63
+ return '';
64
+ default:
65
+ if (state.wb) {
66
+ if (/\d/u.test(ch)) {
67
+ stream.backUp(1);
68
+ return eatNumber(stream, state);
69
+ }
70
+ else if (ch === 'n' && stream.match(/^ull\b/u)) {
71
+ state.wb = false;
72
+ return /* #708 */ 'null';
73
+ }
74
+ else if (ch === 't' && stream.match(/^rue\b/u)
75
+ || ch === 'f' && stream.match(/^alse\b/u)) {
76
+ state.wb = false;
77
+ return /* #219 */ 'bool';
78
+ }
79
+ }
80
+ state.wb = !/[\w$]/u.test(ch);
81
+ return '';
82
+ }
83
+ };
84
+ const inJsoncComment = inComment(inBase, '*/');
85
+ // Interface
86
+ return {
87
+ startState() {
88
+ return {
89
+ tokenize: inBase,
90
+ wb: true,
91
+ };
92
+ },
93
+ token(stream, state) {
94
+ if (stream.sol()) {
95
+ state.wb = true;
96
+ }
97
+ return state.tokenize(stream, state);
98
+ },
99
+ };
100
+ };
101
+ export const jsonBasic = mkJson(), jsonc = mkJson(true);
package/dist/keymap.d.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import type { KeyBinding } from '@codemirror/view';
2
+ import type { EditorState } from '@codemirror/state';
3
+ import type { Tree } from '@lezer/common';
2
4
  import type { KeymapConfig } from './keybindings';
5
+ /**
6
+ * @ignore
7
+ * @test
8
+ */
9
+ export declare const getExtNames: (state: EditorState, tree: Tree, pos: number, side: 1 | -1) => string[];
3
10
  /**
4
11
  * 生成keymap
5
12
  * @param opt 快捷键设置
@@ -9,6 +16,6 @@ import type { KeymapConfig } from './keybindings';
9
16
  * @param opt.splitlines 是否分行
10
17
  * @test
11
18
  */
12
- export declare const getKeymap: ({ key, pre, post, splitlines }: KeymapConfig) => KeyBinding;
19
+ export declare const getWikiKeymap: ({ key, pre, post, splitlines }: KeymapConfig) => KeyBinding;
13
20
  declare const _default: KeyBinding[];
14
21
  export default _default;
package/dist/keymap.js CHANGED
@@ -1,5 +1,50 @@
1
1
  import { EditorSelection } from '@codemirror/state';
2
+ import { syntaxTree } from '@codemirror/language';
2
3
  import { keybindings, encapsulateLines } from './keybindings.js';
4
+ import { getTag } from './matchTag.js';
5
+ import { sliceDoc, getExtTags } from './util.js';
6
+ /**
7
+ * @ignore
8
+ * @test
9
+ */
10
+ export const getExtNames = (state, tree, pos, side) => {
11
+ const node = tree.resolveInner(pos, side), { name } = node;
12
+ if (name === 'Document') {
13
+ const { doc } = state, end = side === 1 ? 'to' : 'from';
14
+ let line = doc.lineAt(pos);
15
+ if (line[end] === pos) {
16
+ const { lines } = doc;
17
+ for (let { number } = line; number > 0 && number <= lines; number -= side) {
18
+ line = doc.line(number);
19
+ if (line.length > 0) {
20
+ return getExtNames(state, tree, line[end], -side);
21
+ }
22
+ }
23
+ }
24
+ return [];
25
+ }
26
+ const ext = name.includes('mw-tag-') ? getExtTags(name.split('_')) : [];
27
+ if (name.includes('mw-exttag-bracket')) {
28
+ const bracket = sliceDoc(state, node), { from } = node;
29
+ // `<score>`、`<maplink>`和`<mapfram>`内部均不可包含其他扩展标签,所以可以省略一些情形
30
+ if (side === 1 ? bracket === '</' && from === pos : bracket === '>') {
31
+ // 在扩展标签旁,如 `・</score>` 或 `<maplink>・`
32
+ const sibling = node[side === 1 ? 'nextSibling' : 'prevSibling'], tag = sibling && getTag(state, sibling);
33
+ if (tag && (side === 1 || !tag.closing)) {
34
+ ext.push(tag.name);
35
+ }
36
+ }
37
+ else if (bracket === '></' && from + 1 === pos) {
38
+ // 扩展标签内尚无内容,如 `<score>・</score>`
39
+ const { prevSibling } = node, tag = prevSibling && getTag(state, prevSibling);
40
+ if (tag) {
41
+ ext.push(tag.name);
42
+ }
43
+ }
44
+ }
45
+ return ext;
46
+ };
47
+ const isExtRange = (from, to, empty, names) => names.some(name => empty ? from.includes(name) || to.includes(name) : from.includes(name) && to.includes(name));
3
48
  /**
4
49
  * 生成keymap
5
50
  * @param opt 快捷键设置
@@ -9,21 +54,58 @@ import { keybindings, encapsulateLines } from './keybindings.js';
9
54
  * @param opt.splitlines 是否分行
10
55
  * @test
11
56
  */
12
- export const getKeymap = ({ key, pre = '', post = '', splitlines }) => ({
57
+ export const getWikiKeymap = ({ key, pre = '', post = '', splitlines }) => ({
13
58
  key,
14
59
  run(view) {
15
- const { state } = view;
16
- view.dispatch(state.changeByRange(({ from, to }) => {
60
+ const { state } = view, tree = syntaxTree(state);
61
+ view.dispatch(state.changeByRange(({ from, to, empty }) => {
62
+ let before = pre, after = post;
63
+ if (key === 'Mod-/') {
64
+ const fromExt = getExtNames(state, tree, from, 1), toExt = getExtNames(state, tree, to, -1);
65
+ if (isExtRange(fromExt, toExt, empty, ['maplink', 'mapframe'])) {
66
+ // JSONC comment
67
+ if (empty) {
68
+ before = '//';
69
+ after = '';
70
+ }
71
+ else {
72
+ before = '/* ';
73
+ after = ' */';
74
+ }
75
+ }
76
+ else if (isExtRange(fromExt, toExt, empty, ['score-scheme'])) {
77
+ // LilyPond scheme comment
78
+ if (empty) {
79
+ before = ';';
80
+ after = '';
81
+ }
82
+ else {
83
+ before = '#! ';
84
+ after = ' !#';
85
+ }
86
+ }
87
+ else if (isExtRange(fromExt, toExt, empty, ['score'])) {
88
+ // LilyPond comment
89
+ if (empty) {
90
+ before = '%';
91
+ after = '';
92
+ }
93
+ else {
94
+ before = '%{ ';
95
+ after = ' %}';
96
+ }
97
+ }
98
+ }
17
99
  if (splitlines) {
18
- const start = state.doc.lineAt(from).from, end = state.doc.lineAt(to).to, insert = encapsulateLines(state.sliceDoc(start, end), pre, post);
100
+ const start = state.doc.lineAt(from).from, end = state.doc.lineAt(to).to, insert = encapsulateLines(state.sliceDoc(start, end), before, after);
19
101
  return {
20
102
  range: EditorSelection.range(start, start + insert.length),
21
103
  changes: { from: start, to: end, insert },
22
104
  };
23
105
  }
24
- const insert = pre + state.sliceDoc(from, to) + post, head = from + insert.length;
106
+ const insert = before + state.sliceDoc(from, to) + after, head = from + insert.length;
25
107
  return {
26
- range: EditorSelection.cursor(from === to ? from + pre.length : head),
108
+ range: EditorSelection.cursor(empty ? from + before.length : head),
27
109
  changes: { from, to, insert },
28
110
  };
29
111
  }));
@@ -31,4 +113,4 @@ export const getKeymap = ({ key, pre = '', post = '', splitlines }) => ({
31
113
  },
32
114
  preventDefault: true,
33
115
  });
34
- export default keybindings.map(getKeymap);
116
+ export default keybindings.map(getWikiKeymap);