@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
@@ -25,20 +25,12 @@ export declare const findEnclosingPlainBrackets: (state: EditorState, pos: numbe
25
25
  * @test
26
26
  */
27
27
  export declare const trySelectMatchingBrackets: (state: EditorState, pos: number, dir: 1 | -1, config?: Config, inside?: boolean) => Selection | false;
28
+ /** @test */
29
+ export declare const customSelection: Record<number, (state: EditorState, pos: number, config?: Config) => Selection | false>;
28
30
  /**
29
31
  * @ignore
30
32
  * @test
31
33
  */
32
- export declare const selectMatchingBrackets: (state: EditorState, pos: number, config?: Config) => Selection | false;
33
- /**
34
- * @ignore
35
- * @test
36
- */
37
- export declare const selectLineBlock: (state: EditorState, pos: number, config?: Config) => Selection | false;
38
- /**
39
- * @ignore
40
- * @test
41
- */
42
- export declare const bracketDeco: (state: EditorState, config: RequiredConfig) => DecorationSet;
34
+ export declare const myBracketDeco: (state: EditorState, config: RequiredConfig) => DecorationSet;
43
35
  declare const _default: (configs?: BracketConfig) => Extension;
44
36
  export default _default;
@@ -1,4 +1,5 @@
1
1
  import { Decoration, EditorView, ViewPlugin } from '@codemirror/view';
2
+ import { EditorSelection } from '@codemirror/state';
2
3
  import { bracketMatching, matchBrackets, syntaxTree } from '@codemirror/language';
3
4
  /**
4
5
  * @ignore
@@ -48,14 +49,25 @@ export const trySelectMatchingBrackets = (state, pos, dir, config, inside = fals
48
49
  head: match.end[rightInside ? 'from' : 'to'],
49
50
  };
50
51
  };
51
- /**
52
- * @ignore
53
- * @test
54
- */
55
- export const selectMatchingBrackets = (state, pos, config) => trySelectMatchingBrackets(state, pos, -1, config)
56
- || trySelectMatchingBrackets(state, pos, 1, config)
57
- || trySelectMatchingBrackets(state, pos + 1, -1, config, true)
58
- || trySelectMatchingBrackets(state, pos - 1, 1, config, true);
52
+ /** @test */
53
+ export const customSelection = {
54
+ 0: state => ({ anchor: 0, head: state.doc.length }),
55
+ 2: (state, pos, config) => trySelectMatchingBrackets(state, pos, -1, config)
56
+ || trySelectMatchingBrackets(state, pos, 1, config)
57
+ || trySelectMatchingBrackets(state, pos + 1, -1, config, true)
58
+ || trySelectMatchingBrackets(state, pos - 1, 1, config, true),
59
+ 3: (state, pos, config) => {
60
+ const { doc } = state, matching = tryMatchBracetks(state, pos, { ...config, afterCursor: true });
61
+ if (!matching || !matching.matched) {
62
+ return false;
63
+ }
64
+ const { start, end } = matching, a = doc.lineAt(start.from), b = doc.lineAt(end.from), dir = a.from < b.from;
65
+ return {
66
+ anchor: (dir ? a : b).from,
67
+ head: Math.min(doc.length, (dir ? b : a).to + 1),
68
+ };
69
+ },
70
+ };
59
71
  const tryMatchBracetks = (state, pos, config) => matchBrackets(state, pos, -1, config)
60
72
  || pos > 0 && matchBrackets(state, pos - 1, 1, config)
61
73
  || config.afterCursor && (matchBrackets(state, pos, 1, config)
@@ -64,22 +76,7 @@ const tryMatchBracetks = (state, pos, config) => matchBrackets(state, pos, -1, c
64
76
  * @ignore
65
77
  * @test
66
78
  */
67
- export const selectLineBlock = (state, pos, config) => {
68
- const { doc } = state, matching = tryMatchBracetks(state, pos, { ...config, afterCursor: true });
69
- if (!matching || !matching.matched) {
70
- return false;
71
- }
72
- const { start, end } = matching, a = doc.lineAt(start.from), b = doc.lineAt(end.from), dir = a.from < b.from;
73
- return {
74
- anchor: (dir ? a : b).from,
75
- head: Math.min(doc.length, (dir ? b : a).to + 1),
76
- };
77
- };
78
- /**
79
- * @ignore
80
- * @test
81
- */
82
- export const bracketDeco = (state, config) => {
79
+ export const myBracketDeco = (state, config) => {
83
80
  const decorations = [], { afterCursor, brackets, renderMatch, exclude, } = config;
84
81
  for (const { empty, head } of state.selection.ranges) {
85
82
  if (!empty) {
@@ -100,14 +97,15 @@ export const bracketDeco = (state, config) => {
100
97
  };
101
98
  const clickHandler = (e, view, facet, select) => {
102
99
  const pos = view.posAtCoords(e), { state } = view, config = state.facet(facet);
103
- if (pos === null
104
- || config.exclude?.(state, pos)) {
100
+ if (select !== customSelection[0] && (pos === null
101
+ || config.exclude?.(state, pos))) {
105
102
  return false;
106
103
  }
107
- const selection = select(state, pos, config);
108
- if (selection) {
104
+ const range = select(state, pos, config);
105
+ if (range) {
106
+ const selection = EditorSelection.single(range.anchor, range.head);
109
107
  view.dispatch({ selection });
110
- return true;
108
+ return selection;
111
109
  }
112
110
  return false;
113
111
  };
@@ -115,7 +113,7 @@ export default (configs) => {
115
113
  const extension = bracketMatching(configs), [{ facet }, plugins] = extension;
116
114
  plugins[0] = ViewPlugin.fromClass(class {
117
115
  constructor({ state }) {
118
- this.decorations = bracketDeco(state, state.facet(facet));
116
+ this.decorations = myBracketDeco(state, state.facet(facet));
119
117
  this.paused = false;
120
118
  }
121
119
  update({ docChanged, selectionSet, changes, state, view: { composing } }) {
@@ -125,7 +123,7 @@ export default (configs) => {
125
123
  this.paused = true;
126
124
  }
127
125
  else {
128
- this.decorations = bracketDeco(state, state.facet(facet));
126
+ this.decorations = myBracketDeco(state, state.facet(facet));
129
127
  this.paused = false;
130
128
  }
131
129
  }
@@ -135,19 +133,33 @@ export default (configs) => {
135
133
  return decorations;
136
134
  },
137
135
  });
136
+ let selection = false;
138
137
  return [
139
138
  extension,
140
139
  EditorView.domEventHandlers({
141
140
  /** @ignore */
142
- click(e, view) {
143
- return e.detail === 3 && clickHandler(e, view, facet, selectLineBlock);
141
+ mousedown(e, view) {
142
+ const n = e.detail % 4;
143
+ selection = e.detail > 0 && n in customSelection && clickHandler(e, view, facet, customSelection[n]);
144
+ return Boolean(selection);
144
145
  },
145
- /**
146
- * @ignore
147
- * @todo 由于括号高亮的重绘,双击会被识别为两次单击,导致功能失效
148
- */
149
- dblclick(e, view) {
150
- return clickHandler(e, view, facet, selectMatchingBrackets);
146
+ /** @ignore */
147
+ mouseup() {
148
+ selection = false;
149
+ },
150
+ /** @ignore */
151
+ mousemove(e, view) {
152
+ if (!selection) {
153
+ return false;
154
+ }
155
+ const head = view.posAtCoords(e), { from, to } = selection.main;
156
+ if (head === null || head >= from && head <= to) {
157
+ return false;
158
+ }
159
+ view.dispatch({
160
+ selection: { head, anchor: head < from ? to : from },
161
+ });
162
+ return true;
151
163
  },
152
164
  }),
153
165
  ];
@@ -5,11 +5,11 @@ import type { MatchResult } from '@codemirror/language';
5
5
  import type { SyntaxNode } from '@lezer/common';
6
6
  declare type TagType = 'ext' | 'html';
7
7
  export interface TagMatchResult extends MatchResult {
8
- start: Tag;
9
- end?: Tag;
8
+ start: WikiTag;
9
+ end?: WikiTag;
10
10
  }
11
11
  /** @test */
12
- export declare class Tag {
12
+ export declare class WikiTag {
13
13
  readonly type: TagType;
14
14
  readonly name: string;
15
15
  readonly first: SyntaxNode;
@@ -27,13 +27,13 @@ export declare class Tag {
27
27
  * @param node 语法树节点
28
28
  * @test
29
29
  */
30
- export declare const getTag: (state: EditorState, node: SyntaxNode) => Tag | null;
30
+ export declare const getTag: (state: EditorState, node: SyntaxNode) => WikiTag | null;
31
31
  /**
32
32
  * 搜索匹配的标签
33
33
  * @param state
34
34
  * @param origin 起始标签
35
35
  */
36
- export declare const searchTag: (state: EditorState, origin: Tag) => Tag | null;
36
+ export declare const searchTag: (state: EditorState, origin: WikiTag) => WikiTag | null;
37
37
  /**
38
38
  * 匹配标签
39
39
  * @param state
package/dist/matchTag.js CHANGED
@@ -5,7 +5,7 @@ import { voidHtmlTags, selfClosingTags } from './config.js';
5
5
  import { matchingCls, nonmatchingCls } from './constants.js';
6
6
  import { sliceDoc, pushDecoration } from './util.js';
7
7
  /** @test */
8
- export class Tag {
8
+ export class WikiTag {
9
9
  get closing() {
10
10
  return isClosing(this.first, this.type, this.state, true);
11
11
  }
@@ -59,7 +59,7 @@ export const getTag = (state, node) => {
59
59
  ({ prevSibling } = prevSibling);
60
60
  }
61
61
  const name = getName(state, nameNode);
62
- return new Tag(type, name, prevSibling, nextSibling, state);
62
+ return new WikiTag(type, name, prevSibling, nextSibling, state);
63
63
  };
64
64
  /**
65
65
  * 搜索匹配的标签
@@ -114,7 +114,7 @@ export const matchTag = (state, pos) => {
114
114
  const end = searchTag(state, start);
115
115
  return end ? { matched: true, start, end } : { matched: false, start };
116
116
  };
117
- const matchingMark = /* @__PURE__ */ Decoration.mark({ class: matchingCls }), nonmatchingMark = /* @__PURE__ */ Decoration.mark({ class: nonmatchingCls });
117
+ const matchingTag = /* @__PURE__ */ Decoration.mark({ class: matchingCls }), nonmatchingTag = /* @__PURE__ */ Decoration.mark({ class: nonmatchingCls });
118
118
  export default /* @__PURE__ */ StateField.define({
119
119
  create() {
120
120
  return Decoration.none;
@@ -128,7 +128,7 @@ export default /* @__PURE__ */ StateField.define({
128
128
  if (range.empty) {
129
129
  const match = matchTag(state, range.head);
130
130
  if (match) {
131
- const mark = match.matched ? matchingMark : nonmatchingMark, { start, end } = match;
131
+ const mark = match.matched ? matchingTag : nonmatchingTag, { start, end } = match;
132
132
  pushDecoration(decorations, mark, start);
133
133
  if (end) {
134
134
  pushDecoration(decorations, mark, end);
package/dist/math.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { StreamParser } from '@codemirror/language';
2
+ /** @test */
3
+ export declare const math: StreamParser<object>;
package/dist/math.js ADDED
@@ -0,0 +1,58 @@
1
+ import { extCompletion, extData } from './constants.js';
2
+ import { getCompletions } from './util.js';
3
+ let mathFetch;
4
+ /** @test */
5
+ export const math = {
6
+ startState() {
7
+ if (typeof wikiparse === 'object') {
8
+ mathFetch ??= (async () => {
9
+ const data = await (await fetch(`${wikiparse.CDN}/data/ext/math.json`)).json();
10
+ extData['math'] = new Set(data);
11
+ extCompletion['math'] = getCompletions(data);
12
+ })();
13
+ }
14
+ return {};
15
+ },
16
+ token(stream) {
17
+ if (stream.eatSpace()) {
18
+ return '';
19
+ }
20
+ const ch = stream.next();
21
+ switch (ch) {
22
+ case '\\':
23
+ if (stream.eatWhile(/[a-z]/iu)) {
24
+ return extData['math']?.has(stream.current()) === false ? '' : /* #708 */ 'keyword';
25
+ }
26
+ else if (stream.eat(/[,;!\\]/u)) {
27
+ return /* #708 */ 'keyword';
28
+ }
29
+ return stream.eat(/[$&%#{}_]/u) ? /* #219 */ 'atom' : /* #f00 */ 'invalid';
30
+ case '^':
31
+ case '_':
32
+ case '&':
33
+ return 'operator';
34
+ case '{':
35
+ case '}':
36
+ return 'brace';
37
+ case '[':
38
+ case ']':
39
+ return 'squareBracket';
40
+ case '(':
41
+ case ')':
42
+ return 'paren';
43
+ case '.':
44
+ return stream.eatWhile(/\d/u) ? /* #164 */ 'number' : '';
45
+ default:
46
+ if (/\d/u.test(ch)) {
47
+ stream.match(/\d*(?:\.\d*)?/u);
48
+ return /* #164 */ 'number';
49
+ }
50
+ else if (/[a-z]/iu.test(ch)) {
51
+ stream.eatWhile(/[a-z]/iu);
52
+ return /* #256 */ 'variableName.special';
53
+ }
54
+ stream.eatWhile(/[^\\^&{}[\]().\w]/u);
55
+ return '';
56
+ }
57
+ },
58
+ };
@@ -6,7 +6,7 @@
6
6
  import { LanguageSupport } from '@codemirror/language';
7
7
  import { EditorView } from '@codemirror/view';
8
8
  import { MediaWiki } from './token.js';
9
- import type { StreamParser, TagStyle } from '@codemirror/language';
9
+ import type { TagStyle } from '@codemirror/language';
10
10
  import type { CompletionSource, Completion } from '@codemirror/autocomplete';
11
11
  import type { MwConfig } from './token';
12
12
  import type { TagName } from './config';
@@ -43,7 +43,7 @@ export declare class FullMediaWiki extends MediaWiki {
43
43
  readonly protocols: Completion[];
44
44
  readonly imgKeys: Completion[];
45
45
  readonly htmlAttrs: Completion[];
46
- readonly elementAttrs: Map<string | undefined, Completion[]>;
46
+ readonly elementAttrs: Map<string, Completion[]>;
47
47
  readonly extAttrs: Map<string, Completion[]>;
48
48
  constructor(config: MwConfig, templatedata?: boolean);
49
49
  /**
@@ -52,7 +52,6 @@ export declare class FullMediaWiki extends MediaWiki {
52
52
  * @see https://codemirror.net/docs/ref/#language.TagStyle
53
53
  */
54
54
  getTagStyles(): TagStyle[];
55
- mediawiki(tags?: string[]): StreamParser<any>;
56
55
  /** 自动补全魔术字和标签名 */
57
56
  get completionSource(): CompletionSource;
58
57
  }
package/dist/mediawiki.js CHANGED
@@ -9,9 +9,10 @@ import { insertCompletionText, pickedCompletion } from '@codemirror/autocomplete
9
9
  import { isUnderscore } from '@bhsd/cm-util';
10
10
  import { commonHtmlAttrs, htmlAttrs, extAttrs } from 'wikiparser-node/dist/util/sharable.mjs';
11
11
  import { htmlTags, tokens } from './config.js';
12
- import { hoverSelector, isWMF, } from './constants.js';
12
+ import { hoverSelector, extCompletion, isWMF, } from './constants.js';
13
+ import { lightHighlightStyle } from './theme.js';
13
14
  import { MediaWiki } from './token.js';
14
- import { leadingSpaces, findTemplateName } from './util.js';
15
+ import { getCompletions, getExtTags, leadingSpaces, findTemplateName, } from './util.js';
15
16
  const ranks = { Required: 1, Suggested: 2, Optional: 3, Deprecated: 4 };
16
17
  /**
17
18
  * 是否是普通维基链接
@@ -66,15 +67,9 @@ export class FullMediaWiki extends MediaWiki {
66
67
  type: i ? 'constant' : 'function',
67
68
  label,
68
69
  })));
69
- this.doubleUnderscore = doubleUnderscore.flatMap(Object.keys).filter(isUnderscore).map((label) => ({
70
- type: 'constant',
71
- label,
72
- }));
73
- this.extTags = this.tags.map((label) => ({ type: 'type', label }));
74
- this.htmlTags = htmlTags.filter(tag => !this.tags.includes(tag)).map((label) => ({
75
- type: 'type',
76
- label,
77
- }));
70
+ this.doubleUnderscore = getCompletions(doubleUnderscore.flatMap(Object.keys).filter(isUnderscore), 'constant');
71
+ this.extTags = getCompletions(this.tags, 'type');
72
+ this.htmlTags = getCompletions(htmlTags.filter(tag => !this.tags.includes(tag)), 'type');
78
73
  this.protocols = urlProtocols.split('|').map((label) => ({
79
74
  type: 'namespace',
80
75
  label: label.replace(/\\\//gu, '/'),
@@ -83,17 +78,17 @@ export class FullMediaWiki extends MediaWiki {
83
78
  ? { type: 'property', label: label.slice(0, -2), detail: '$1' }
84
79
  : { type: 'keyword', label });
85
80
  this.htmlAttrs = [
86
- ...[...commonHtmlAttrs].map((label) => ({ type: 'property', label })),
81
+ ...getCompletions([...commonHtmlAttrs], 'property'),
87
82
  { type: 'variable', label: 'data-', detail: '*' },
88
83
  { type: 'namespace', label: 'xmlns:', detail: '*' },
89
84
  ];
90
85
  this.elementAttrs = new Map(Object.entries(htmlAttrs).map(([key, value]) => [
91
86
  key,
92
- [...value].map((label) => ({ type: 'property', label })),
87
+ getCompletions([...value], 'property'),
93
88
  ]));
94
89
  this.extAttrs = new Map(Object.entries(extAttrs).map(([key, value]) => [
95
90
  key,
96
- [...value].map((label) => ({ type: 'property', label })),
91
+ getCompletions([...value], 'property'),
97
92
  ]));
98
93
  }
99
94
  /**
@@ -107,13 +102,6 @@ export class FullMediaWiki extends MediaWiki {
107
102
  class: `cm-${className}`,
108
103
  }));
109
104
  }
110
- mediawiki(tags) {
111
- const parser = super.mediawiki(tags);
112
- parser.languageData = {
113
- closeBrackets: { brackets: ['(', '[', '{', '"'], before: ')]}>' },
114
- };
115
- return parser;
116
- }
117
105
  /**
118
106
  * 提供链接建议
119
107
  * @param str 搜索字符串,开头不包含` `,但可能包含`_`
@@ -311,6 +299,26 @@ export class FullMediaWiki extends MediaWiki {
311
299
  // 不可能是状态开关、标签、协议或图片参数名
312
300
  return null;
313
301
  }
302
+ else if ('math' in extCompletion
303
+ && hasTag(types, ['mw-tag-math', 'mw-tag-chem', 'mw-tag-ce'])
304
+ && (types.size === 1 || types.has('keyword') || types.has('invalid'))) {
305
+ const mt = context.matchBefore(/\\[a-z]*$/iu);
306
+ return mt && {
307
+ from: mt.from,
308
+ options: extCompletion['math'],
309
+ validFor: /^[a-z]*$/iu,
310
+ };
311
+ }
312
+ else if ('score' in extCompletion
313
+ && hasTag(types, 'mw-tag-score')
314
+ && (types.size === 1 || types.has('keyword'))) {
315
+ const mt = context.matchBefore(/\\[-a-z]*$/iu);
316
+ return mt && {
317
+ from: mt.from,
318
+ options: extCompletion['score'],
319
+ validFor: /^[-a-z]*$/iu,
320
+ };
321
+ }
314
322
  let mt = context.matchBefore(/__(?:(?!__)[\p{L}\p{N}_])*$/u);
315
323
  if (mt) {
316
324
  return {
@@ -320,8 +328,7 @@ export class FullMediaWiki extends MediaWiki {
320
328
  };
321
329
  }
322
330
  mt = context.matchBefore(/<\/?[a-z\d]*$/iu);
323
- const extTags = [...types].filter(type => type.startsWith('mw-tag-'))
324
- .map(s => s.slice(7));
331
+ const extTags = getExtTags([...types]);
325
332
  if (mt && (explicit || mt.to - mt.from > 1)) {
326
333
  const validFor = /^[a-z\d]*$/iu;
327
334
  if (mt.text[1] === '/') {
@@ -395,7 +402,7 @@ const getGrounds = (grounds, r, g, b, a) => ({
395
402
  * @license GPL-2.0-or-later
396
403
  * @see https://gerrit.wikimedia.org/g/mediawiki/extensions/CodeMirror
397
404
  */
398
- const theme = /* @__PURE__ */ EditorView.theme({
405
+ const wikiTheme = /* @__PURE__ */ EditorView.theme({
399
406
  [getSelector(['', '~*'], 'section--1')]: {
400
407
  fontSize: '1.8em',
401
408
  lineHeight: '1.2em',
@@ -484,7 +491,7 @@ const theme = /* @__PURE__ */ EditorView.theme({
484
491
  '.cm-mw-entity': {
485
492
  color: 'var(--cm-entity)',
486
493
  },
487
- '.cm-mw-exttag': {
494
+ '.cm-mw-exttag,.cm-mw-tag-score-scheme': {
488
495
  backgroundColor: 'rgb(119,0,170,.04)',
489
496
  },
490
497
  /* eslint-disable no-sparse-arrays */
@@ -546,8 +553,9 @@ const theme = /* @__PURE__ */ EditorView.theme({
546
553
  export const mediawikiBase = (config, templatedata) => {
547
554
  const mode = new FullMediaWiki(config, templatedata), lang = StreamLanguage.define(mode.mediawiki());
548
555
  return new LanguageSupport(lang, [
556
+ lightHighlightStyle,
549
557
  syntaxHighlighting(HighlightStyle.define(mode.getTagStyles())),
550
- theme,
558
+ wikiTheme,
551
559
  lang.data.of({ autocomplete: mode.completionSource }),
552
560
  ]);
553
561
  };