@bhsd/codemirror-mediawiki 2.1.15 → 2.2.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 +50 -4
- package/dist/codemirror.d.ts +13 -0
- package/dist/escape.d.ts +2 -0
- package/dist/main.min.js +12 -12
- package/dist/main.min.js.map +4 -4
- package/dist/mw.min.js +1 -1
- package/dist/mw.min.js.map +4 -4
- package/mw/base.ts +73 -39
- package/mw/config.ts +1 -1
- package/mw/msg.ts +34 -0
- package/mw/preference.ts +81 -0
- package/package.json +2 -2
- package/src/codemirror.ts +58 -25
- package/src/escape.ts +28 -0
package/src/codemirror.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {Compartment, EditorState} from '@codemirror/state';
|
|
1
|
+
import {Compartment, EditorState, EditorSelection} from '@codemirror/state';
|
|
2
2
|
import {
|
|
3
3
|
EditorView,
|
|
4
4
|
lineNumbers,
|
|
@@ -23,9 +23,10 @@ import {searchKeymap} from '@codemirror/search';
|
|
|
23
23
|
import {linter, lintGutter, openLintPanel, closeLintPanel, lintKeymap} from '@codemirror/lint';
|
|
24
24
|
import {closeBrackets} from '@codemirror/autocomplete';
|
|
25
25
|
import {mediawiki, html} from './mediawiki';
|
|
26
|
+
import {keyMap} from './escape';
|
|
26
27
|
import * as plugins from './plugins';
|
|
27
|
-
import type {ViewPlugin} from '@codemirror/view';
|
|
28
|
-
import type {Extension, Text} from '@codemirror/state';
|
|
28
|
+
import type {ViewPlugin, KeyBinding} from '@codemirror/view';
|
|
29
|
+
import type {Extension, Text, StateEffect} from '@codemirror/state';
|
|
29
30
|
import type {Diagnostic} from '@codemirror/lint';
|
|
30
31
|
import type {Highlighter} from '@lezer/highlight';
|
|
31
32
|
import type {Linter} from 'eslint';
|
|
@@ -60,8 +61,13 @@ const avail: Record<string, [(config?: any) => Extension, Record<string, unknown
|
|
|
60
61
|
],
|
|
61
62
|
{},
|
|
62
63
|
],
|
|
64
|
+
escape: [
|
|
65
|
+
(keys: KeyBinding[] = []): Extension => keymap.of(keys),
|
|
66
|
+
{mediawiki: keyMap},
|
|
67
|
+
],
|
|
63
68
|
};
|
|
64
|
-
|
|
69
|
+
|
|
70
|
+
export const CDN = 'https://testingcf.jsdelivr.net';
|
|
65
71
|
|
|
66
72
|
/**
|
|
67
73
|
* 使用传统方法加载脚本
|
|
@@ -96,6 +102,7 @@ export class CodeMirror6 {
|
|
|
96
102
|
readonly #linter = new Compartment();
|
|
97
103
|
readonly #extensions = new Compartment();
|
|
98
104
|
readonly #indent = new Compartment();
|
|
105
|
+
readonly #extraKeys = new Compartment();
|
|
99
106
|
#lang;
|
|
100
107
|
#visible = false;
|
|
101
108
|
#preferred = new Set<string>();
|
|
@@ -130,6 +137,7 @@ export class CodeMirror6 {
|
|
|
130
137
|
this.#linter.of([]),
|
|
131
138
|
this.#extensions.of([]),
|
|
132
139
|
this.#indent.of(indentUnit.of('\t')),
|
|
140
|
+
this.#extraKeys.of([]),
|
|
133
141
|
syntaxHighlighting(defaultHighlightStyle as Highlighter),
|
|
134
142
|
EditorView.contentAttributes.of({
|
|
135
143
|
accesskey: textarea.accessKey,
|
|
@@ -168,6 +176,14 @@ export class CodeMirror6 {
|
|
|
168
176
|
this.toggle(true);
|
|
169
177
|
}
|
|
170
178
|
|
|
179
|
+
/**
|
|
180
|
+
* 修改扩展
|
|
181
|
+
* @param effects 扩展变动
|
|
182
|
+
*/
|
|
183
|
+
#effects(effects: StateEffect<unknown> | StateEffect<unknown>[]): void {
|
|
184
|
+
this.#view.dispatch({effects});
|
|
185
|
+
}
|
|
186
|
+
|
|
171
187
|
/** 刷新编辑器高度 */
|
|
172
188
|
#refresh(): void {
|
|
173
189
|
const {offsetHeight} = this.#textarea;
|
|
@@ -203,14 +219,13 @@ export class CodeMirror6 {
|
|
|
203
219
|
* @param config 语言设置
|
|
204
220
|
*/
|
|
205
221
|
setLanguage(lang = 'plain', config?: unknown): void {
|
|
206
|
-
this.#
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
],
|
|
211
|
-
});
|
|
222
|
+
this.#effects([
|
|
223
|
+
this.#language.reconfigure(languages[lang]!(config)),
|
|
224
|
+
this.#linter.reconfigure(linters[lang] || []),
|
|
225
|
+
]);
|
|
212
226
|
this.#lang = lang;
|
|
213
227
|
this.#toggleLintPanel(Boolean(linters[lang]));
|
|
228
|
+
this.prefer({});
|
|
214
229
|
}
|
|
215
230
|
|
|
216
231
|
/**
|
|
@@ -229,9 +244,7 @@ export class CodeMirror6 {
|
|
|
229
244
|
} else {
|
|
230
245
|
delete linters[this.#lang];
|
|
231
246
|
}
|
|
232
|
-
this.#
|
|
233
|
-
effects: [this.#linter.reconfigure(linterExtension)],
|
|
234
|
-
});
|
|
247
|
+
this.#effects(this.#linter.reconfigure(linterExtension));
|
|
235
248
|
this.#toggleLintPanel(Boolean(lintSource));
|
|
236
249
|
}
|
|
237
250
|
|
|
@@ -261,14 +274,12 @@ export class CodeMirror6 {
|
|
|
261
274
|
}
|
|
262
275
|
}
|
|
263
276
|
}
|
|
264
|
-
this.#
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
],
|
|
271
|
-
});
|
|
277
|
+
this.#effects(
|
|
278
|
+
this.#extensions.reconfigure([...this.#preferred].map(name => {
|
|
279
|
+
const [extension, configs] = avail[name]!;
|
|
280
|
+
return extension(configs[this.#lang]);
|
|
281
|
+
})),
|
|
282
|
+
);
|
|
272
283
|
}
|
|
273
284
|
|
|
274
285
|
/**
|
|
@@ -276,16 +287,14 @@ export class CodeMirror6 {
|
|
|
276
287
|
* @param indent 缩进字符串
|
|
277
288
|
*/
|
|
278
289
|
setIndent(indent: string): void {
|
|
279
|
-
this.#
|
|
280
|
-
effects: [this.#indent.reconfigure(indentUnit.of(indent))],
|
|
281
|
-
});
|
|
290
|
+
this.#effects(this.#indent.reconfigure(indentUnit.of(indent)));
|
|
282
291
|
}
|
|
283
292
|
|
|
284
293
|
/** 获取默认linter */
|
|
285
294
|
async getLinter(opt?: Record<string, unknown>): Promise<LintSource | undefined> {
|
|
286
295
|
switch (this.#lang) {
|
|
287
296
|
case 'mediawiki': {
|
|
288
|
-
const REPO = 'npm/wikiparser-node@1.4.
|
|
297
|
+
const REPO = 'npm/wikiparser-node@1.4.3-b',
|
|
289
298
|
DIR = `${REPO}/extensions/dist`,
|
|
290
299
|
src = `combine/${DIR}/base.min.js,${DIR}/lint.min.js`,
|
|
291
300
|
lang = opt?.['i18n'];
|
|
@@ -471,4 +480,28 @@ export class CodeMirror6 {
|
|
|
471
480
|
}
|
|
472
481
|
this.#visible = show;
|
|
473
482
|
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* 添加额外快捷键
|
|
486
|
+
* @param keys 快捷键
|
|
487
|
+
*/
|
|
488
|
+
extraKeys(keys: KeyBinding[]): void {
|
|
489
|
+
this.#effects(this.#extraKeys.reconfigure(keymap.of(keys)));
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* 替换选中内容
|
|
494
|
+
* @param view EditorView
|
|
495
|
+
* @param func 替换函数
|
|
496
|
+
*/
|
|
497
|
+
static replaceSelections(view: EditorView, func: (str: string) => string): void {
|
|
498
|
+
const {state} = view;
|
|
499
|
+
view.dispatch(state.update(state.changeByRange(({from, to}) => {
|
|
500
|
+
const insert = func(state.sliceDoc(from, to));
|
|
501
|
+
return {
|
|
502
|
+
range: EditorSelection.cursor(from + insert.length),
|
|
503
|
+
changes: {from, to, insert},
|
|
504
|
+
};
|
|
505
|
+
})));
|
|
506
|
+
}
|
|
474
507
|
}
|
package/src/escape.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {CodeMirror6} from './codemirror';
|
|
2
|
+
import type {KeyBinding, Command} from '@codemirror/view';
|
|
3
|
+
|
|
4
|
+
const entity = {'"': 'quot', "'": 'apos', '<': 'lt', '>': 'gt', '&': 'amp', ' ': 'nbsp'};
|
|
5
|
+
const convert = (func: (str: string) => string): Command => (view): true => {
|
|
6
|
+
CodeMirror6.replaceSelections(view, func);
|
|
7
|
+
return true;
|
|
8
|
+
},
|
|
9
|
+
escapeHTML = convert(str => [...str].map(c => {
|
|
10
|
+
if (c in entity) {
|
|
11
|
+
return `&${entity[c as keyof typeof entity]};`;
|
|
12
|
+
}
|
|
13
|
+
const code = c.codePointAt(0)!;
|
|
14
|
+
return code < 256 ? `&#${code};` : `&#x${code.toString(16)};`;
|
|
15
|
+
}).join('')),
|
|
16
|
+
escapeURI = convert(str => {
|
|
17
|
+
if (str.includes('%')) {
|
|
18
|
+
try {
|
|
19
|
+
return decodeURIComponent(str);
|
|
20
|
+
} catch {}
|
|
21
|
+
}
|
|
22
|
+
return encodeURIComponent(str);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const keyMap: KeyBinding[] = [
|
|
26
|
+
{key: 'Mod-[', run: escapeHTML},
|
|
27
|
+
{key: 'Mod-]', run: escapeURI},
|
|
28
|
+
];
|