@bhsd/codemirror-mediawiki 3.12.0 → 3.12.2
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/LICENSE +19 -0
- package/dist/bidi.js +9 -8
- package/dist/codemirror.js +5 -5
- package/dist/constants.d.ts +2 -1
- package/dist/constants.js +2 -1
- package/dist/escape.js +3 -3
- package/dist/fold.d.ts +4 -4
- package/dist/fold.js +22 -19
- package/dist/hover.js +3 -3
- package/dist/html.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/inlay.js +2 -2
- package/dist/javascript.d.ts +3 -3
- package/dist/javascript.js +30 -9
- package/dist/json.d.ts +8 -0
- package/dist/json.js +108 -0
- package/dist/keymap.d.ts +1 -1
- package/dist/keymap.js +18 -3
- package/dist/lint.js +2 -2
- package/dist/lintsource.js +7 -7
- package/dist/lua.d.ts +16 -0
- package/dist/lua.js +65 -9
- package/dist/main.min.js +31 -29
- package/dist/matchBrackets.d.ts +3 -6
- package/dist/matchBrackets.js +61 -24
- package/dist/matchTag.d.ts +5 -5
- package/dist/matchTag.js +8 -8
- package/dist/mediawiki.d.ts +1 -2
- package/dist/mediawiki.js +4 -9
- package/dist/mw.min.js +34 -32
- package/dist/ref.d.ts +2 -2
- package/dist/ref.js +5 -5
- package/dist/signature.js +13 -13
- package/dist/static.d.ts +3 -0
- package/dist/static.js +3 -0
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +21 -3
- package/dist/token.d.ts +8 -5
- package/dist/token.js +17 -4
- package/dist/util.d.ts +22 -4
- package/dist/util.js +45 -4
- package/dist/vue.js +2 -2
- package/dist/wiki.min.js +34 -32
- package/i18n/en.json +1 -1
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/package.json +13 -13
package/LICENSE
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
@bhsd/codemirror-mediawiki
|
|
2
|
+
Copyright (C) 2022 Bhsd
|
|
3
|
+
|
|
4
|
+
This program is free software; you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU General Public License as published by
|
|
6
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License along
|
|
15
|
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
16
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
1
20
|
GNU GENERAL PUBLIC LICENSE
|
|
2
21
|
Version 2, June 1991
|
|
3
22
|
|
package/dist/bidi.js
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* @see https://gerrit.wikimedia.org/g/mediawiki/extensions/CodeMirror
|
|
5
5
|
*/
|
|
6
6
|
import { EditorView, Direction, ViewPlugin, Decoration } from '@codemirror/view';
|
|
7
|
-
import { Prec
|
|
7
|
+
import { Prec } from '@codemirror/state';
|
|
8
8
|
import { syntaxTree } from '@codemirror/language';
|
|
9
9
|
import { tokens } from './config.js';
|
|
10
10
|
import { getTag } from './matchTag.js';
|
|
11
|
+
import { pushDecoration } from './util.js';
|
|
11
12
|
const isolateSelector = '.cm-bidi-isolate', ltrSelector = '.cm-bidi-ltr', cls = isolateSelector.slice(1), isolateLTR = Decoration.mark({
|
|
12
13
|
class: `${cls} ${ltrSelector.slice(1)}`,
|
|
13
14
|
bidiIsolate: Direction.LTR,
|
|
@@ -18,7 +19,7 @@ const isolateSelector = '.cm-bidi-isolate', ltrSelector = '.cm-bidi-ltr', cls =
|
|
|
18
19
|
* @test
|
|
19
20
|
*/
|
|
20
21
|
export const computeIsolates = ({ visibleRanges, state, textDirection }) => {
|
|
21
|
-
const set =
|
|
22
|
+
const set = [];
|
|
22
23
|
if (textDirection === Direction.RTL) {
|
|
23
24
|
for (const { from, to } of visibleRanges) {
|
|
24
25
|
let node = syntaxTree(state).resolve(from, 1), td = 0, table = 0, parameter = 0;
|
|
@@ -27,13 +28,13 @@ export const computeIsolates = ({ visibleRanges, state, textDirection }) => {
|
|
|
27
28
|
if (/-(?:ext|html)tag-bracket/u.test(name) && state.sliceDoc(f, t).includes('<')) {
|
|
28
29
|
const tag = getTag(state, nextSibling);
|
|
29
30
|
if (tag) {
|
|
30
|
-
set
|
|
31
|
+
pushDecoration(set, isolateLTR, tag);
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
else if (!td && !table && name.includes(tokens.tableDefinition)) {
|
|
34
35
|
if (/-html-(?:table|tr)/u.test(name)) {
|
|
35
36
|
table = state.doc.lineAt(f).to;
|
|
36
|
-
set
|
|
37
|
+
pushDecoration(set, isolateLTR, f, table);
|
|
37
38
|
}
|
|
38
39
|
else {
|
|
39
40
|
td = f;
|
|
@@ -43,18 +44,18 @@ export const computeIsolates = ({ visibleRanges, state, textDirection }) => {
|
|
|
43
44
|
table = 0;
|
|
44
45
|
}
|
|
45
46
|
else if (td && name.includes(tokens.tableDelimiter2)) {
|
|
46
|
-
set
|
|
47
|
+
pushDecoration(set, isolateLTR, td, f);
|
|
47
48
|
td = 0;
|
|
48
49
|
}
|
|
49
50
|
else if (/-(?:template|parserfunction)-delimiter/u.test(name)) {
|
|
50
51
|
if (parameter) {
|
|
51
|
-
set
|
|
52
|
+
pushDecoration(set, isolate, parameter, f);
|
|
52
53
|
}
|
|
53
54
|
parameter = t;
|
|
54
55
|
}
|
|
55
56
|
else if (parameter && /-(?:template|parserfunction)-bracket/u.test(name)) {
|
|
56
57
|
if (state.sliceDoc(f, f + 1) === '}') {
|
|
57
|
-
set
|
|
58
|
+
pushDecoration(set, isolate, parameter, f);
|
|
58
59
|
}
|
|
59
60
|
parameter = 0;
|
|
60
61
|
}
|
|
@@ -62,7 +63,7 @@ export const computeIsolates = ({ visibleRanges, state, textDirection }) => {
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
|
-
return set
|
|
66
|
+
return Decoration.set(set, true);
|
|
66
67
|
};
|
|
67
68
|
export default [
|
|
68
69
|
ViewPlugin.fromClass(class {
|
package/dist/codemirror.js
CHANGED
|
@@ -5,7 +5,7 @@ import { defaultKeymap, historyKeymap, history, redo, indentWithTab, insertNewli
|
|
|
5
5
|
import { search, searchKeymap } from '@codemirror/search';
|
|
6
6
|
import { linter, lintGutter } from '@codemirror/lint';
|
|
7
7
|
import elt from 'crelt';
|
|
8
|
-
import {
|
|
8
|
+
import { baseData, panelSelector, panelsSelector, diagnosticSelector, noDetectionLangs } from './constants.js';
|
|
9
9
|
import { light } from './theme.js';
|
|
10
10
|
import { nextDiagnostic } from './lint.js';
|
|
11
11
|
export const plain = () => [
|
|
@@ -62,10 +62,10 @@ export const replaceSelections = (view, func) => {
|
|
|
62
62
|
/** CodeMirror 6 editor */
|
|
63
63
|
export class CodeMirror6 {
|
|
64
64
|
static get CDN() {
|
|
65
|
-
return
|
|
65
|
+
return baseData.CDN;
|
|
66
66
|
}
|
|
67
67
|
static set CDN(url) {
|
|
68
|
-
|
|
68
|
+
baseData.CDN = url;
|
|
69
69
|
}
|
|
70
70
|
#textarea;
|
|
71
71
|
#language = new Compartment();
|
|
@@ -301,10 +301,10 @@ export class CodeMirror6 {
|
|
|
301
301
|
const diagnostics = (await source(state)).map((diagnostic) => ({
|
|
302
302
|
...diagnostic,
|
|
303
303
|
renderMessage(view) {
|
|
304
|
-
const span = elt('span', { class: diagnosticSelector.slice(1) }, diagnostic.renderMessage?.(view) ??
|
|
304
|
+
const span = elt('span', { class: diagnosticSelector.slice(1) }, diagnostic.renderMessage?.call(this, view) ?? this.message);
|
|
305
305
|
span.addEventListener('click', () => {
|
|
306
306
|
view.dispatch({
|
|
307
|
-
selection: { anchor:
|
|
307
|
+
selection: { anchor: this.from, head: this.to },
|
|
308
308
|
});
|
|
309
309
|
view.focus();
|
|
310
310
|
});
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { Decoration } from '@codemirror/view';
|
|
2
|
+
export declare const baseData: Record<'CDN', string | undefined>, hoverSelector = ".cm-tooltip-hover-mw", diagnosticSelector = ".cm-diagnosticText-clickable", panelSelector = ".cm-panel", panelsSelector = ".cm-panels", actionSelector = ".cm-diagnosticAction", doctagMark: Decoration, typeMark: Decoration, noDetectionLangs: Set<string>, bgDark = "#4c566a", matchingCls = "cm-matchingTag", nonmatchingCls = "cm-nonmatchingTag";
|
|
2
3
|
export declare const isWMF: boolean;
|
|
3
4
|
export declare const isMac: boolean;
|
package/dist/constants.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { Decoration } from '@codemirror/view';
|
|
1
2
|
import { wmf } from '@bhsd/common';
|
|
2
|
-
export const
|
|
3
|
+
export const baseData = { CDN: undefined }, hoverSelector = '.cm-tooltip-hover-mw', diagnosticSelector = '.cm-diagnosticText-clickable', panelSelector = '.cm-panel', panelsSelector = '.cm-panels', actionSelector = '.cm-diagnosticAction', doctagMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag' }), typeMark = /* @__PURE__ */ Decoration.mark({ class: 'cm-doctag-type' }), noDetectionLangs = new Set(['plain', 'mediawiki']), bgDark = '#4c566a', matchingCls = 'cm-matchingTag', nonmatchingCls = 'cm-nonmatchingTag';
|
|
3
4
|
export const isWMF = /* @__PURE__ */ (() => typeof location === 'object'
|
|
4
5
|
&& new RegExp(String.raw `\.(?:${wmf})\.org$`, 'u').test(location.hostname))();
|
|
5
6
|
export const isMac = /* @__PURE__ */ (() => {
|
package/dist/escape.js
CHANGED
|
@@ -3,7 +3,7 @@ import { EditorSelection } from '@codemirror/state';
|
|
|
3
3
|
import { indentMore, indentLess } from '@codemirror/commands';
|
|
4
4
|
import { getLSP } from '@bhsd/browser';
|
|
5
5
|
import elt from 'crelt';
|
|
6
|
-
import {
|
|
6
|
+
import { baseData } from './constants.js';
|
|
7
7
|
import { replaceSelections, menuRegistry, } from './codemirror.js';
|
|
8
8
|
import { sliceDoc, toConfigGetter, } from './util.js';
|
|
9
9
|
const entity = { '"': 'quot', "'": 'apos', '<': 'lt', '>': 'gt', '&': 'amp', ' ': 'nbsp' };
|
|
@@ -70,7 +70,7 @@ escapeWiki = async (view, lsp) => {
|
|
|
70
70
|
}));
|
|
71
71
|
};
|
|
72
72
|
const escapeWikiCommand = (view, getConfig) => {
|
|
73
|
-
const lsp = getLSP(view, false, getConfig,
|
|
73
|
+
const lsp = getLSP(view, false, getConfig, baseData.CDN);
|
|
74
74
|
if (lsp && 'provideRefactoringAction' in lsp && view.state.selection.ranges.some(({ empty }) => !empty)) {
|
|
75
75
|
void escapeWiki(view, lsp);
|
|
76
76
|
return true;
|
|
@@ -99,7 +99,7 @@ menuRegistry.push({
|
|
|
99
99
|
handlerBase(view, e);
|
|
100
100
|
});
|
|
101
101
|
items = [btnHTML, btnURI];
|
|
102
|
-
const lsp = getLSP(view, false, cm.getWikiConfig,
|
|
102
|
+
const lsp = getLSP(view, false, cm.getWikiConfig, baseData.CDN);
|
|
103
103
|
if (lsp && 'provideRefactoringAction' in lsp) {
|
|
104
104
|
const btnWiki = elt('div', 'Escape with magic words');
|
|
105
105
|
btnWiki.addEventListener('click', e => {
|
package/dist/fold.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export declare const updateSelection: AnchorUpdate, updateAll: AnchorUpdate;
|
|
|
17
17
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
18
18
|
* @test
|
|
19
19
|
*/
|
|
20
|
-
export declare const
|
|
20
|
+
export declare const foldableInline: (state: EditorState, posOrNode: number | SyntaxNode, tree?: Tree | null, refOnly?: boolean) => DocRange | false;
|
|
21
21
|
/**
|
|
22
22
|
* 折叠所有模板
|
|
23
23
|
* @param state
|
|
@@ -31,7 +31,7 @@ export declare const foldable: (state: EditorState, posOrNode: number | SyntaxNo
|
|
|
31
31
|
* @test
|
|
32
32
|
*/
|
|
33
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
|
|
34
|
+
declare class MyFoldMarker extends GutterMarker {
|
|
35
35
|
readonly open: boolean;
|
|
36
36
|
constructor(open: boolean);
|
|
37
37
|
eq(other: this): boolean;
|
|
@@ -48,7 +48,7 @@ export declare const foldableLine: ({ state, viewportLineBlocks }: EditorView, {
|
|
|
48
48
|
* @param view
|
|
49
49
|
* @test
|
|
50
50
|
*/
|
|
51
|
-
export declare const buildMarkers: (view: EditorView) => RangeSet<
|
|
51
|
+
export declare const buildMarkers: (view: EditorView) => RangeSet<MyFoldMarker>;
|
|
52
52
|
/**
|
|
53
53
|
* 生成折叠命令
|
|
54
54
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
@@ -62,7 +62,7 @@ export declare const unfoldRef: Command;
|
|
|
62
62
|
* @param view
|
|
63
63
|
* @test
|
|
64
64
|
*/
|
|
65
|
-
export declare const
|
|
65
|
+
export declare const mySelectedLines: (view: EditorView) => BlockInfo[];
|
|
66
66
|
/**
|
|
67
67
|
* Fold the template at the selection/cursor
|
|
68
68
|
* @param view
|
package/dist/fold.js
CHANGED
|
@@ -47,7 +47,7 @@ const refNames = new Set(['ref', 'references']);
|
|
|
47
47
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
48
48
|
* @test
|
|
49
49
|
*/
|
|
50
|
-
export const
|
|
50
|
+
export const foldableInline = (state, posOrNode, tree, refOnly = false) => {
|
|
51
51
|
if (typeof posOrNode === 'number') {
|
|
52
52
|
tree = ensureSyntaxTree(state, posOrNode);
|
|
53
53
|
}
|
|
@@ -141,7 +141,7 @@ const foldSelector = '.cm-tooltip-fold';
|
|
|
141
141
|
* @param state
|
|
142
142
|
*/
|
|
143
143
|
const create = (state) => {
|
|
144
|
-
const { head } = state.selection.main, range =
|
|
144
|
+
const { head } = state.selection.main, range = foldableInline(state, head);
|
|
145
145
|
if (range) {
|
|
146
146
|
const { from, to } = range;
|
|
147
147
|
let folded = false;
|
|
@@ -207,7 +207,7 @@ export const traverse = (state, tree, effects, node, end, anchor, update, refOnl
|
|
|
207
207
|
while (node && (node.from < end
|
|
208
208
|
|| node.from === end
|
|
209
209
|
&& !(isTemplateBracket(node) && sliceDoc(state, node).startsWith('}}')))) {
|
|
210
|
-
const range =
|
|
210
|
+
const range = foldableInline(state, node, tree, refOnly);
|
|
211
211
|
if (range) {
|
|
212
212
|
effects.push(foldEffect.of(range));
|
|
213
213
|
node = tree.resolve(range.to, 1);
|
|
@@ -219,7 +219,7 @@ export const traverse = (state, tree, effects, node, end, anchor, update, refOnl
|
|
|
219
219
|
}
|
|
220
220
|
return anchor;
|
|
221
221
|
};
|
|
222
|
-
class
|
|
222
|
+
class MyFoldMarker extends GutterMarker {
|
|
223
223
|
constructor(open) {
|
|
224
224
|
super();
|
|
225
225
|
this.open = open;
|
|
@@ -231,8 +231,8 @@ class FoldMarker extends GutterMarker {
|
|
|
231
231
|
return elt('span', { title: state.phrase(this.open ? 'Fold line' : 'Unfold line') }, this.open ? '⌄' : '›');
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
|
-
const canFold = /* @__PURE__ */ new
|
|
235
|
-
const
|
|
234
|
+
const canFold = /* @__PURE__ */ new MyFoldMarker(true), canUnfold = /* @__PURE__ */ new MyFoldMarker(false);
|
|
235
|
+
const myFindFold = ({ state }, line) => {
|
|
236
236
|
let found;
|
|
237
237
|
state.field(foldState, false)?.between(line.from, line.to, (from, to) => {
|
|
238
238
|
if (!found && to === line.to) {
|
|
@@ -323,7 +323,7 @@ export const buildMarkers = (view) => {
|
|
|
323
323
|
const builder = new RangeSetBuilder();
|
|
324
324
|
for (const line of view.viewportLineBlocks) {
|
|
325
325
|
let mark;
|
|
326
|
-
if (
|
|
326
|
+
if (myFindFold(view, line)) {
|
|
327
327
|
mark = canUnfold;
|
|
328
328
|
}
|
|
329
329
|
else if (foldableLine(view, line)) {
|
|
@@ -337,14 +337,17 @@ export const buildMarkers = (view) => {
|
|
|
337
337
|
};
|
|
338
338
|
const markers = /* @__PURE__ */ ViewPlugin.fromClass(class {
|
|
339
339
|
constructor(view) {
|
|
340
|
+
this.tree = syntaxTree(view.state);
|
|
340
341
|
this.markers = buildMarkers(view);
|
|
341
342
|
}
|
|
342
343
|
update({ docChanged, viewportChanged, startState, state, view }) {
|
|
344
|
+
const tree = syntaxTree(state);
|
|
343
345
|
if (docChanged
|
|
344
346
|
|| viewportChanged
|
|
345
347
|
|| startState.facet(language) !== state.facet(language)
|
|
346
348
|
|| startState.field(foldState, false) !== state.field(foldState, false)
|
|
347
|
-
||
|
|
349
|
+
|| tree !== this.tree) {
|
|
350
|
+
this.tree = tree;
|
|
348
351
|
this.markers = buildMarkers(view);
|
|
349
352
|
}
|
|
350
353
|
}
|
|
@@ -390,7 +393,7 @@ export const unfoldRef = (view) => {
|
|
|
390
393
|
* @param view
|
|
391
394
|
* @test
|
|
392
395
|
*/
|
|
393
|
-
export const
|
|
396
|
+
export const mySelectedLines = (view) => {
|
|
394
397
|
const lines = [];
|
|
395
398
|
for (const { head } of view.state.selection.ranges) {
|
|
396
399
|
if (lines.some(({ from, to }) => from <= head && to >= head)) {
|
|
@@ -400,7 +403,7 @@ export const selectedLines = (view) => {
|
|
|
400
403
|
}
|
|
401
404
|
return lines;
|
|
402
405
|
};
|
|
403
|
-
const
|
|
406
|
+
const myFoldCode = (view, line) => {
|
|
404
407
|
const range = foldableLine(view, line);
|
|
405
408
|
if (range) {
|
|
406
409
|
view.dispatch({ effects: foldEffect.of(range) });
|
|
@@ -408,8 +411,8 @@ const foldCode = (view, line) => {
|
|
|
408
411
|
}
|
|
409
412
|
return false;
|
|
410
413
|
};
|
|
411
|
-
const
|
|
412
|
-
const folded =
|
|
414
|
+
const myUnfoldCode = (view, line) => {
|
|
415
|
+
const folded = myFindFold(view, line);
|
|
413
416
|
return folded && unfoldEffect.of(folded);
|
|
414
417
|
};
|
|
415
418
|
/**
|
|
@@ -434,8 +437,8 @@ export const foldAt = view => {
|
|
|
434
437
|
if (effects.length > 0) {
|
|
435
438
|
return execute(view, effects, anchor);
|
|
436
439
|
}
|
|
437
|
-
for (const line of
|
|
438
|
-
if (
|
|
440
|
+
for (const line of mySelectedLines(view)) {
|
|
441
|
+
if (myFoldCode(view, line)) {
|
|
439
442
|
return true;
|
|
440
443
|
}
|
|
441
444
|
}
|
|
@@ -512,8 +515,8 @@ export const mediawikiFold = /* @__PURE__ */ (() => [
|
|
|
512
515
|
view.dispatch({ effects, selection });
|
|
513
516
|
return true;
|
|
514
517
|
}
|
|
515
|
-
for (const line of
|
|
516
|
-
const effect =
|
|
518
|
+
for (const line of mySelectedLines(view)) {
|
|
519
|
+
const effect = myUnfoldCode(view, line);
|
|
517
520
|
if (effect) {
|
|
518
521
|
effects.push(effect);
|
|
519
522
|
}
|
|
@@ -534,16 +537,16 @@ export const mediawikiFold = /* @__PURE__ */ (() => [
|
|
|
534
537
|
return view.plugin(markers)?.markers ?? RangeSet.empty;
|
|
535
538
|
},
|
|
536
539
|
initialSpacer() {
|
|
537
|
-
return new
|
|
540
|
+
return new MyFoldMarker(false);
|
|
538
541
|
},
|
|
539
542
|
domEventHandlers: {
|
|
540
543
|
click(view, line) {
|
|
541
|
-
const effects =
|
|
544
|
+
const effects = myUnfoldCode(view, line);
|
|
542
545
|
if (effects) {
|
|
543
546
|
view.dispatch({ effects });
|
|
544
547
|
return true;
|
|
545
548
|
}
|
|
546
|
-
return
|
|
549
|
+
return myFoldCode(view, line);
|
|
547
550
|
},
|
|
548
551
|
},
|
|
549
552
|
}),
|
package/dist/hover.js
CHANGED
|
@@ -2,7 +2,7 @@ import { hoverTooltip, EditorView } from '@codemirror/view';
|
|
|
2
2
|
import { ensureSyntaxTree } from '@codemirror/language';
|
|
3
3
|
import { getLSP, loadScript, } from '@bhsd/browser';
|
|
4
4
|
import { tokens } from './config.js';
|
|
5
|
-
import {
|
|
5
|
+
import { baseData, hoverSelector, bgDark } from './constants.js';
|
|
6
6
|
import { indexToPos, posToIndex, createTooltipView, toConfigGetter, escHTML, sliceDoc, findTemplateName, } from './util.js';
|
|
7
7
|
const code = `${hoverSelector} code`;
|
|
8
8
|
/**
|
|
@@ -58,13 +58,13 @@ export default (articlePath, templatedata) => (cm) => {
|
|
|
58
58
|
hoverTooltip(async (view, pos, side) => {
|
|
59
59
|
const { state } = view, { doc } = state;
|
|
60
60
|
const { paramSuggest, tags } = cm.langConfig;
|
|
61
|
-
let hover = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath),
|
|
61
|
+
let hover = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), baseData.CDN)?.provideHover(doc.toString(), indexToPos(doc, pos));
|
|
62
62
|
if (!hover && paramSuggest && 'templatedata' in tags) {
|
|
63
63
|
// eslint-disable-next-line require-atomic-updates
|
|
64
64
|
hover = await getHoverFromApi(state, pos, side, paramSuggest, templatedata);
|
|
65
65
|
}
|
|
66
66
|
if (hover) {
|
|
67
|
-
const { CDN = '' } =
|
|
67
|
+
const { CDN = '' } = baseData;
|
|
68
68
|
await loadScript(`${CDN}${CDN && '/'}npm/marked/lib/marked.umd.js`, 'marked', true);
|
|
69
69
|
const { end } = hover.range;
|
|
70
70
|
return {
|
package/dist/html.js
CHANGED
|
@@ -4,7 +4,7 @@ import { javascript, javascriptLanguage } from '@codemirror/lang-javascript';
|
|
|
4
4
|
import { cssLanguage } from '@codemirror/lang-css';
|
|
5
5
|
import { LanguageSupport } from '@codemirror/language';
|
|
6
6
|
import { cssCompletion } from './css.js';
|
|
7
|
-
import { jsCompletion,
|
|
7
|
+
import { jsCompletion, markGlobalsAndDocTagPlugin } from './javascript.js';
|
|
8
8
|
import { mediawikiBase } from './mediawiki.js';
|
|
9
9
|
import { lightHighlightStyle } from './theme.js';
|
|
10
10
|
export default (config, cm) => {
|
|
@@ -31,7 +31,7 @@ export default (config, cm) => {
|
|
|
31
31
|
cssCompletion(),
|
|
32
32
|
support,
|
|
33
33
|
lightHighlightStyle,
|
|
34
|
-
|
|
34
|
+
markGlobalsAndDocTagPlugin(cm),
|
|
35
35
|
]);
|
|
36
36
|
Object.assign(langSupport, { nestedMWLanguage: language });
|
|
37
37
|
return langSupport;
|
package/dist/index.d.ts
CHANGED
|
@@ -159,4 +159,4 @@ export declare const registerLanguage: (name: string, lang: (config?: unknown) =
|
|
|
159
159
|
*/
|
|
160
160
|
export declare const registerLanguageCore: (name: string, lang: (config?: unknown) => LanguageSupport, lintSource?: LintSourceGetter) => void;
|
|
161
161
|
export declare const registerTheme: (name: string, theme: Extension) => void;
|
|
162
|
-
export { nord } from './theme.js';
|
|
162
|
+
export { nordDark as nord } from './theme.js';
|
package/dist/index.js
CHANGED
package/dist/inlay.js
CHANGED
|
@@ -2,7 +2,7 @@ import { StateField, StateEffect } from '@codemirror/state';
|
|
|
2
2
|
import { Decoration, EditorView, WidgetType, ViewPlugin } from '@codemirror/view';
|
|
3
3
|
import { getLSP } from '@bhsd/browser';
|
|
4
4
|
import elt from 'crelt';
|
|
5
|
-
import {
|
|
5
|
+
import { baseData } from './constants.js';
|
|
6
6
|
import { posToIndex, toConfigGetter, } from './util.js';
|
|
7
7
|
const cls = 'cm-inlay-hint';
|
|
8
8
|
class InlayHintWidget extends WidgetType {
|
|
@@ -54,7 +54,7 @@ export default (articlePath) => (cm) => {
|
|
|
54
54
|
field,
|
|
55
55
|
ViewPlugin.define(view => {
|
|
56
56
|
const timer = setInterval(() => {
|
|
57
|
-
if (getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath),
|
|
57
|
+
if (getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), baseData.CDN)) {
|
|
58
58
|
clearInterval(timer);
|
|
59
59
|
void update({ view, docChanged: true });
|
|
60
60
|
}
|
package/dist/javascript.d.ts
CHANGED
|
@@ -12,11 +12,11 @@ export declare const jsCompletion: Extension;
|
|
|
12
12
|
*/
|
|
13
13
|
export declare const exclude: (state: EditorState, pos: number) => boolean;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* 高亮显示全局变量和JSDoc标签
|
|
16
16
|
* @ignore
|
|
17
17
|
* @test
|
|
18
18
|
*/
|
|
19
|
-
export declare const
|
|
20
|
-
export declare const
|
|
19
|
+
export declare const markGlobalsAndDocTag: (tree: Tree, visibleRanges: readonly DocRange[], state: EditorState, cm?: CodeMirror6) => DecorationSet;
|
|
20
|
+
export declare const markGlobalsAndDocTagPlugin: (cm?: CodeMirror6) => Extension;
|
|
21
21
|
declare const _default: (_?: unknown, cm?: CodeMirror6) => Extension;
|
|
22
22
|
export default _default;
|
package/dist/javascript.js
CHANGED
|
@@ -3,8 +3,10 @@ import { ViewPlugin, Decoration } from '@codemirror/view';
|
|
|
3
3
|
import { syntaxTree } from '@codemirror/language';
|
|
4
4
|
import { setDiagnosticsEffect } from '@codemirror/lint';
|
|
5
5
|
import { builtin } from './javascript-globals.js';
|
|
6
|
+
import { doctagMark } from './constants.js';
|
|
7
|
+
import { markDocTagType, pushDecoration } from './util.js';
|
|
6
8
|
export const jsCompletion = javascriptLanguage.data.of({ autocomplete: scopeCompletionSource(globalThis) });
|
|
7
|
-
const globalsMark = Decoration.mark({ class: 'cm-globals' }), builtinGlobals = new Set(Object.keys(builtin));
|
|
9
|
+
const globalsMark = Decoration.mark({ class: 'cm-globals' }), varMark = Decoration.mark({ class: 'cm-doctag-var' }), builtinGlobals = new Set(Object.keys(builtin));
|
|
8
10
|
/**
|
|
9
11
|
* 忽略JavaScript正则表达式中的括号匹配
|
|
10
12
|
* @param state
|
|
@@ -14,11 +16,11 @@ const globalsMark = Decoration.mark({ class: 'cm-globals' }), builtinGlobals = n
|
|
|
14
16
|
export const exclude = (state, pos) => javascriptLanguage.isActiveAt(state, pos, 0)
|
|
15
17
|
&& syntaxTree(state).resolveInner(pos, 0).name === 'RegExp';
|
|
16
18
|
/**
|
|
17
|
-
*
|
|
19
|
+
* 高亮显示全局变量和JSDoc标签
|
|
18
20
|
* @ignore
|
|
19
21
|
* @test
|
|
20
22
|
*/
|
|
21
|
-
export const
|
|
23
|
+
export const markGlobalsAndDocTag = (tree, visibleRanges, state, cm) => {
|
|
22
24
|
const decorations = [];
|
|
23
25
|
let allGlobals = builtinGlobals;
|
|
24
26
|
if (cm?.lintSources.length && typeof eslint === 'object' && 'environments' in eslint) {
|
|
@@ -49,10 +51,29 @@ export const markGlobals = (tree, visibleRanges, state, cm) => {
|
|
|
49
51
|
to,
|
|
50
52
|
enter({ type, from: f, to: t }) {
|
|
51
53
|
const name = state.sliceDoc(f, t);
|
|
52
|
-
if (
|
|
54
|
+
if (!javascriptLanguage.isActiveAt(state, f)) {
|
|
55
|
+
//
|
|
56
|
+
}
|
|
57
|
+
else if (type.is('VariableName') && allGlobals.has(name)) {
|
|
53
58
|
const completions = localCompletionSource({ state, pos: t, explicit: true });
|
|
54
59
|
if (!completions?.options.some(({ label }) => label === name)) {
|
|
55
|
-
decorations
|
|
60
|
+
pushDecoration(decorations, globalsMark, f, t);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (type.is('BlockComment') && /^\/\*{2}(?!\*)/u.test(name)) {
|
|
64
|
+
const comment = name.slice(2), pos = f + 2, mtAll = comment.matchAll(/^[ \t]*\*\s*(@[a-z]+)(\s+\{)?|\{(@[a-z]+)/dgimu);
|
|
65
|
+
for (const mt of mtAll) {
|
|
66
|
+
if (mt[3]) {
|
|
67
|
+
const [start, end] = mt.indices[3];
|
|
68
|
+
pushDecoration(decorations, doctagMark, pos + start, pos + end);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const index = markDocTagType(decorations, pos, mt), m = /^\s+([a-z_]\w*)\s+-/diu.exec(comment.slice(index));
|
|
72
|
+
if (m) {
|
|
73
|
+
const [start, end] = m.indices[1];
|
|
74
|
+
pushDecoration(decorations, varMark, pos + index + start, pos + index + end);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
56
77
|
}
|
|
57
78
|
}
|
|
58
79
|
},
|
|
@@ -60,10 +81,10 @@ export const markGlobals = (tree, visibleRanges, state, cm) => {
|
|
|
60
81
|
}
|
|
61
82
|
return Decoration.set(decorations);
|
|
62
83
|
};
|
|
63
|
-
export const
|
|
84
|
+
export const markGlobalsAndDocTagPlugin = (cm) => ViewPlugin.fromClass(class {
|
|
64
85
|
constructor({ state, visibleRanges }) {
|
|
65
86
|
this.tree = syntaxTree(state);
|
|
66
|
-
this.decorations =
|
|
87
|
+
this.decorations = markGlobalsAndDocTag(this.tree, visibleRanges, state, cm);
|
|
67
88
|
}
|
|
68
89
|
update({ docChanged, viewportChanged, state, view: { visibleRanges }, transactions }) {
|
|
69
90
|
const tree = syntaxTree(state);
|
|
@@ -76,7 +97,7 @@ export const markGlobalsPlugin = (cm) => ViewPlugin.fromClass(class {
|
|
|
76
97
|
flag = transactions.some(tr => tr.effects.some(e => e.is(setDiagnosticsEffect)));
|
|
77
98
|
}
|
|
78
99
|
if (flag) {
|
|
79
|
-
this.decorations =
|
|
100
|
+
this.decorations = markGlobalsAndDocTag(tree, visibleRanges, state, cm);
|
|
80
101
|
}
|
|
81
102
|
}
|
|
82
103
|
}, {
|
|
@@ -87,5 +108,5 @@ export const markGlobalsPlugin = (cm) => ViewPlugin.fromClass(class {
|
|
|
87
108
|
export default (_, cm) => [
|
|
88
109
|
js(),
|
|
89
110
|
jsCompletion,
|
|
90
|
-
|
|
111
|
+
markGlobalsAndDocTagPlugin(cm),
|
|
91
112
|
];
|
package/dist/json.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { StreamParser, StringStream } from '@codemirror/language';
|
|
2
|
+
declare interface State {
|
|
3
|
+
tokenize: Tokenizer;
|
|
4
|
+
wb: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare type Tokenizer = (stream: StringStream, state: State) => string;
|
|
7
|
+
export declare const jsonBasic: StreamParser<State>, jsonc: StreamParser<State>;
|
|
8
|
+
export {};
|
package/dist/json.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const tokenNumber = (stream, state) => {
|
|
2
|
+
if (stream.match(/^\d+(?:\.\d+)?(?:e[+-]?\d+)?/iu)) {
|
|
3
|
+
state.wb = false;
|
|
4
|
+
return 'number';
|
|
5
|
+
}
|
|
6
|
+
state.wb = true;
|
|
7
|
+
return '';
|
|
8
|
+
};
|
|
9
|
+
const mkJson = (jsoncMode) => {
|
|
10
|
+
// Tokenizer
|
|
11
|
+
const tokenComment = (stream, state) => {
|
|
12
|
+
if (stream.skipTo('*/')) {
|
|
13
|
+
stream.next();
|
|
14
|
+
stream.next();
|
|
15
|
+
state.tokenize = tokenBase;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
stream.skipToEnd();
|
|
19
|
+
}
|
|
20
|
+
return 'comment';
|
|
21
|
+
};
|
|
22
|
+
const tokenBase = (stream, state) => {
|
|
23
|
+
if (stream.eatSpace()) {
|
|
24
|
+
state.wb = true;
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
const ch = stream.next();
|
|
28
|
+
switch (ch) {
|
|
29
|
+
case '{':
|
|
30
|
+
case '}':
|
|
31
|
+
state.wb = true;
|
|
32
|
+
return 'brace';
|
|
33
|
+
case '[':
|
|
34
|
+
case ']':
|
|
35
|
+
state.wb = true;
|
|
36
|
+
return 'squareBracket';
|
|
37
|
+
case ':':
|
|
38
|
+
case ',':
|
|
39
|
+
state.wb = true;
|
|
40
|
+
return 'separator';
|
|
41
|
+
case '/':
|
|
42
|
+
state.wb = true;
|
|
43
|
+
if (jsoncMode) {
|
|
44
|
+
if (stream.eat('/')) {
|
|
45
|
+
stream.skipToEnd();
|
|
46
|
+
return 'comment';
|
|
47
|
+
}
|
|
48
|
+
else if (stream.eat('*')) {
|
|
49
|
+
state.tokenize = tokenComment;
|
|
50
|
+
return tokenComment(stream, state);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return '';
|
|
54
|
+
case '"': {
|
|
55
|
+
state.wb = true;
|
|
56
|
+
let escaped = false, next = stream.next();
|
|
57
|
+
while (next) {
|
|
58
|
+
if (!escaped && next === '"') {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
escaped = !escaped && next === '\\';
|
|
62
|
+
next = stream.next();
|
|
63
|
+
}
|
|
64
|
+
return stream.match(/^\s*:/u, false) ? 'propertyName.definition' : 'string';
|
|
65
|
+
}
|
|
66
|
+
case '-':
|
|
67
|
+
if (state.wb) {
|
|
68
|
+
return tokenNumber(stream, state);
|
|
69
|
+
}
|
|
70
|
+
state.wb = true;
|
|
71
|
+
return '';
|
|
72
|
+
default:
|
|
73
|
+
if (state.wb) {
|
|
74
|
+
if (ch >= '0' && ch <= '9') {
|
|
75
|
+
stream.backUp(1);
|
|
76
|
+
return tokenNumber(stream, state);
|
|
77
|
+
}
|
|
78
|
+
else if (ch === 'n' && stream.match(/^ull\b/u)) {
|
|
79
|
+
state.wb = false;
|
|
80
|
+
return 'null';
|
|
81
|
+
}
|
|
82
|
+
else if (ch === 't' && stream.match(/^rue\b/u)
|
|
83
|
+
|| ch === 'f' && stream.match(/^alse\b/u)) {
|
|
84
|
+
state.wb = false;
|
|
85
|
+
return 'bool';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
state.wb = !/[\w$]/u.test(ch);
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
// Interface
|
|
93
|
+
return {
|
|
94
|
+
startState() {
|
|
95
|
+
return {
|
|
96
|
+
tokenize: tokenBase,
|
|
97
|
+
wb: true,
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
token(stream, state) {
|
|
101
|
+
if (stream.sol()) {
|
|
102
|
+
state.wb = true;
|
|
103
|
+
}
|
|
104
|
+
return state.tokenize(stream, state);
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
export const jsonBasic = mkJson(), jsonc = mkJson(true);
|
package/dist/keymap.d.ts
CHANGED
|
@@ -9,6 +9,6 @@ import type { KeymapConfig } from './keybindings';
|
|
|
9
9
|
* @param opt.splitlines 是否分行
|
|
10
10
|
* @test
|
|
11
11
|
*/
|
|
12
|
-
export declare const
|
|
12
|
+
export declare const getWikiKeymap: ({ key, pre, post, splitlines }: KeymapConfig) => KeyBinding;
|
|
13
13
|
declare const _default: KeyBinding[];
|
|
14
14
|
export default _default;
|