@bhsd/codemirror-mediawiki 3.9.2 → 3.10.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.
- package/README.md +147 -87
- package/dist/bidi.d.ts +9 -8
- package/dist/bidi.js +38 -23
- package/dist/codemirror.d.ts +7 -0
- package/dist/codemirror.js +22 -9
- package/dist/color.d.ts +8 -5
- package/dist/color.js +5 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -0
- package/dist/constants.d.ts +3 -2
- package/dist/constants.js +3 -2
- package/dist/css.d.ts +5 -0
- package/dist/css.js +14 -6
- package/dist/escape.d.ts +22 -2
- package/dist/escape.js +44 -25
- package/dist/fold.d.ts +57 -5
- package/dist/fold.js +149 -58
- package/dist/hover.d.ts +16 -3
- package/dist/hover.js +84 -67
- package/dist/html.js +17 -12
- package/dist/indent.d.ts +7 -0
- package/dist/indent.js +7 -1
- package/dist/index.d.ts +54 -16
- package/dist/index.js +91 -38
- package/dist/inlay.d.ts +1 -1
- package/dist/inlay.js +26 -25
- package/dist/javascript.d.ts +10 -1
- package/dist/javascript.js +50 -2
- package/dist/keybindings.d.ts +1 -0
- package/dist/keybindings.js +1 -0
- package/dist/keymap.d.ts +11 -0
- package/dist/keymap.js +3 -4
- package/dist/linter.d.ts +31 -2
- package/dist/linter.js +10 -3
- package/dist/lintsource.d.ts +47 -3
- package/dist/lintsource.js +50 -11
- package/dist/lua.d.ts +0 -2
- package/dist/lua.js +27 -10
- package/dist/main.min.js +31 -29
- package/dist/matchBrackets.d.ts +16 -0
- package/dist/matchBrackets.js +16 -0
- package/dist/matchTag.d.ts +5 -2
- package/dist/matchTag.js +11 -7
- package/dist/mediawiki.d.ts +15 -2
- package/dist/mediawiki.js +59 -45
- package/dist/mw.min.js +33 -37
- package/dist/mwConfig.js +2 -2
- package/dist/openLinks.d.ts +12 -2
- package/dist/openLinks.js +64 -54
- package/dist/ref.d.ts +16 -2
- package/dist/ref.js +110 -95
- package/dist/signature.d.ts +7 -1
- package/dist/signature.js +53 -49
- package/dist/static.d.ts +4 -0
- package/dist/static.js +4 -0
- package/dist/statusBar.js +9 -8
- package/dist/theme.d.ts +1 -0
- package/dist/theme.js +8 -0
- package/dist/token.d.ts +29 -7
- package/dist/token.js +33 -18
- package/dist/util.d.ts +25 -2
- package/dist/util.js +47 -1
- package/dist/wiki.min.js +32 -36
- package/i18n/en.json +2 -2
- package/i18n/zh-hans.json +2 -2
- package/i18n/zh-hant.json +2 -2
- package/package.json +15 -13
package/dist/bidi.d.ts
CHANGED
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
* @license GPL-2.0-or-later
|
|
4
4
|
* @see https://gerrit.wikimedia.org/g/mediawiki/extensions/CodeMirror
|
|
5
5
|
*/
|
|
6
|
-
import { EditorView
|
|
7
|
-
import type {
|
|
6
|
+
import { EditorView } from '@codemirror/view';
|
|
7
|
+
import type { DecorationSet } from '@codemirror/view';
|
|
8
|
+
import type { Extension } from '@codemirror/state';
|
|
9
|
+
/**
|
|
10
|
+
* 计算需要`unicode-bidi:isolate`的范围
|
|
11
|
+
* @ignore
|
|
12
|
+
* @test
|
|
13
|
+
*/
|
|
8
14
|
export declare const computeIsolates: ({ visibleRanges, state, textDirection }: EditorView) => DecorationSet;
|
|
9
|
-
declare const _default:
|
|
10
|
-
isolates: DecorationSet;
|
|
11
|
-
tree: import("@lezer/common").Tree;
|
|
12
|
-
dir: Direction;
|
|
13
|
-
update({ docChanged, viewportChanged, state, view }: ViewUpdate): void;
|
|
14
|
-
}, undefined>;
|
|
15
|
+
declare const _default: Extension[];
|
|
15
16
|
export default _default;
|
package/dist/bidi.js
CHANGED
|
@@ -7,12 +7,16 @@ import { EditorView, Direction, ViewPlugin, Decoration } from '@codemirror/view'
|
|
|
7
7
|
import { Prec, RangeSetBuilder } from '@codemirror/state';
|
|
8
8
|
import { syntaxTree } from '@codemirror/language';
|
|
9
9
|
import { tokens } from './config.js';
|
|
10
|
-
import { isolateSelector, ltrSelector } from './constants.js';
|
|
11
10
|
import { getTag } from './matchTag.js';
|
|
12
|
-
const cls = isolateSelector.slice(1), isolateLTR = Decoration.mark({
|
|
11
|
+
const isolateSelector = '.cm-bidi-isolate', ltrSelector = '.cm-bidi-ltr', cls = isolateSelector.slice(1), isolateLTR = Decoration.mark({
|
|
13
12
|
class: `${cls} ${ltrSelector.slice(1)}`,
|
|
14
13
|
bidiIsolate: Direction.LTR,
|
|
15
14
|
}), isolate = Decoration.mark({ class: cls });
|
|
15
|
+
/**
|
|
16
|
+
* 计算需要`unicode-bidi:isolate`的范围
|
|
17
|
+
* @ignore
|
|
18
|
+
* @test
|
|
19
|
+
*/
|
|
16
20
|
export const computeIsolates = ({ visibleRanges, state, textDirection }) => {
|
|
17
21
|
const set = new RangeSetBuilder();
|
|
18
22
|
if (textDirection === Direction.RTL) {
|
|
@@ -60,26 +64,37 @@ export const computeIsolates = ({ visibleRanges, state, textDirection }) => {
|
|
|
60
64
|
}
|
|
61
65
|
return set.finish();
|
|
62
66
|
};
|
|
63
|
-
export default
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.tree = syntaxTree(view.state);
|
|
67
|
-
this.dir = view.textDirection;
|
|
68
|
-
}
|
|
69
|
-
update({ docChanged, viewportChanged, state, view }) {
|
|
70
|
-
const tree = syntaxTree(state), { textDirection } = view;
|
|
71
|
-
if (docChanged || viewportChanged || tree !== this.tree || textDirection !== this.dir) {
|
|
67
|
+
export default [
|
|
68
|
+
ViewPlugin.fromClass(class {
|
|
69
|
+
constructor(view) {
|
|
72
70
|
this.isolates = computeIsolates(view);
|
|
73
|
-
this.tree =
|
|
74
|
-
this.dir = textDirection;
|
|
71
|
+
this.tree = syntaxTree(view.state);
|
|
72
|
+
this.dir = view.textDirection;
|
|
75
73
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
},
|
|
85
|
-
|
|
74
|
+
update({ docChanged, viewportChanged, state, view }) {
|
|
75
|
+
const tree = syntaxTree(state), { textDirection } = view;
|
|
76
|
+
if (docChanged || viewportChanged || tree !== this.tree || textDirection !== this.dir) {
|
|
77
|
+
this.isolates = computeIsolates(view);
|
|
78
|
+
this.tree = tree;
|
|
79
|
+
this.dir = textDirection;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}, {
|
|
83
|
+
provide(plugin) {
|
|
84
|
+
const access = (view) => view.plugin(plugin)?.isolates ?? Decoration.none;
|
|
85
|
+
return Prec.lowest([
|
|
86
|
+
EditorView.decorations.of(access),
|
|
87
|
+
EditorView.bidiIsolatedRanges.of(access),
|
|
88
|
+
]);
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
91
|
+
EditorView.theme({
|
|
92
|
+
[`${isolateSelector}, &[dir="rtl"] .cm-mw-template-name`]: {
|
|
93
|
+
unicodeBidi: 'isolate',
|
|
94
|
+
},
|
|
95
|
+
[ltrSelector]: {
|
|
96
|
+
direction: 'ltr',
|
|
97
|
+
display: 'inline-block',
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
];
|
package/dist/codemirror.d.ts
CHANGED
|
@@ -33,6 +33,12 @@ export declare const menuRegistry: MenuItem[];
|
|
|
33
33
|
export declare const destroyListeners: ((view: EditorView) => void)[];
|
|
34
34
|
export declare const themes: Record<string, Extension>;
|
|
35
35
|
export declare const optionalFunctions: OptionalFunctions;
|
|
36
|
+
/**
|
|
37
|
+
* 替换选中内容
|
|
38
|
+
* @param view
|
|
39
|
+
* @param func 用于生成替换文本和光标位置的函数
|
|
40
|
+
* @test
|
|
41
|
+
*/
|
|
36
42
|
export declare const replaceSelections: (view: EditorView, func: ReplaceFunction) => void;
|
|
37
43
|
/** CodeMirror 6 editor */
|
|
38
44
|
export declare class CodeMirror6 {
|
|
@@ -151,6 +157,7 @@ export declare class CodeMirror6 {
|
|
|
151
157
|
* Replace the current selection with the result of a function
|
|
152
158
|
* @param view EditorView instance
|
|
153
159
|
* @param func function to produce the replacement text
|
|
160
|
+
* @test
|
|
154
161
|
*/
|
|
155
162
|
static replaceSelections: (view: EditorView, func: ReplaceFunction) => void;
|
|
156
163
|
/**
|
package/dist/codemirror.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EditorView, lineNumbers, keymap, highlightActiveLineGutter } from '@codemirror/view';
|
|
2
2
|
import { EditorSelection, Compartment, EditorState, SelectionRange, } from '@codemirror/state';
|
|
3
|
-
import { syntaxHighlighting, defaultHighlightStyle, indentOnInput, indentUnit, ensureSyntaxTree, } from '@codemirror/language';
|
|
3
|
+
import { syntaxHighlighting, defaultHighlightStyle, indentOnInput, indentUnit, ensureSyntaxTree, syntaxTree, } from '@codemirror/language';
|
|
4
4
|
import { defaultKeymap, historyKeymap, history, redo, indentWithTab, insertNewlineKeepIndent, deleteCharBackwardStrict, } from '@codemirror/commands';
|
|
5
5
|
import { search, searchKeymap } from '@codemirror/search';
|
|
6
6
|
import { linter, lintGutter, lintKeymap } from '@codemirror/lint';
|
|
@@ -16,8 +16,7 @@ export const plain = () => [
|
|
|
16
16
|
];
|
|
17
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
18
|
export const languages = { plain };
|
|
19
|
-
// eslint-disable-
|
|
20
|
-
export const avail = {};
|
|
19
|
+
export const avail = {}; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
21
20
|
export const linterRegistry = {};
|
|
22
21
|
export const menuRegistry = [];
|
|
23
22
|
export const destroyListeners = [];
|
|
@@ -33,13 +32,19 @@ export const optionalFunctions = {
|
|
|
33
32
|
return () => { };
|
|
34
33
|
},
|
|
35
34
|
};
|
|
36
|
-
const editExtensions = new Set(['closeBrackets', 'autocompletion', 'signatureHelp']);
|
|
35
|
+
const editExtensions = new Set(['closeBrackets', 'autocompletion', 'signatureHelp', 'escape']);
|
|
37
36
|
const linters = {};
|
|
38
37
|
const phrases = {};
|
|
38
|
+
/**
|
|
39
|
+
* 替换选中内容
|
|
40
|
+
* @param view
|
|
41
|
+
* @param func 用于生成替换文本和光标位置的函数
|
|
42
|
+
* @test
|
|
43
|
+
*/
|
|
39
44
|
export const replaceSelections = (view, func) => {
|
|
40
45
|
const { state } = view;
|
|
41
|
-
view.dispatch(state.changeByRange(
|
|
42
|
-
const result = func(state.sliceDoc(from, to),
|
|
46
|
+
view.dispatch(state.changeByRange(range => {
|
|
47
|
+
const { from, to } = range, result = func(state.sliceDoc(from, to), range);
|
|
43
48
|
if (typeof result === 'string') {
|
|
44
49
|
return {
|
|
45
50
|
range: EditorSelection.range(from, from + result.length),
|
|
@@ -172,18 +177,18 @@ export class CodeMirror6 {
|
|
|
172
177
|
'& .cm-lineNumbers .cm-gutterElement': {
|
|
173
178
|
textAlign: 'end',
|
|
174
179
|
},
|
|
175
|
-
[`.cm-textfield
|
|
180
|
+
[`.cm-textfield, .cm-button,${panelSelector}.cm-search label,${panelSelector}.cm-gotoLine label`]: {
|
|
176
181
|
fontSize: 'inherit',
|
|
177
182
|
},
|
|
178
183
|
[`${panelSelector} [name="close"]`]: {
|
|
179
184
|
color: 'inherit',
|
|
180
185
|
},
|
|
181
186
|
}),
|
|
182
|
-
EditorView.updateListener.of(({ state
|
|
187
|
+
EditorView.updateListener.of(({ state, startState: { doc: startDoc }, docChanged, focusChanged, selectionSet, }) => {
|
|
183
188
|
if (docChanged) {
|
|
184
189
|
clearTimeout(timer);
|
|
185
190
|
timer = setTimeout(() => {
|
|
186
|
-
textarea.value = doc.toString();
|
|
191
|
+
textarea.value = state.doc.toString();
|
|
187
192
|
textarea.dispatchEvent(new InputEvent('input'));
|
|
188
193
|
}, 400);
|
|
189
194
|
if (!noDetectionLangs.has(this.#lang) && !startDoc.toString().trim()) {
|
|
@@ -193,6 +198,13 @@ export class CodeMirror6 {
|
|
|
193
198
|
if (focusChanged) {
|
|
194
199
|
textarea.dispatchEvent(new FocusEvent(this.#view.hasFocus ? 'focus' : 'blur'));
|
|
195
200
|
}
|
|
201
|
+
if (selectionSet && this.lang === 'mediawiki'
|
|
202
|
+
&& ['localhost:8080', 'bhsd-harry.github.io'].includes(location.host)) {
|
|
203
|
+
const tree = syntaxTree(state), { head } = state.selection.main, { name } = tree.resolve(head), innerName = tree.resolveInner(head).name;
|
|
204
|
+
if (name !== innerName) {
|
|
205
|
+
console.error(`Cursor at ${head}: ${name} (inner: ${innerName})`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
196
208
|
}),
|
|
197
209
|
...readOnly
|
|
198
210
|
? [
|
|
@@ -511,6 +523,7 @@ export class CodeMirror6 {
|
|
|
511
523
|
* Replace the current selection with the result of a function
|
|
512
524
|
* @param view EditorView instance
|
|
513
525
|
* @param func function to produce the replacement text
|
|
526
|
+
* @test
|
|
514
527
|
*/
|
|
515
528
|
static replaceSelections = replaceSelections;
|
|
516
529
|
}
|
package/dist/color.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { makeColorPicker } from '@bhsd/codemirror-css-color-picker';
|
|
2
|
+
import type { Extension } from '@codemirror/state';
|
|
3
|
+
/**
|
|
4
|
+
* @implements
|
|
5
|
+
* @test
|
|
6
|
+
*/
|
|
7
|
+
export declare const discoverColors: Parameters<typeof makeColorPicker>[0]['discoverColors'];
|
|
8
|
+
declare const _default: Extension[];
|
|
6
9
|
export default _default;
|
package/dist/color.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { splitColors, numToHex } from '@bhsd/common';
|
|
2
2
|
import { parseCallExpression, parseColorLiteral, ColorType, colorPickerTheme, makeColorPicker, } from '@bhsd/codemirror-css-color-picker';
|
|
3
|
+
/**
|
|
4
|
+
* @implements
|
|
5
|
+
* @test
|
|
6
|
+
*/
|
|
3
7
|
export const discoverColors = (_, from, to, type, doc) => {
|
|
4
8
|
if (!/mw-(?:(?:ext|html)tag-attribute-value|table-definition)/u.test(type)
|
|
5
9
|
&& (!/mw-(?:template|parserfunction)(?:$|_)/u.test(type)
|
|
@@ -26,7 +30,7 @@ export const discoverColors = (_, from, to, type, doc) => {
|
|
|
26
30
|
};
|
|
27
31
|
}).filter(options => options !== null);
|
|
28
32
|
};
|
|
29
|
-
export default
|
|
33
|
+
export default [
|
|
30
34
|
makeColorPicker({ discoverColors }),
|
|
31
35
|
colorPickerTheme,
|
|
32
36
|
];
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -124,6 +124,7 @@ var tokens = {
|
|
|
124
124
|
magicLink: "mw-magic-link",
|
|
125
125
|
pageName: "mw-pagename",
|
|
126
126
|
parserFunction: "mw-parserfunction",
|
|
127
|
+
parserFunctionArgumentName: "mw-parserfunction-argument-name",
|
|
127
128
|
parserFunctionBracket: "mw-parserfunction-bracket",
|
|
128
129
|
parserFunctionDelimiter: "mw-parserfunction-delimiter",
|
|
129
130
|
parserFunctionName: "mw-parserfunction-name",
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export declare const base: Record<'CDN', string | undefined>, hoverSelector = ".cm-tooltip-hover-mw", diagnosticSelector = ".cm-diagnosticText-clickable", panelSelector = ".cm-panel", panelsSelector = ".cm-panels",
|
|
2
|
-
export declare const isWMF: boolean
|
|
1
|
+
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", noDetectionLangs: Set<string>, bgDark = "#4c566a", matchingCls = "cm-matchingTag", nonmatchingCls = "cm-nonmatchingTag";
|
|
2
|
+
export declare const isWMF: boolean;
|
|
3
|
+
export declare const isMac: boolean;
|
package/dist/constants.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { wmf } from '@bhsd/common';
|
|
2
|
-
export const base = { CDN: undefined }, hoverSelector = '.cm-tooltip-hover-mw', diagnosticSelector = '.cm-diagnosticText-clickable', panelSelector = '.cm-panel', panelsSelector = '.cm-panels',
|
|
2
|
+
export const base = { CDN: undefined }, hoverSelector = '.cm-tooltip-hover-mw', diagnosticSelector = '.cm-diagnosticText-clickable', panelSelector = '.cm-panel', panelsSelector = '.cm-panels', actionSelector = '.cm-diagnosticAction', noDetectionLangs = new Set(['plain', 'mediawiki']), bgDark = '#4c566a', matchingCls = 'cm-matchingTag', nonmatchingCls = 'cm-nonmatchingTag';
|
|
3
3
|
export const isWMF = /* @__PURE__ */ (() => typeof location === 'object'
|
|
4
|
-
&& new RegExp(String.raw `\.(?:${wmf})\.org$`, 'u').test(location.hostname))()
|
|
4
|
+
&& new RegExp(String.raw `\.(?:${wmf})\.org$`, 'u').test(location.hostname))();
|
|
5
|
+
export const isMac = /* @__PURE__ */ (() => {
|
|
5
6
|
const { vendor, userAgent, maxTouchPoints, platform } = navigator;
|
|
6
7
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
7
8
|
return vendor?.includes('Apple Computer')
|
package/dist/css.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { LanguageSupport } from '@codemirror/language';
|
|
2
2
|
import type { Extension } from '@codemirror/state';
|
|
3
3
|
import type { Dialect } from './codemirror';
|
|
4
|
+
/**
|
|
5
|
+
* CSS completion source with dialect-specific adjustments.
|
|
6
|
+
* @param dialect 是否是sanitized-css
|
|
7
|
+
* @test
|
|
8
|
+
*/
|
|
4
9
|
export declare const cssCompletion: (dialect?: Dialect) => Extension;
|
|
5
10
|
declare const _default: (dialect: Dialect) => LanguageSupport;
|
|
6
11
|
export default _default;
|
package/dist/css.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { cssLanguage, cssCompletionSource } from '@codemirror/lang-css';
|
|
2
2
|
import { LanguageSupport, syntaxTree } from '@codemirror/language';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { sliceDoc } from './util.js';
|
|
4
|
+
const cssWideKeywords = /* @__PURE__ */ (() => ['revert', 'revert-layer'].map((label) => ({ label, type: 'keyword' })))();
|
|
5
|
+
/**
|
|
6
|
+
* CSS completion source with dialect-specific adjustments.
|
|
7
|
+
* @param dialect 是否是sanitized-css
|
|
8
|
+
* @test
|
|
9
|
+
*/
|
|
10
|
+
export const cssCompletion = (dialect) => {
|
|
11
|
+
const source = context => {
|
|
5
12
|
const { state, pos } = context, node = syntaxTree(state).resolveInner(pos, -1), result = cssCompletionSource(context);
|
|
6
13
|
if (result) {
|
|
7
14
|
if (node.name === 'ValueName') {
|
|
8
|
-
const options = [
|
|
15
|
+
const options = [...cssWideKeywords, ...result.options];
|
|
9
16
|
let { prevSibling } = node;
|
|
10
17
|
while (prevSibling && prevSibling.name !== 'PropertyName') {
|
|
11
18
|
({ prevSibling } = prevSibling);
|
|
@@ -13,7 +20,7 @@ export const cssCompletion = (dialect) => cssLanguage.data.of({
|
|
|
13
20
|
if (prevSibling) {
|
|
14
21
|
for (let i = 0; i < options.length; i++) {
|
|
15
22
|
const option = options[i];
|
|
16
|
-
if (CSS.supports(
|
|
23
|
+
if (CSS.supports(sliceDoc(state, prevSibling), option.label)) {
|
|
17
24
|
options.splice(i, 1, { ...option, boost: 50 });
|
|
18
25
|
}
|
|
19
26
|
}
|
|
@@ -26,6 +33,7 @@ export const cssCompletion = (dialect) => cssLanguage.data.of({
|
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
35
|
return result;
|
|
29
|
-
}
|
|
30
|
-
});
|
|
36
|
+
};
|
|
37
|
+
return cssLanguage.data.of({ autocomplete: source });
|
|
38
|
+
};
|
|
31
39
|
export default (dialect) => new LanguageSupport(cssLanguage, cssCompletion(dialect));
|
package/dist/escape.d.ts
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
|
+
import { getLSP } from '@bhsd/browser';
|
|
2
|
+
import type { EditorView } from '@codemirror/view';
|
|
1
3
|
import type { Extension } from '@codemirror/state';
|
|
2
4
|
import type { CodeMirror6 } from './codemirror';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* 转义HTML
|
|
7
|
+
* @param str 输入字符串
|
|
8
|
+
* @test
|
|
9
|
+
*/
|
|
10
|
+
export declare const escapeHTML: (str: string) => string,
|
|
11
|
+
/**
|
|
12
|
+
* 转义URI
|
|
13
|
+
* @param str 输入字符串
|
|
14
|
+
* @test
|
|
15
|
+
*/
|
|
16
|
+
escapeURI: (str: string) => string,
|
|
17
|
+
/**
|
|
18
|
+
* 使用魔术字转义选中文本
|
|
19
|
+
* @param view
|
|
20
|
+
* @param lsp LSP实例
|
|
21
|
+
* @test
|
|
22
|
+
*/
|
|
23
|
+
escapeWiki: (view: EditorView, lsp: Exclude<ReturnType<typeof getLSP>, undefined>) => Promise<void>;
|
|
24
|
+
declare const _default: (articlePath?: string) => (cm: CodeMirror6) => Extension;
|
|
5
25
|
export default _default;
|
package/dist/escape.js
CHANGED
|
@@ -5,6 +5,7 @@ import { getLSP } from '@bhsd/browser';
|
|
|
5
5
|
import elt from 'crelt';
|
|
6
6
|
import { base } from './constants.js';
|
|
7
7
|
import { replaceSelections, menuRegistry, } from './codemirror.js';
|
|
8
|
+
import { sliceDoc, toConfigGetter, } from './util.js';
|
|
8
9
|
const entity = { '"': 'quot', "'": 'apos', '<': 'lt', '>': 'gt', '&': 'amp', ' ': 'nbsp' };
|
|
9
10
|
/**
|
|
10
11
|
* 根据函数转换选中文本
|
|
@@ -18,13 +19,24 @@ const convert = (func, cmd) => (view) => {
|
|
|
18
19
|
}
|
|
19
20
|
return cmd(view);
|
|
20
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* 转义HTML
|
|
24
|
+
* @param str 输入字符串
|
|
25
|
+
* @test
|
|
26
|
+
*/
|
|
21
27
|
export const escapeHTML = (str) => [...str].map(c => {
|
|
22
28
|
if (c in entity) {
|
|
23
29
|
return `&${entity[c]};`;
|
|
24
30
|
}
|
|
25
31
|
const code = c.codePointAt(0);
|
|
26
32
|
return code < 256 ? `&#${code};` : `&#x${code.toString(16)};`;
|
|
27
|
-
}).join(''),
|
|
33
|
+
}).join(''),
|
|
34
|
+
/**
|
|
35
|
+
* 转义URI
|
|
36
|
+
* @param str 输入字符串
|
|
37
|
+
* @test
|
|
38
|
+
*/
|
|
39
|
+
escapeURI = (str) => {
|
|
28
40
|
if (str.includes('%')) {
|
|
29
41
|
try {
|
|
30
42
|
return decodeURIComponent(str);
|
|
@@ -32,28 +44,35 @@ export const escapeHTML = (str) => [...str].map(c => {
|
|
|
32
44
|
catch { }
|
|
33
45
|
}
|
|
34
46
|
return encodeURIComponent(str);
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* 使用魔术字转义选中文本
|
|
50
|
+
* @param view
|
|
51
|
+
* @param lsp LSP实例
|
|
52
|
+
* @test
|
|
53
|
+
*/
|
|
54
|
+
escapeWiki = async (view, lsp) => {
|
|
55
|
+
const { state } = view, { ranges } = state.selection, replacements = new WeakMap();
|
|
56
|
+
for (const range of ranges) {
|
|
57
|
+
// eslint-disable-next-line no-await-in-loop
|
|
58
|
+
const [action] = await lsp.provideRefactoringAction(sliceDoc(state, range));
|
|
59
|
+
replacements.set(range, action?.edit.changes[''][0].newText);
|
|
60
|
+
}
|
|
61
|
+
view.dispatch(state.changeByRange(range => {
|
|
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
|
+
};
|
|
70
|
+
}));
|
|
35
71
|
};
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
if (lsp && 'provideRefactoringAction' in lsp && ranges.some(({ empty }) => !empty)) {
|
|
39
|
-
(
|
|
40
|
-
const replacements = new WeakMap();
|
|
41
|
-
for (const range of ranges) {
|
|
42
|
-
// eslint-disable-next-line no-await-in-loop
|
|
43
|
-
const [action] = await lsp.provideRefactoringAction(state.sliceDoc(range.from, range.to));
|
|
44
|
-
replacements.set(range, action?.edit.changes[''][0].newText);
|
|
45
|
-
}
|
|
46
|
-
view.dispatch(state.changeByRange(range => {
|
|
47
|
-
const insert = replacements.get(range);
|
|
48
|
-
if (insert === undefined) {
|
|
49
|
-
return { range };
|
|
50
|
-
}
|
|
51
|
-
return {
|
|
52
|
-
range: EditorSelection.range(range.from, range.from + insert.length),
|
|
53
|
-
changes: { from: range.from, to: range.to, insert },
|
|
54
|
-
};
|
|
55
|
-
}));
|
|
56
|
-
})();
|
|
72
|
+
const escapeWikiCommand = (view, getConfig) => {
|
|
73
|
+
const lsp = getLSP(view, false, getConfig, base.CDN);
|
|
74
|
+
if (lsp && 'provideRefactoringAction' in lsp && view.state.selection.ranges.some(({ empty }) => !empty)) {
|
|
75
|
+
void escapeWiki(view, lsp);
|
|
57
76
|
return true;
|
|
58
77
|
}
|
|
59
78
|
return false;
|
|
@@ -84,7 +103,7 @@ menuRegistry.push({
|
|
|
84
103
|
if (lsp && 'provideRefactoringAction' in lsp) {
|
|
85
104
|
const btnWiki = elt('div', 'Escape with magic words');
|
|
86
105
|
btnWiki.addEventListener('click', e => {
|
|
87
|
-
|
|
106
|
+
escapeWikiCommand(view, cm.getWikiConfig);
|
|
88
107
|
handlerBase(view, e);
|
|
89
108
|
});
|
|
90
109
|
items.unshift(btnWiki);
|
|
@@ -93,13 +112,13 @@ menuRegistry.push({
|
|
|
93
112
|
return items;
|
|
94
113
|
},
|
|
95
114
|
});
|
|
96
|
-
export default (cm) => keymap.of([
|
|
115
|
+
export default (articlePath) => (cm) => keymap.of([
|
|
97
116
|
{ key: 'Mod-[', run: convert(escapeHTML, indentLess) },
|
|
98
117
|
{ key: 'Mod-]', run: convert(escapeURI, indentMore) },
|
|
99
118
|
{
|
|
100
119
|
key: 'Mod-\\',
|
|
101
120
|
run(view) {
|
|
102
|
-
return
|
|
121
|
+
return escapeWikiCommand(view, toConfigGetter(cm.getWikiConfig, articlePath));
|
|
103
122
|
},
|
|
104
123
|
},
|
|
105
124
|
]);
|
package/dist/fold.d.ts
CHANGED
|
@@ -1,25 +1,77 @@
|
|
|
1
|
-
import { EditorView } from '@codemirror/view';
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
1
|
+
import { GutterMarker, EditorView } from '@codemirror/view';
|
|
2
|
+
import { RangeSet } from '@codemirror/state';
|
|
3
|
+
import type { BlockInfo, Command } from '@codemirror/view';
|
|
4
|
+
import type { EditorState, StateEffect, Extension } from '@codemirror/state';
|
|
4
5
|
import type { SyntaxNode, Tree } from '@lezer/common';
|
|
5
6
|
export interface DocRange {
|
|
6
7
|
from: number;
|
|
7
8
|
to: number;
|
|
8
9
|
}
|
|
10
|
+
declare type AnchorUpdate = (pos: number, range: DocRange) => number;
|
|
11
|
+
export declare const updateSelection: AnchorUpdate, updateAll: AnchorUpdate;
|
|
9
12
|
/**
|
|
10
13
|
* 寻找可折叠的范围
|
|
11
14
|
* @param state
|
|
12
15
|
* @param posOrNode 字符位置或语法树节点
|
|
13
16
|
* @param tree 语法树
|
|
14
17
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
18
|
+
* @test
|
|
15
19
|
*/
|
|
16
20
|
export declare const foldable: (state: EditorState, posOrNode: number | SyntaxNode, tree?: Tree | null, refOnly?: boolean) => DocRange | false;
|
|
17
|
-
|
|
21
|
+
/**
|
|
22
|
+
* 折叠所有模板
|
|
23
|
+
* @param state
|
|
24
|
+
* @param tree 语法树
|
|
25
|
+
* @param effects 折叠
|
|
26
|
+
* @param node 语法树节点
|
|
27
|
+
* @param end 终止位置
|
|
28
|
+
* @param anchor 光标位置
|
|
29
|
+
* @param update 更新光标位置
|
|
30
|
+
* @param refOnly 是否仅检查`<ref>`标签
|
|
31
|
+
* @test
|
|
32
|
+
*/
|
|
33
|
+
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 {
|
|
35
|
+
readonly open: boolean;
|
|
36
|
+
constructor(open: boolean);
|
|
37
|
+
eq(other: this): boolean;
|
|
38
|
+
toDOM({ state }: EditorView): HTMLElement;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 寻找可折叠的行范围
|
|
42
|
+
* @ignore
|
|
43
|
+
* @test
|
|
44
|
+
*/
|
|
45
|
+
export declare const foldableLine: ({ state, viewportLineBlocks }: EditorView, { from: f, to: t }: DocRange) => DocRange | false;
|
|
46
|
+
/**
|
|
47
|
+
* 生成行号旁的折叠标记
|
|
48
|
+
* @param view
|
|
49
|
+
* @test
|
|
50
|
+
*/
|
|
51
|
+
export declare const buildMarkers: (view: EditorView) => RangeSet<FoldMarker>;
|
|
52
|
+
/**
|
|
53
|
+
* 生成折叠命令
|
|
54
|
+
* @param refOnly 是否仅检查`<ref>`标签
|
|
55
|
+
* @test
|
|
56
|
+
*/
|
|
57
|
+
export declare const foldCommand: (refOnly?: boolean) => Command;
|
|
18
58
|
export declare const foldRef: Command;
|
|
19
59
|
export declare const unfoldRef: Command;
|
|
60
|
+
/**
|
|
61
|
+
* 获取所有光标所在的行
|
|
62
|
+
* @param view
|
|
63
|
+
* @test
|
|
64
|
+
*/
|
|
65
|
+
export declare const selectedLines: (view: EditorView) => BlockInfo[];
|
|
66
|
+
/**
|
|
67
|
+
* Fold the template at the selection/cursor
|
|
68
|
+
* @param view
|
|
69
|
+
* @test
|
|
70
|
+
*/
|
|
71
|
+
export declare const foldAt: Command;
|
|
20
72
|
declare const _default: (e?: Extension | undefined) => Extension;
|
|
21
73
|
export default _default;
|
|
22
|
-
export declare const
|
|
74
|
+
export declare const mediawikiFold: Extension;
|
|
23
75
|
/**
|
|
24
76
|
* 点击提示折叠模板参数
|
|
25
77
|
* @param view
|