@bhsd/codemirror-mediawiki 3.5.2 → 3.6.0

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.
@@ -2,7 +2,6 @@ import { EditorView } from '@codemirror/view';
2
2
  import type { Extension } from '@codemirror/state';
3
3
  import type { CodeMirror6 } from './codemirror';
4
4
  import type { MwConfig } from './token';
5
- export declare const isMac: boolean;
6
5
  export declare const mouseEventListener: (e: MouseEvent, view: EditorView, langConfig: MwConfig | undefined) => string | undefined;
7
6
  declare const _default: ({ langConfig }: CodeMirror6) => Extension;
8
7
  export default _default;
package/dist/openLinks.js CHANGED
@@ -1,18 +1,14 @@
1
1
  import { EditorView } from '@codemirror/view';
2
2
  import { ensureSyntaxTree } from '@codemirror/language';
3
3
  import { tokens } from './config';
4
- import { hasTag } from './mediawiki';
5
- const { vendor, userAgent, maxTouchPoints, platform } = navigator;
6
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
7
- export const isMac = vendor?.includes('Apple Computer')
8
- && (userAgent.includes('Mobile/') || maxTouchPoints > 2)
9
- || platform.includes('Mac');
10
- const modKey = isMac ? 'metaKey' : 'ctrlKey', key = isMac ? 'Meta' : 'Control', tags = ['extLinkProtocol', 'extLink', 'freeExtLinkProtocol', 'freeExtLink', 'magicLink', 'pageName'], links = ['extlink-protocol', 'extlink', 'free-extlink-protocol', 'free-extlink', 'magic-link'], wikiLinks = [
4
+ import { isMac } from './constants';
5
+ import { hasTag } from './util';
6
+ const modKey = isMac ? 'metaKey' : 'ctrlKey', key = isMac ? 'Meta' : 'Control', tags = ['extLinkProtocol', 'extLink', 'freeExtLinkProtocol', 'freeExtLink', 'magicLink', 'pageName'], links = ['extlink-protocol', 'extlink', 'free-extlink-protocol', 'free-extlink', 'magic-link'], pagename = '.cm-mw-pagename', wikiLinks = [
11
7
  'template-name',
12
8
  'link-pagename',
13
- 'parserfunction.cm-mw-pagename',
14
- 'exttag-attribute-value.cm-mw-pagename',
15
- 'file-text.cm-mw-pagename',
9
+ `parserfunction${pagename}`,
10
+ `exttag-attribute-value${pagename}`,
11
+ `file-text${pagename}`,
16
12
  ];
17
13
  const toggleOpenLinks = (toggle) => {
18
14
  for (const ele of document.querySelectorAll('.cm-content')) {
package/dist/ref.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { hoverTooltip, EditorView } from '@codemirror/view';
2
- import { ensureSyntaxTree } from '@codemirror/language';
2
+ import { ensureSyntaxTree, language, highlightingFor } from '@codemirror/language';
3
+ import { highlightCode } from '@lezer/highlight';
3
4
  import { getLSP } from '@bhsd/browser';
4
5
  import elt from 'crelt';
5
- import { getTag } from './matchTag';
6
6
  import { tokens } from './config';
7
- import { indexToPos, posToIndex } from './hover';
8
- const trees = new WeakMap();
7
+ import { getTag } from './matchTag';
8
+ import { indexToPos, posToIndex, escHTML } from './util';
9
+ const trees = new WeakMap(), selector = '.cm-tooltip-ref', noDef = '.cm-tooltip-no-def';
9
10
  /**
10
11
  * 获取节点内容
11
12
  * @param state
@@ -50,20 +51,33 @@ export default (cm) => [
50
51
  end: to,
51
52
  above: true,
52
53
  create() {
53
- const dom = elt('div', { class: 'cm-tooltip-ref' });
54
+ const dom = elt('div', { class: selector.slice(1) });
54
55
  dom.style.font = getComputedStyle(view.contentDOM).font;
55
56
  if (ref) {
56
- const { range: { start, end } } = ref[0], anchor = posToIndex(doc, start), head = posToIndex(doc, end);
57
- dom.textContent = state.sliceDoc(anchor, head);
57
+ const { range: { start, end } } = ref[0], anchor = posToIndex(doc, start), head = posToIndex(doc, end), text = state.sliceDoc(anchor, head);
58
+ let result = '';
59
+ highlightCode(text, state.facet(language).parser.parse(text), {
60
+ style(tags) {
61
+ return highlightingFor(state, tags);
62
+ },
63
+ }, (code, classes) => {
64
+ const escaped = escHTML(code);
65
+ result += classes ? `<span class="${classes}">${escaped}</span>` : escaped;
66
+ }, () => {
67
+ result += '<br>';
68
+ });
69
+ dom.innerHTML = result;
58
70
  dom.addEventListener('click', () => {
59
71
  view.dispatch({
60
72
  selection: { anchor, head },
61
73
  scrollIntoView: true,
62
74
  });
75
+ view.focus();
63
76
  });
64
77
  }
65
78
  else {
66
79
  dom.textContent = state.phrase('No definition found');
80
+ dom.classList.add(noDef.slice(1));
67
81
  }
68
82
  return { dom };
69
83
  },
@@ -83,12 +97,15 @@ export default (cm) => [
83
97
  }
84
98
  }),
85
99
  EditorView.theme({
86
- '.cm-tooltip-ref': {
100
+ [selector]: {
87
101
  padding: '2px 5px',
88
102
  width: 'max-content',
89
103
  maxWidth: '60vw',
90
104
  cursor: 'pointer',
91
105
  whiteSpace: 'pre-wrap',
92
106
  },
107
+ [noDef]: {
108
+ color: 'var(--cm-comment)',
109
+ },
93
110
  }),
94
111
  ];
package/dist/signature.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { EditorView, showTooltip } from '@codemirror/view';
2
2
  import { StateField, StateEffect } from '@codemirror/state';
3
3
  import { getLSP } from '@bhsd/browser';
4
- import { indexToPos, createTooltipView } from './hover';
4
+ import { createTooltipView, indexToPos } from './util';
5
5
  const stateEffect = StateEffect.define(), field = StateField.define({
6
6
  create() {
7
7
  return undefined;
package/dist/statusBar.js CHANGED
@@ -2,16 +2,17 @@ import { showPanel, EditorView } from '@codemirror/view';
2
2
  import { nextDiagnostic, setDiagnosticsEffect } from '@codemirror/lint';
3
3
  import elt from 'crelt';
4
4
  import { menuRegistry } from './codemirror';
5
- const optionAll = elt('div', 'Fix all auto-fixable problems');
5
+ import { panelSelector, diagnosticSelector, menuSelector, messageSelector, actionSelector } from './constants';
6
+ const statusSelector = '.cm-panel-status', workerSelector = '.cm-status-worker', errorSelector = '.cm-status-error', warningSelector = '.cm-status-warning', enabledSelector = '.cm-status-fix-enabled', disabledSelector = '.cm-status-fix-disabled', workerCls = 'cm-status-worker-enabled', lineCls = 'cm-status-line';
6
7
  function getLintMarker(view, severity, menu) {
7
8
  const marker = elt('div', { class: `cm-status-${severity}` }), icon = elt('div');
8
9
  if (severity === 'fix') {
9
- icon.className = 'cm-status-fix-disabled';
10
+ icon.className = disabledSelector.slice(1);
10
11
  marker.title = 'Fix all';
11
12
  marker.append(icon);
12
13
  if (menu) {
13
14
  marker.addEventListener('click', ({ clientX, clientY }) => {
14
- if (icon.className === 'cm-status-fix-enabled') {
15
+ if (icon.className === enabledSelector.slice(1)) {
15
16
  const { bottom, left } = view.dom.getBoundingClientRect();
16
17
  menu.style.bottom = `${bottom - clientY + 5}px`;
17
18
  menu.style.left = `${clientX - 20 - left}px`;
@@ -25,7 +26,7 @@ function getLintMarker(view, severity, menu) {
25
26
  icon.className = `cm-lint-marker-${severity}`;
26
27
  marker.append(icon, elt('div', '0'));
27
28
  marker.addEventListener('click', () => {
28
- if (marker.parentElement?.classList.contains('cm-status-worker-enabled')) {
29
+ if (marker.parentElement?.classList.contains(workerCls)) {
29
30
  nextDiagnostic(view);
30
31
  view.focus();
31
32
  }
@@ -37,8 +38,8 @@ const updateDiagnosticsCount = (diagnostics, s, marker) => {
37
38
  marker.lastChild.textContent = String(diagnostics.filter(({ severity }) => severity === s).length);
38
39
  };
39
40
  const toggleClass = (classList, enabled) => {
40
- classList.toggle('cm-status-fix-enabled', enabled);
41
- classList.toggle('cm-status-fix-disabled', !enabled);
41
+ classList.toggle(enabledSelector.slice(1), enabled);
42
+ classList.toggle(disabledSelector.slice(1), !enabled);
42
43
  };
43
44
  const getDiagnostics = (all, main) => all.filter(({ from, to }) => from <= main.to && to >= main.from);
44
45
  const updateDiagnosticMessage = (cm, allDiagnostics, main, msg) => {
@@ -51,7 +52,7 @@ const updateDiagnosticMessage = (cm, allDiagnostics, main, msg) => {
51
52
  msg.textContent = diagnostic.message;
52
53
  if (diagnostic.actions) {
53
54
  msg.append(...diagnostic.actions.map(({ name, apply }) => {
54
- const button = elt('button', { type: 'button', class: 'cm-diagnosticAction' }, name);
55
+ const button = elt('button', { type: 'button', class: actionSelector.slice(1) }, name);
55
56
  button.addEventListener('click', e => {
56
57
  e.preventDefault();
57
58
  apply(view, diagnostic.from, diagnostic.to);
@@ -61,7 +62,7 @@ const updateDiagnosticMessage = (cm, allDiagnostics, main, msg) => {
61
62
  }
62
63
  }
63
64
  };
64
- const updateMenu = (cm, allDiagnostics, main, classList, menu, fixer) => {
65
+ const updateMenu = (cm, allDiagnostics, main, classList, optionAll, menu, fixer) => {
65
66
  if (menu) {
66
67
  const actionable = menuRegistry.filter(({ name, isActionable }) => cm.hasPreference(name) && isActionable(cm)), fixable = new Set(fixer && getDiagnostics(allDiagnostics, main).filter(({ actions }) => actions?.some(({ name }) => name === 'fix'
67
68
  || name !== 'Fix: Stylelint' && name.startsWith('Fix:'))).map(({ message }) => / \(([^()]+)\)$/u.exec(message)?.[1])
@@ -82,13 +83,12 @@ const updateMenu = (cm, allDiagnostics, main, classList, menu, fixer) => {
82
83
  menu.replaceChildren(...actions, ...quickfix);
83
84
  }
84
85
  };
85
- const panelSelector = '.cm-panel-status', workerSelector = '.cm-status-worker', errorSelector = '.cm-status-error', warningSelector = '.cm-status-warning', enabledSelector = '.cm-status-fix-enabled', disabledSelector = '.cm-status-fix-disabled', menuSelector = '.cm-status-fix-menu', messageSelector = '.cm-status-message';
86
86
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
87
87
  export default (cm, fixer) => [
88
88
  showPanel.of(view => {
89
89
  let diagnostics = [], menu;
90
90
  if (!view.state.readOnly && (fixer || menuRegistry.length > 0)) {
91
- menu = elt('div', { class: 'cm-status-fix-menu', tabIndex: -1 });
91
+ menu = elt('div', { class: menuSelector.slice(1), tabIndex: -1 });
92
92
  if (fixer) {
93
93
  menu.addEventListener('click', ({ target }) => {
94
94
  if (target === menu) {
@@ -110,7 +110,7 @@ export default (cm, fixer) => [
110
110
  });
111
111
  view.dom.append(menu);
112
112
  }
113
- const error = getLintMarker(view, 'error'), warning = getLintMarker(view, 'warning'), fix = getLintMarker(view, 'fix', menu), worker = elt('div', { class: 'cm-status-worker' }, error, warning, fix), message = elt('div', { class: 'cm-status-message' }), position = elt('div', { class: 'cm-status-line' }, '0:0'), dom = elt('div', { class: 'cm-panel cm-panel-status' }, worker, message, position), { classList } = fix.firstChild;
113
+ const error = getLintMarker(view, 'error'), warning = getLintMarker(view, 'warning'), fix = getLintMarker(view, 'fix', menu), optionAll = elt('div', 'Fix all auto-fixable problems'), worker = elt('div', { class: workerSelector.slice(1) }, error, warning, fix), message = elt('div', { class: messageSelector.slice(1) }), position = elt('div', { class: lineCls }, '0:0'), dom = elt('div', { class: `${panelSelector.slice(1)} ${statusSelector.slice(1)}` }, worker, message, position), { classList } = fix.firstChild;
114
114
  return {
115
115
  dom,
116
116
  update({ state: { selection: { main }, doc }, transactions, docChanged, selectionSet }) {
@@ -118,17 +118,17 @@ export default (cm, fixer) => [
118
118
  for (const effect of tr.effects) {
119
119
  if (effect.is(setDiagnosticsEffect)) {
120
120
  diagnostics = effect.value;
121
- worker.classList.toggle('cm-status-worker-enabled', diagnostics.length > 0);
121
+ worker.classList.toggle(workerCls, diagnostics.length > 0);
122
122
  updateDiagnosticsCount(diagnostics, 'error', error);
123
123
  updateDiagnosticsCount(diagnostics, 'warning', warning);
124
124
  updateDiagnosticMessage(cm, diagnostics, main, message);
125
- updateMenu(cm, diagnostics, main, classList, menu, fixer);
125
+ updateMenu(cm, diagnostics, main, classList, optionAll, menu, fixer);
126
126
  }
127
127
  }
128
128
  }
129
129
  if (docChanged || selectionSet) {
130
130
  updateDiagnosticMessage(cm, diagnostics, main, message);
131
- updateMenu(cm, diagnostics, main, classList, menu, fixer);
131
+ updateMenu(cm, diagnostics, main, classList, optionAll, menu, fixer);
132
132
  const { number, from } = doc.lineAt(main.head);
133
133
  position.textContent = `${number}:${main.head - from}`;
134
134
  if (!main.empty) {
@@ -139,10 +139,10 @@ export default (cm, fixer) => [
139
139
  };
140
140
  }),
141
141
  EditorView.theme({
142
- [panelSelector]: {
142
+ [statusSelector]: {
143
143
  lineHeight: 1.4,
144
144
  },
145
- [`${panelSelector}>div`]: {
145
+ [`${statusSelector}>div`]: {
146
146
  padding: '0 .3em',
147
147
  display: 'table-cell',
148
148
  },
@@ -163,7 +163,7 @@ export default (cm, fixer) => [
163
163
  [`${errorSelector},${warningSelector}`]: {
164
164
  paddingRight: '8px',
165
165
  },
166
- [`.cm-status-worker-enabled ${errorSelector},.cm-status-worker-enabled ${warningSelector}`]: {
166
+ [`.${workerCls} ${errorSelector},.${workerCls} ${warningSelector}`]: {
167
167
  cursor: 'pointer',
168
168
  },
169
169
  [`${workerSelector}>*>div`]: {
@@ -210,14 +210,14 @@ export default (cm, fixer) => [
210
210
  borderWidth: '0 1px',
211
211
  width: '100%',
212
212
  },
213
- [`${messageSelector} .cm-diagnosticAction`]: {
213
+ [`${messageSelector} ${actionSelector}`]: {
214
214
  paddingTop: 0,
215
215
  paddingBottom: 0,
216
216
  },
217
- '.cm-status-line': {
217
+ [`.${lineCls}`]: {
218
218
  whiteSpace: 'nowrap',
219
219
  },
220
- '.cm-diagnosticText-clickable': {
220
+ [diagnosticSelector]: {
221
221
  cursor: 'pointer',
222
222
  },
223
223
  }),
package/dist/theme.js CHANGED
@@ -1,29 +1,10 @@
1
1
  import { EditorView } from '@codemirror/view';
2
2
  import { nord as nordBase } from 'cm6-theme-nord';
3
+ import { foldSelector, hoverSelector, matchingCls, nonmatchingCls, menuSelector, messageSelector, actionSelector, panelsSelector, } from './constants';
4
+ const focused = '&.cm-focused', matching = `${focused} .${matchingCls}`, nonmatching = `${focused} .${nonmatchingCls}`, code = `${hoverSelector} code`, menuHover = `${menuSelector}>div:hover`;
3
5
  export const light = /* @__PURE__ */ EditorView.theme({
4
6
  '&': {
5
7
  backgroundColor: '#fff',
6
- },
7
- '&.cm-focused .cm-matchingTag': {
8
- backgroundColor: 'rgb(50,140,130,.32)',
9
- },
10
- '&.cm-focused .cm-nonmatchingTag': {
11
- backgroundColor: 'rgb(187,85,85,.27)',
12
- },
13
- '.cm-tooltip-hover code': {
14
- backgroundColor: '#e0e6eb',
15
- },
16
- '.cm-status-fix-menu': {
17
- backgroundColor: '#f5f5f5',
18
- boxShadow: '0 2px 2px 0 rgb(0,0,0,.25)',
19
- },
20
- '.cm-status-fix-menu>div:hover': {
21
- backgroundColor: '#e2f2ff',
22
- },
23
- '.cm-status-message': {
24
- borderColor: '#c8ccd1',
25
- },
26
- '.cm-content': {
27
8
  '--cm-arg': '#b0c',
28
9
  '--cm-attr': '#179b1c',
29
10
  '--cm-comment': '#7b8c8f',
@@ -43,39 +24,77 @@ export const light = /* @__PURE__ */ EditorView.theme({
43
24
  '--cm-var': '#ad9300',
44
25
  '--cm-var-name': '#ac6600',
45
26
  },
27
+ [matching]: {
28
+ backgroundColor: 'rgb(50,140,130,.32)',
29
+ },
30
+ [nonmatching]: {
31
+ backgroundColor: 'rgb(187,85,85,.27)',
32
+ },
33
+ [code]: {
34
+ backgroundColor: '#e0e6eb',
35
+ },
36
+ [menuSelector]: {
37
+ backgroundColor: '#f5f5f5',
38
+ boxShadow: '0 2px 2px 0 rgb(0,0,0,.25)',
39
+ },
40
+ [menuHover]: {
41
+ backgroundColor: '#e2f2ff',
42
+ },
43
+ [messageSelector]: {
44
+ borderColor: '#c8ccd1',
45
+ },
46
46
  }),
47
47
  /**
48
48
  * @author 鬼影233
49
49
  * @author Bhsd
50
50
  * @see https://zh.moegirl.org.cn/User:%E9%AC%BC%E5%BD%B1233/nord-moeskin.css
51
51
  */
52
- nord = [
52
+ nord = /* @__PURE__ */ (() => [
53
53
  nordBase,
54
- /* @__PURE__ */ EditorView.theme({
54
+ EditorView.theme({
55
+ '&': {
56
+ '--cm-arg': '#9f78a5',
57
+ '--cm-attr': '#97b757',
58
+ '--cm-comment': '#4c566a',
59
+ '--cm-convert': '#b68',
60
+ '--cm-entity': '#00a1a1',
61
+ '--cm-error': '#bf616a',
62
+ '--cm-func': '#bf616a',
63
+ '--cm-hr': '#5e81ac',
64
+ '--cm-hr-bg': '#3b4252',
65
+ '--cm-link': '#5e81ac',
66
+ '--cm-sect': '#81a1c1',
67
+ '--cm-sp': '#88c0d0',
68
+ '--cm-table': '#b48ead',
69
+ '--cm-table-attr': '#9f78a5',
70
+ '--cm-tag': '#a3be8c',
71
+ '--cm-tpl': '#9f78a5',
72
+ '--cm-var': '#d08770',
73
+ '--cm-var-name': '#d08770',
74
+ },
55
75
  'div.cm-activeLine': {
56
76
  backgroundColor: 'rgb(76,86,106,.27)',
57
77
  },
58
- '&.cm-focused .cm-matchingTag': {
78
+ [matching]: {
59
79
  backgroundColor: '#eceff4',
60
80
  color: '#434c5e',
61
81
  },
62
- '&.cm-focused .cm-nonmatchingTag': {
82
+ [nonmatching]: {
63
83
  backgroundColor: 'rgb(235,203,139,.32)',
64
84
  },
65
- ['&.cm-focused>.cm-scroller>.cm-selectionLayer div.cm-selectionBackground,'
66
- + '.cm-tooltip-hover code, .cm-status-fix-menu>div:hover, .cm-diagnosticAction, div.cm-tooltip-fold']: {
85
+ [`${focused}>.cm-scroller>.cm-selectionLayer div.cm-selectionBackground, ${code}, ${menuHover}, ${actionSelector}, div${foldSelector}`]: {
67
86
  backgroundColor: '#4c566a',
68
87
  },
69
- 'div.cm-panels': {
88
+ [`div${panelsSelector}`]: {
70
89
  color: '#d8dee9',
71
90
  },
72
- '.cm-status-fix-menu': {
91
+ [menuSelector]: {
73
92
  backgroundColor: '#252a33',
74
93
  },
75
- '.cm-status-message': {
94
+ [messageSelector]: {
76
95
  borderColor: '#000',
77
96
  },
78
- '&.cm-focused .cm-searchMatch.cm-searchMatch-selected': {
97
+ [`${focused} .cm-searchMatch.cm-searchMatch-selected`]: {
79
98
  color: '#b48ead',
80
99
  },
81
100
  'div.cm-tooltip-autocomplete ul li[aria-selected]': {
@@ -84,25 +103,5 @@ nord = [
84
103
  'div.cm-gutters': {
85
104
  color: '#5e81ac',
86
105
  },
87
- '.cm-content': {
88
- '--cm-arg': '#9f78a5',
89
- '--cm-attr': '#97b757',
90
- '--cm-comment': '#4c566a',
91
- '--cm-convert': '#b68',
92
- '--cm-entity': '#00a1a1',
93
- '--cm-error': '#bf616a',
94
- '--cm-func': '#bf616a',
95
- '--cm-hr': '#5e81ac',
96
- '--cm-hr-bg': '#3b4252',
97
- '--cm-link': '#5e81ac',
98
- '--cm-sect': '#81a1c1',
99
- '--cm-sp': '#88c0d0',
100
- '--cm-table': '#b48ead',
101
- '--cm-table-attr': '#9f78a5',
102
- '--cm-tag': '#a3be8c',
103
- '--cm-tpl': '#9f78a5',
104
- '--cm-var': '#d08770',
105
- '--cm-var-name': '#d08770',
106
- },
107
106
  }),
108
- ];
107
+ ])();
package/dist/token.d.ts CHANGED
@@ -49,14 +49,16 @@ declare interface StringStream extends StringStreamBase {
49
49
  match(pattern: RegExp, consume?: boolean): RegExpMatchArray | null;
50
50
  }
51
51
  export type TagName = keyof typeof tokens;
52
- export type ApiSuggestions = [string, string?][];
52
+ export type ApiSuggestions = [string, string?][] & {
53
+ description?: string;
54
+ };
53
55
  /**
54
56
  * 获取维基链接建议
55
57
  * @param search 搜索字符串,开头不包含` `
56
- * @param namespace 命名空间
57
58
  * @param subpage 是否为子页面
59
+ * @param namespace 命名空间
58
60
  */
59
- export type ApiSuggest = (search: string, namespace?: number, subpage?: boolean) => ApiSuggestions | Promise<ApiSuggestions>;
61
+ export type ApiSuggest = (search: string, subpage?: boolean, namespace?: number) => ApiSuggestions | Promise<ApiSuggestions>;
60
62
  export interface MwConfig extends MwConfigBase {
61
63
  nsid: Record<string, number>;
62
64
  variants?: string[];
package/dist/util.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ import type { EditorView, TooltipView } from '@codemirror/view';
2
+ import type { Text, EditorState } from '@codemirror/state';
3
+ import type { SyntaxNode } from '@lezer/common';
4
+ import type { Position } from 'vscode-languageserver-types';
5
+ /**
6
+ * 转义HTML字符串
7
+ * @param text 原字符串
8
+ */
9
+ export declare const escHTML: (text: string) => string;
10
+ /**
11
+ * 将索引转换为位置
12
+ * @param doc Text 实例
13
+ * @param index 索引
14
+ */
15
+ export declare const indexToPos: (doc: Text, index: number) => Position;
16
+ /**
17
+ * 将位置转换为索引
18
+ * @param doc Text 实例
19
+ * @param pos 位置
20
+ */
21
+ export declare const posToIndex: (doc: Text, pos: Position) => number;
22
+ /**
23
+ * 创建 TooltipView
24
+ * @param view EditorView 实例
25
+ * @param innerHTML 提示内容
26
+ */
27
+ export declare const createTooltipView: (view: EditorView, innerHTML: string) => TooltipView;
28
+ /**
29
+ * Update the stack of opening (+) or closing (-) brackets
30
+ * @param state
31
+ * @param node 语法树节点
32
+ */
33
+ export declare const braceStackUpdate: (state: EditorState, node: SyntaxNode) => [number, number];
34
+ /**
35
+ * 判断节点是否包含指定类型
36
+ * @param types 节点类型
37
+ * @param names 指定类型
38
+ */
39
+ export declare const hasTag: (types: Set<string>, names: string | string[]) => boolean;
package/dist/util.js ADDED
@@ -0,0 +1,53 @@
1
+ import elt from 'crelt';
2
+ import { tokens } from './config';
3
+ import { hoverSelector } from './constants';
4
+ const dict = { '\n': '<br>', '&': '&amp;', '<': '&lt;' };
5
+ /**
6
+ * 转义HTML字符串
7
+ * @param text 原字符串
8
+ */
9
+ export const escHTML = (text) => text.replace(/[\n<&]/gu, ch => dict[ch]);
10
+ /**
11
+ * 将索引转换为位置
12
+ * @param doc Text 实例
13
+ * @param index 索引
14
+ */
15
+ export const indexToPos = (doc, index) => {
16
+ const line = doc.lineAt(index);
17
+ return { line: line.number - 1, character: index - line.from };
18
+ };
19
+ /**
20
+ * 将位置转换为索引
21
+ * @param doc Text 实例
22
+ * @param pos 位置
23
+ */
24
+ export const posToIndex = (doc, pos) => {
25
+ const line = doc.line(pos.line + 1);
26
+ return Math.min(line.from + pos.character, line.to);
27
+ };
28
+ /**
29
+ * 创建 TooltipView
30
+ * @param view EditorView 实例
31
+ * @param innerHTML 提示内容
32
+ */
33
+ export const createTooltipView = (view, innerHTML) => {
34
+ const inner = elt('div'), dom = elt('div', { class: hoverSelector.slice(1) }, inner);
35
+ dom.style.font = getComputedStyle(view.contentDOM).font;
36
+ inner.innerHTML = innerHTML;
37
+ return { dom };
38
+ };
39
+ /**
40
+ * Update the stack of opening (+) or closing (-) brackets
41
+ * @param state
42
+ * @param node 语法树节点
43
+ */
44
+ export const braceStackUpdate = (state, node) => {
45
+ const brackets = state.sliceDoc(node.from, node.to);
46
+ return [brackets.split('{{').length - 1, 1 - brackets.split('}}').length];
47
+ };
48
+ /**
49
+ * 判断节点是否包含指定类型
50
+ * @param types 节点类型
51
+ * @param names 指定类型
52
+ */
53
+ export const hasTag = (types, names) => (Array.isArray(names) ? names : [names]).some(name => types.has(name in tokens ? tokens[name] : name));
package/dist/vue.js CHANGED
@@ -2,8 +2,8 @@ import { vue } from '@codemirror/lang-vue';
2
2
  import { htmlLanguage, htmlCompletionSource } from '@codemirror/lang-html';
3
3
  import { javascript } from '@codemirror/lang-javascript';
4
4
  import { LanguageSupport } from '@codemirror/language';
5
- import { jsCompletion } from './javascript';
6
5
  import { cssCompletion } from './css';
6
+ import { jsCompletion } from './javascript';
7
7
  export default () => vue({
8
8
  base: new LanguageSupport(htmlLanguage, [
9
9
  htmlLanguage.data.of({ autocomplete: htmlCompletionSource }),