@bhsd/codemirror-mediawiki 2.30.2 → 2.31.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.
- package/README.md +7 -3
- package/dist/bidi.d.ts +1 -1
- package/dist/codemirror.d.ts +3 -2
- package/dist/codemirror.js +18 -28
- package/dist/config.js +1 -2
- package/dist/fold.js +11 -4
- package/dist/hover.js +3 -5
- package/dist/inlay.js +1 -1
- package/dist/linter.d.ts +1 -1
- package/dist/linter.js +5 -4
- package/dist/lsp.d.ts +3 -0
- package/dist/lsp.js +34 -0
- package/dist/main.min.js +20 -20
- package/dist/mediawiki.js +3 -2
- package/dist/mw.min.js +24 -24
- package/dist/mwConfig.js +2 -2
- package/dist/ref.js +1 -1
- package/dist/signature.js +1 -1
- package/dist/token.d.ts +13 -11
- package/dist/token.js +73 -47
- package/dist/wiki.min.js +24 -24
- package/i18n/en.json +1 -1
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/package.json +15 -9
package/README.md
CHANGED
|
@@ -396,6 +396,7 @@ cm.scrollTo();
|
|
|
396
396
|
*version added: 2.1.8*
|
|
397
397
|
|
|
398
398
|
**param**: `string` new content
|
|
399
|
+
**param**: `boolean` whether to force the content to be set in the read-only mode, default as false
|
|
399
400
|
Reset the content of the editor. Need initialization first.
|
|
400
401
|
|
|
401
402
|
```js
|
|
@@ -654,18 +655,17 @@ Matched or unmatched tags are highlighted in cyan or dark red when the cursor is
|
|
|
654
655
|
|
|
655
656
|
### Transclusion
|
|
656
657
|
|
|
657
|
-
1. Substitution is not correctly highlighted ([Example](http://bhsd-harry.github.io/monaco-wiki/tests.html#Scribunto%3A%20isSubsting%20during%20PST)).
|
|
658
658
|
1. Non-existing parser functions starting with `#` are highlighted as parser functions ([Example](http://bhsd-harry.github.io/codemirror-mediawiki/tests.html#Parsoid%3A%20unknown%20parser%20function%20(T314524))).
|
|
659
659
|
1. Wikitext in template parameter names is not highlighted ([Example](http://bhsd-harry.github.io/codemirror-mediawiki/tests.html#Templates%3A%20Other%20wikitext%20in%20parameter%20names%20(T69657))).
|
|
660
660
|
1. Template parameter names followed by a newline are not recognized ([Example](http://bhsd-harry.github.io/codemirror-mediawiki/tests.html#Templates%3A%20Handle%20comments%20in%20parameter%20names%20(T69657))).
|
|
661
661
|
|
|
662
662
|
### Heading
|
|
663
663
|
|
|
664
|
-
1. Comments at the SOL break section headings ([Example](https://bhsd-harry.github.io/codemirror-mediawiki/tests.html#Section%20extraction%20prefixed%20by%20comment%20(section%201))).
|
|
664
|
+
1. Comments at the SOL should not break section headings ([Example](https://bhsd-harry.github.io/codemirror-mediawiki/tests.html#Section%20extraction%20prefixed%20by%20comment%20(section%201))).
|
|
665
665
|
|
|
666
666
|
### Table
|
|
667
667
|
|
|
668
|
-
1. Comments at the SOL break table syntax ([Example](https://bhsd-harry.github.io/codemirror-mediawiki/tests.html#3c.%20Table%20cells%20without%20escapable%20prefixes%20after%20edits)).
|
|
668
|
+
1. Comments at the SOL should not break table syntax ([Example](https://bhsd-harry.github.io/codemirror-mediawiki/tests.html#3c.%20Table%20cells%20without%20escapable%20prefixes%20after%20edits)).
|
|
669
669
|
|
|
670
670
|
### External link
|
|
671
671
|
|
|
@@ -676,3 +676,7 @@ Matched or unmatched tags are highlighted in cyan or dark red when the cursor is
|
|
|
676
676
|
|
|
677
677
|
1. Comments at the SOL break the highlighting ([Example](https://bhsd-harry.github.io/codemirror-mediawiki/tests.html#1.%20Lists%20with%20start-of-line-transparent%20tokens%20before%20bullets%3A%20Comments)).
|
|
678
678
|
1. False positives of preformatted text when there are categories ([Example](http://bhsd-harry.github.io/codemirror-mediawiki/tests.html#Category%20%2F%20paragraph%20interactions)) or HTML tags ([Example](http://bhsd-harry.github.io/codemirror-mediawiki/tests.html#Parsing%20optional%20HTML%20elements%20(T8171))).
|
|
679
|
+
|
|
680
|
+
### Language conversion
|
|
681
|
+
|
|
682
|
+
1. BCP 47 language codes are not supported in language conversion ([Example](https://bhsd-harry.github.io/wikiparser-node/tests.html#Explicit%20definition%20of%20language%20variant%20alternatives%20(BCP%2047%20codes))).
|
package/dist/bidi.d.ts
CHANGED
package/dist/codemirror.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export declare class CodeMirror6 {
|
|
|
40
40
|
* @param lang 语言
|
|
41
41
|
* @param config 语言设置
|
|
42
42
|
*/
|
|
43
|
-
setLanguage(lang?: string, config?: unknown):
|
|
43
|
+
setLanguage(lang?: string, config?: unknown): Promise<void>;
|
|
44
44
|
/**
|
|
45
45
|
* 开始语法检查
|
|
46
46
|
* @param lintSource 语法检查函数
|
|
@@ -71,8 +71,9 @@ export declare class CodeMirror6 {
|
|
|
71
71
|
/**
|
|
72
72
|
* 重设编辑器内容
|
|
73
73
|
* @param insert 新内容
|
|
74
|
+
* @param force 是否强制
|
|
74
75
|
*/
|
|
75
|
-
setContent(insert: string): void;
|
|
76
|
+
setContent(insert: string, force?: boolean): void;
|
|
76
77
|
/**
|
|
77
78
|
* 在编辑器和文本框之间切换
|
|
78
79
|
* @param show 是否显示编辑器
|
package/dist/codemirror.js
CHANGED
|
@@ -6,7 +6,7 @@ import { searchKeymap, highlightSelectionMatches } from '@codemirror/search';
|
|
|
6
6
|
import { linter, lintGutter, lintKeymap } from '@codemirror/lint';
|
|
7
7
|
import { closeBrackets, autocompletion, acceptCompletion, completionKeymap, startCompletion, } from '@codemirror/autocomplete';
|
|
8
8
|
import { json } from '@codemirror/lang-json';
|
|
9
|
-
import { getLSP } from '@bhsd/
|
|
9
|
+
import { getLSP } from '@bhsd/browser';
|
|
10
10
|
import colorPicker from './color';
|
|
11
11
|
import { mediawiki, html } from './mediawiki';
|
|
12
12
|
import escapeKeymap from './escape';
|
|
@@ -24,6 +24,7 @@ import toolKeymap from './keymap';
|
|
|
24
24
|
import statusBar from './statusBar';
|
|
25
25
|
import { detectIndent } from './indent';
|
|
26
26
|
import bracketMatching from './matchBrackets';
|
|
27
|
+
import wikitextLSP from './lsp';
|
|
27
28
|
import javascript from './javascript';
|
|
28
29
|
import css from './css';
|
|
29
30
|
import lua from './lua';
|
|
@@ -249,11 +250,17 @@ export class CodeMirror6 {
|
|
|
249
250
|
* @param lang 语言
|
|
250
251
|
* @param config 语言设置
|
|
251
252
|
*/
|
|
252
|
-
setLanguage(lang = 'plain', config) {
|
|
253
|
+
async setLanguage(lang = 'plain', config) {
|
|
253
254
|
this.#lang = lang;
|
|
254
255
|
if (this.#view) {
|
|
256
|
+
let ext = languages[lang](config);
|
|
257
|
+
ws: { // eslint-disable-line no-unused-labels
|
|
258
|
+
if (lang === 'mediawiki') {
|
|
259
|
+
ext = [ext, await wikitextLSP()];
|
|
260
|
+
}
|
|
261
|
+
}
|
|
255
262
|
this.#effects([
|
|
256
|
-
this.#language.reconfigure(
|
|
263
|
+
this.#language.reconfigure(ext),
|
|
257
264
|
this.#linter.reconfigure(linters[lang] ?? []),
|
|
258
265
|
]);
|
|
259
266
|
this.#minHeight(Boolean(linters[lang]));
|
|
@@ -355,11 +362,11 @@ export class CodeMirror6 {
|
|
|
355
362
|
* @param opt 选项
|
|
356
363
|
*/
|
|
357
364
|
async getLinter(opt) {
|
|
358
|
-
const isFunc = typeof opt === 'function', getOpt =
|
|
365
|
+
const isFunc = typeof opt === 'function', getOpt = runtime => isFunc ? opt(runtime) : opt;
|
|
359
366
|
switch (this.#lang) {
|
|
360
367
|
case 'mediawiki': {
|
|
361
|
-
const wikiLint = await getWikiLinter(getOpt(), this.#view);
|
|
362
|
-
return async (doc) => (await wikiLint(doc.toString(), getOpt(true)))
|
|
368
|
+
const wikiLint = await getWikiLinter(await getOpt(), this.#view);
|
|
369
|
+
return async (doc) => (await wikiLint(doc.toString(), await getOpt(true)))
|
|
363
370
|
.map(({ severity, code, message, range: r, from, to, data = [], source }) => ({
|
|
364
371
|
source: source,
|
|
365
372
|
from: from ?? posToIndex(doc, r.start),
|
|
@@ -382,7 +389,7 @@ export class CodeMirror6 {
|
|
|
382
389
|
}
|
|
383
390
|
case 'javascript': {
|
|
384
391
|
const esLint = await getJsLinter();
|
|
385
|
-
const lintSource = doc => esLint(doc.toString(), getOpt())
|
|
392
|
+
const lintSource = async (doc) => esLint(doc.toString(), await getOpt())
|
|
386
393
|
.map(({ ruleId, message, severity, line, column, endLine, endColumn, fix, suggestions = [] }) => {
|
|
387
394
|
const start = pos(doc, line, column), diagnostic = {
|
|
388
395
|
source: 'ESLint',
|
|
@@ -409,29 +416,10 @@ export class CodeMirror6 {
|
|
|
409
416
|
}
|
|
410
417
|
case 'css': {
|
|
411
418
|
const styleLint = await getCssLinter();
|
|
412
|
-
let option = getOpt() ?? {};
|
|
419
|
+
let option = await getOpt() ?? {};
|
|
413
420
|
if (!('extends' in option || 'rules' in option)) {
|
|
414
421
|
option = { rules: option };
|
|
415
422
|
}
|
|
416
|
-
if (this.dialect === 'sanitized-css') {
|
|
417
|
-
const rules = option['rules'];
|
|
418
|
-
option = {
|
|
419
|
-
...option,
|
|
420
|
-
rules: {
|
|
421
|
-
...rules,
|
|
422
|
-
'property-no-vendor-prefix': [
|
|
423
|
-
true,
|
|
424
|
-
{
|
|
425
|
-
ignoreProperties: ['user-select'],
|
|
426
|
-
},
|
|
427
|
-
],
|
|
428
|
-
'property-disallowed-list': [
|
|
429
|
-
...rules?.['property-disallowed-list'] ?? [],
|
|
430
|
-
'/^--/',
|
|
431
|
-
],
|
|
432
|
-
},
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
423
|
const lintSource = async (doc) => (await styleLint(doc.toString(), option))
|
|
436
424
|
.map(({ text, severity, line, column, endLine, endColumn, fix }) => {
|
|
437
425
|
const diagnostic = {
|
|
@@ -494,11 +482,13 @@ export class CodeMirror6 {
|
|
|
494
482
|
/**
|
|
495
483
|
* 重设编辑器内容
|
|
496
484
|
* @param insert 新内容
|
|
485
|
+
* @param force 是否强制
|
|
497
486
|
*/
|
|
498
|
-
setContent(insert) {
|
|
487
|
+
setContent(insert, force) {
|
|
499
488
|
if (this.#view) {
|
|
500
489
|
this.#view.dispatch({
|
|
501
490
|
changes: { from: 0, to: this.#view.state.doc.length, insert },
|
|
491
|
+
filter: !force,
|
|
502
492
|
});
|
|
503
493
|
}
|
|
504
494
|
}
|
package/dist/config.js
CHANGED
package/dist/fold.js
CHANGED
|
@@ -10,11 +10,18 @@ const updateSelection = (pos, { to }) => Math.max(pos, to), updateAll = (pos, {
|
|
|
10
10
|
* Check if a SyntaxNode is among the specified components
|
|
11
11
|
* @param keys The keys of the tokens to check
|
|
12
12
|
*/
|
|
13
|
-
const isComponent = (keys) => (
|
|
13
|
+
const isComponent = (keys) => (node) => keys.some(key => node?.name.includes(tokens[key])),
|
|
14
14
|
/** Check if a SyntaxNode is a template bracket (`{{` or `}}`) */
|
|
15
15
|
isTemplateBracket = isComponent(['templateBracket', 'parserFunctionBracket']),
|
|
16
|
+
/** Check if a SyntaxNode is a template name */
|
|
17
|
+
isTemplateName = isComponent(['templateName', 'parserFunctionName']),
|
|
16
18
|
/** Check if a SyntaxNode is a template delimiter (`|` or `:`) */
|
|
17
19
|
isDelimiter = isComponent(['templateDelimiter', 'parserFunctionDelimiter']),
|
|
20
|
+
/**
|
|
21
|
+
* Check if a SyntaxNode is a template delimiter (`|` or `:`), excluding `subst:` and `safesubst:`
|
|
22
|
+
* @param node SyntaxNode
|
|
23
|
+
*/
|
|
24
|
+
isTemplateDelimiter = (node) => isDelimiter(node) && !isTemplateName(node.nextSibling),
|
|
18
25
|
/**
|
|
19
26
|
* Check if a SyntaxNode is part of a template, except for the brackets
|
|
20
27
|
* @param node 语法树节点
|
|
@@ -88,7 +95,7 @@ export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
|
88
95
|
}
|
|
89
96
|
let { prevSibling, nextSibling } = node,
|
|
90
97
|
/** The stack of opening (+) or closing (-) brackets */ stack = 1,
|
|
91
|
-
/** The first delimiter */ delimiter =
|
|
98
|
+
/** The first delimiter */ delimiter = isTemplateDelimiter(node) ? node : null,
|
|
92
99
|
/** The start of the closing bracket */ to = 0;
|
|
93
100
|
while (nextSibling) {
|
|
94
101
|
if (isTemplateBracket(nextSibling)) {
|
|
@@ -103,7 +110,7 @@ export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
|
103
110
|
}
|
|
104
111
|
stack += lbrace;
|
|
105
112
|
}
|
|
106
|
-
else if (!delimiter && stack === 1 &&
|
|
113
|
+
else if (!delimiter && stack === 1 && isTemplateDelimiter(nextSibling)) {
|
|
107
114
|
// The first delimiter of the current template so far
|
|
108
115
|
delimiter = nextSibling;
|
|
109
116
|
}
|
|
@@ -124,7 +131,7 @@ export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
|
124
131
|
}
|
|
125
132
|
stack += rbrace;
|
|
126
133
|
}
|
|
127
|
-
else if (stack === -1 &&
|
|
134
|
+
else if (stack === -1 && isTemplateDelimiter(prevSibling)) {
|
|
128
135
|
// The first delimiter of the current template so far
|
|
129
136
|
delimiter = prevSibling;
|
|
130
137
|
}
|
package/dist/hover.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { hoverTooltip } from '@codemirror/view';
|
|
2
|
-
import { loadScript, getLSP } from '@bhsd/
|
|
3
|
-
let md;
|
|
2
|
+
import { loadScript, getLSP } from '@bhsd/browser';
|
|
4
3
|
/**
|
|
5
4
|
* 将索引转换为位置
|
|
6
5
|
* @param doc Text 实例
|
|
@@ -36,15 +35,14 @@ export default (cm) => hoverTooltip(async (view, pos) => {
|
|
|
36
35
|
const { state: { doc } } = view, hover = await getLSP(view, false, cm.getWikiConfig)
|
|
37
36
|
?.provideHover(doc.toString(), indexToPos(doc, pos));
|
|
38
37
|
if (hover) {
|
|
39
|
-
await loadScript('npm/
|
|
40
|
-
md ??= markdownit();
|
|
38
|
+
await loadScript('npm/marked/lib/marked.umd.js', 'marked', true);
|
|
41
39
|
const { end } = hover.range;
|
|
42
40
|
return {
|
|
43
41
|
pos,
|
|
44
42
|
end: posToIndex(doc, end),
|
|
45
43
|
above: true,
|
|
46
44
|
create() {
|
|
47
|
-
return createTooltipView(view,
|
|
45
|
+
return createTooltipView(view, marked.parse(hover.contents.value));
|
|
48
46
|
},
|
|
49
47
|
};
|
|
50
48
|
}
|
package/dist/inlay.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StateField, StateEffect } from '@codemirror/state';
|
|
2
2
|
import { Decoration, EditorView, WidgetType, ViewPlugin } from '@codemirror/view';
|
|
3
|
-
import { getLSP } from '@bhsd/
|
|
3
|
+
import { getLSP } from '@bhsd/browser';
|
|
4
4
|
import { posToIndex } from './hover';
|
|
5
5
|
class InlayHintWidget extends WidgetType {
|
|
6
6
|
constructor(label) {
|
package/dist/linter.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Linter } from 'eslint';
|
|
|
3
3
|
import type { Warning } from 'stylelint';
|
|
4
4
|
import type { Diagnostic } from 'luacheck-browserify';
|
|
5
5
|
export type Option = Record<string, unknown> | null | undefined;
|
|
6
|
-
export type LiveOption = (runtime?: boolean) => Option
|
|
6
|
+
export type LiveOption = (runtime?: boolean) => Option | Promise<Option>;
|
|
7
7
|
declare type getLinter<T> = () => (text: string) => T;
|
|
8
8
|
declare type asyncLinter<T, S = Record<string, unknown>> = ((text: string, config?: Option) => T) & {
|
|
9
9
|
config?: S;
|
package/dist/linter.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable unicorn/no-unreadable-iife */
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { sanitizeInlineStyle } from '@bhsd/common';
|
|
3
|
+
import { loadScript, getWikiparse, getLSP } from '@bhsd/browser';
|
|
4
|
+
import { styleLint } from '@bhsd/stylelint-util';
|
|
4
5
|
/**
|
|
5
6
|
* 计算位置
|
|
6
7
|
* @param range 范围
|
|
@@ -22,7 +23,7 @@ export const getWikiLinter = async (opt, obj) => {
|
|
|
22
23
|
await getWikiparse(opt?.['getConfig'], opt?.['i18n']);
|
|
23
24
|
const lsp = getLSP(obj, opt?.['include']);
|
|
24
25
|
return async (text, config) => {
|
|
25
|
-
const diagnostics = (await lsp.provideDiagnostics(text)).filter(({ code, severity }) => Number(config?.[code] ??
|
|
26
|
+
const defaultSeverity = config?.['defaultSeverity'] ?? 2, diagnostics = (await lsp.provideDiagnostics(text)).filter(({ code, severity }) => Number(config?.[code] ?? defaultSeverity) > Number(severity === 2)), tokens = 'findStyleTokens' in lsp && config?.['invalid-css'] !== '0' ? await lsp.findStyleTokens() : [];
|
|
26
27
|
if (tokens.length === 0) {
|
|
27
28
|
return diagnostics;
|
|
28
29
|
}
|
|
@@ -30,7 +31,7 @@ export const getWikiLinter = async (opt, obj) => {
|
|
|
30
31
|
return [
|
|
31
32
|
...diagnostics,
|
|
32
33
|
...(await cssLint(tokens.map(({ childNodes, type, tag }, i) => `${type === 'ext-attr' ? 'div' : tag}#${i}{\n${sanitizeInlineStyle(childNodes[1].childNodes[0].data)
|
|
33
|
-
.replace(/\n/gu, ' ')}\n}`).join('\n'))).map(({ line, column, endLine, endColumn, rule, severity, text: message }) => {
|
|
34
|
+
.replace(/\n/gu, ' ')}\n}`).join('\n'), config?.['css'])).map(({ line, column, endLine, endColumn, rule, severity, text: message }) => {
|
|
34
35
|
const i = Math.ceil(line / 3), { range } = tokens[i - 1].childNodes[1].childNodes[0], from = offsetAt(range, line - 3 * i, column - 1);
|
|
35
36
|
return {
|
|
36
37
|
from,
|
package/dist/lsp.d.ts
ADDED
package/dist/lsp.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { LSPClient, languageServerSupport } from '@codemirror/lsp-client';
|
|
2
|
+
let promise, file = 0;
|
|
3
|
+
export default async () => {
|
|
4
|
+
if (location.hostname !== 'localhost') {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
promise ??= new Promise(resolve => {
|
|
8
|
+
let handlers = [];
|
|
9
|
+
const ws = new WebSocket('ws://localhost:3000/wikitext');
|
|
10
|
+
ws.onmessage = ({ data }) => {
|
|
11
|
+
for (const handler of handlers) {
|
|
12
|
+
handler(String(data));
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
ws.onopen = () => {
|
|
16
|
+
resolve({
|
|
17
|
+
send(message) {
|
|
18
|
+
ws.send(message);
|
|
19
|
+
},
|
|
20
|
+
subscribe(handler) {
|
|
21
|
+
handlers.push(handler);
|
|
22
|
+
},
|
|
23
|
+
unsubscribe(handler) {
|
|
24
|
+
handlers = handlers.filter(h => h !== handler);
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
ws.onerror = () => {
|
|
29
|
+
resolve(null);
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
const transport = await promise;
|
|
33
|
+
return transport ? languageServerSupport(new LSPClient().connect(transport), `file:///${file++}.wiki`) : [];
|
|
34
|
+
};
|