@bhsd/codemirror-mediawiki 3.11.5 → 3.12.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.
@@ -1,3 +1,4 @@
1
+ import type { DecorationSet } from '@codemirror/view';
1
2
  import type { Extension, EditorState } from '@codemirror/state';
2
3
  import type { Config, MatchResult } from '@codemirror/language';
3
4
  import type { SyntaxNode } from '@lezer/common';
@@ -5,6 +6,10 @@ export interface Selection {
5
6
  anchor: number;
6
7
  head: number;
7
8
  }
9
+ export interface BracketConfig extends Config {
10
+ exclude?: (state: EditorState, pos: number) => boolean;
11
+ }
12
+ export type RequiredConfig = Required<Config> & BracketConfig;
8
13
  /**
9
14
  * @ignore
10
15
  * @test
@@ -25,5 +30,15 @@ export declare const trySelectMatchingBrackets: (state: EditorState, pos: number
25
30
  * @test
26
31
  */
27
32
  export declare const selectMatchingBrackets: (state: EditorState, pos: number, config?: Config) => Selection | false;
28
- declare const _default: (configs?: Config) => Extension;
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;
43
+ declare const _default: (configs?: BracketConfig) => Extension;
29
44
  export default _default;
@@ -1,4 +1,4 @@
1
- import { Decoration, EditorView } from '@codemirror/view';
1
+ import { Decoration, EditorView, ViewPlugin } from '@codemirror/view';
2
2
  import { bracketMatching, matchBrackets, syntaxTree } from '@codemirror/language';
3
3
  /**
4
4
  * @ignore
@@ -56,50 +56,98 @@ export const selectMatchingBrackets = (state, pos, config) => trySelectMatchingB
56
56
  || trySelectMatchingBrackets(state, pos, 1, config)
57
57
  || trySelectMatchingBrackets(state, pos + 1, -1, config, true)
58
58
  || trySelectMatchingBrackets(state, pos - 1, 1, config, true);
59
+ const tryMatchBracetks = (state, pos, config) => matchBrackets(state, pos, -1, config)
60
+ || pos > 0 && matchBrackets(state, pos - 1, 1, config)
61
+ || config.afterCursor && (matchBrackets(state, pos, 1, config)
62
+ || pos < state.doc.length && matchBrackets(state, pos + 1, -1, config));
63
+ /**
64
+ * @ignore
65
+ * @test
66
+ */
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) => {
83
+ const decorations = [], { afterCursor, brackets, renderMatch, exclude, } = config;
84
+ for (const { empty, head } of state.selection.ranges) {
85
+ if (!empty) {
86
+ continue;
87
+ }
88
+ const tree = syntaxTree(state), excluded = exclude?.(state, head), match = !excluded && // eslint-disable-line @stylistic/operator-linebreak
89
+ tryMatchBracetks(state, head, config)
90
+ || findEnclosingBrackets(tree.resolveInner(head, -1), head, brackets)
91
+ || afterCursor && findEnclosingBrackets(tree.resolveInner(head, 1), head, brackets)
92
+ || // eslint-disable-line @stylistic/operator-linebreak
93
+ !excluded && // eslint-disable-line @stylistic/operator-linebreak
94
+ findEnclosingPlainBrackets(state, head, config);
95
+ if (match) {
96
+ decorations.push(...renderMatch(match, state));
97
+ }
98
+ }
99
+ return Decoration.set(decorations, true);
100
+ };
101
+ const clickHandler = (e, view, facet, select) => {
102
+ const pos = view.posAtCoords(e), { state } = view, config = state.facet(facet);
103
+ if (pos === null
104
+ || config.exclude?.(state, pos)) {
105
+ return false;
106
+ }
107
+ const selection = select(state, pos, config);
108
+ if (selection) {
109
+ view.dispatch({ selection });
110
+ return true;
111
+ }
112
+ return false;
113
+ };
59
114
  export default (configs) => {
60
- const extension = bracketMatching(configs), [{ facet }, [field]] = extension;
61
- Object.assign(field, {
62
- updateF(value, { state, docChanged, selection }) {
63
- if (!docChanged && !selection) {
64
- return value;
65
- }
66
- const decorations = [], config = state.facet(facet), { afterCursor, brackets, renderMatch } = config;
67
- for (const { empty, head } of state.selection.ranges) {
68
- if (!empty) {
69
- continue;
115
+ const extension = bracketMatching(configs), [{ facet }, plugins] = extension;
116
+ plugins[0] = ViewPlugin.fromClass(class {
117
+ constructor({ state }) {
118
+ this.decorations = bracketDeco(state, state.facet(facet));
119
+ this.paused = false;
120
+ }
121
+ update({ docChanged, selectionSet, changes, state, view: { composing } }) {
122
+ if (docChanged || selectionSet || this.paused) {
123
+ if (composing) {
124
+ this.decorations = this.decorations.map(changes);
125
+ this.paused = true;
70
126
  }
71
- const tree = syntaxTree(state), match = matchBrackets(state, head, -1, config)
72
- || head > 0 && matchBrackets(state, head - 1, 1, config)
73
- || afterCursor && (matchBrackets(state, head, 1, config)
74
- || head < state.doc.length && matchBrackets(state, head + 1, -1, config))
75
- || findEnclosingBrackets(tree.resolveInner(head, -1), head, brackets)
76
- || afterCursor && findEnclosingBrackets(tree.resolveInner(head, 1), head, brackets)
77
- || findEnclosingPlainBrackets(state, head, config);
78
- if (match) {
79
- decorations.push(...renderMatch(match, state));
127
+ else {
128
+ this.decorations = bracketDeco(state, state.facet(facet));
129
+ this.paused = false;
80
130
  }
81
131
  }
82
- return Decoration.set(decorations, true);
132
+ }
133
+ }, {
134
+ decorations({ decorations }) {
135
+ return decorations;
83
136
  },
84
137
  });
85
138
  return [
86
139
  extension,
87
140
  EditorView.domEventHandlers({
141
+ /** @ignore */
142
+ click(e, view) {
143
+ return e.detail === 3 && clickHandler(e, view, facet, selectLineBlock);
144
+ },
88
145
  /**
89
146
  * @ignore
90
147
  * @todo 由于括号高亮的重绘,双击会被识别为两次单击,导致功能失效
91
148
  */
92
149
  dblclick(e, view) {
93
- const pos = view.posAtCoords(e);
94
- if (pos === null) {
95
- return false;
96
- }
97
- const { state } = view, selection = selectMatchingBrackets(state, pos, state.facet(facet));
98
- if (selection) {
99
- view.dispatch({ selection });
100
- return true;
101
- }
102
- return false;
150
+ return clickHandler(e, view, facet, selectMatchingBrackets);
103
151
  },
104
152
  }),
105
153
  ];
@@ -28,6 +28,12 @@ export declare class Tag {
28
28
  * @test
29
29
  */
30
30
  export declare const getTag: (state: EditorState, node: SyntaxNode) => Tag | null;
31
+ /**
32
+ * 搜索匹配的标签
33
+ * @param state
34
+ * @param origin 起始标签
35
+ */
36
+ export declare const searchTag: (state: EditorState, origin: Tag) => Tag | null;
31
37
  /**
32
38
  * 匹配标签
33
39
  * @param state
package/dist/matchTag.js CHANGED
@@ -3,7 +3,7 @@ import { StateField } from '@codemirror/state';
3
3
  import { ensureSyntaxTree } from '@codemirror/language';
4
4
  import { voidHtmlTags, selfClosingTags } from './config.js';
5
5
  import { matchingCls, nonmatchingCls } from './constants.js';
6
- import { sliceDoc } from './util.js';
6
+ import { sliceDoc, pushDecoration } from './util.js';
7
7
  /** @test */
8
8
  export class Tag {
9
9
  get closing() {
@@ -66,7 +66,7 @@ export const getTag = (state, node) => {
66
66
  * @param state
67
67
  * @param origin 起始标签
68
68
  */
69
- const searchTag = (state, origin) => {
69
+ export const searchTag = (state, origin) => {
70
70
  const { type, name, closing } = origin, siblingGetter = closing ? 'prevSibling' : 'nextSibling', endGetter = closing ? 'first' : 'last';
71
71
  let stack = closing ? -1 : 1, sibling = origin[endGetter][siblingGetter];
72
72
  while (sibling) {
@@ -128,15 +128,15 @@ 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: { from, to, closing }, end } = match;
132
- decorations.push(mark.range(from, to));
131
+ const mark = match.matched ? matchingMark : nonmatchingMark, { start, end } = match;
132
+ pushDecoration(decorations, mark, start);
133
133
  if (end) {
134
- decorations[closing ? 'unshift' : 'push'](mark.range(end.from, end.to));
134
+ pushDecoration(decorations, mark, end);
135
135
  }
136
136
  }
137
137
  }
138
138
  }
139
- return Decoration.set(decorations);
139
+ return Decoration.set(decorations, true);
140
140
  },
141
141
  provide(f) {
142
142
  return EditorView.decorations.from(f);
@@ -30,7 +30,7 @@ export declare const apply: (view: EditorView, completion: Completion, from: num
30
30
  * @param names 指定类型
31
31
  * @test
32
32
  */
33
- export declare const hasTag: (types: Set<string>, names: TagName | TagName[]) => boolean;
33
+ export declare const hasTag: (types: Set<string> | string, names: TagName | TagName[]) => boolean;
34
34
  /** @test */
35
35
  export declare class FullMediaWiki extends MediaWiki {
36
36
  #private;
package/dist/mediawiki.js CHANGED
@@ -48,7 +48,12 @@ export const apply = (view, completion, from, to) => {
48
48
  * @param names 指定类型
49
49
  * @test
50
50
  */
51
- export const hasTag = (types, names) => (Array.isArray(names) ? names : [names]).some(name => types.has(name in tokens ? tokens[name] : name));
51
+ export const hasTag = (types, names) => {
52
+ if (typeof types === 'string') {
53
+ types = new Set(types.split('_'));
54
+ }
55
+ return (Array.isArray(names) ? names : [names]).some(name => types.has(name in tokens ? tokens[name] : name));
56
+ };
52
57
  /** @test */
53
58
  export class FullMediaWiki extends MediaWiki {
54
59
  constructor(config, templatedata = false) {
@@ -399,7 +404,7 @@ const theme = /* @__PURE__ */ EditorView.theme({
399
404
  fontSize: '1.5em',
400
405
  lineHeight: '1.2em',
401
406
  },
402
- [getSelector(['3~*', '4~*', '5~*', '6~*'], 'section--')]: {
407
+ [getSelector(['3', '3~*', '4', '4~*', '5', '5~*', '6', '6~*'], 'section--')]: {
403
408
  fontWeight: 'bold',
404
409
  },
405
410
  [`${getSelector(['section-header', 'template', 'parserfunction', 'file-delimiter', 'magic-link'])},${getSelector(['pagename', 'bracket', 'delimiter'], 'link-')},${getSelector(['extlink'], ['', 'free-'])},${getSelector(['bracket', 'attribute'], ['exttag-', 'htmltag-'])},${getSelector(['delimiter2', 'definition'], 'table-')}`]: {