@bhsd/codemirror-mediawiki 2.30.3 → 3.0.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 +177 -27
- package/dist/codemirror.d.ts +74 -48
- package/dist/codemirror.js +180 -229
- package/dist/color.d.ts +1 -6
- package/dist/color.js +1 -8
- package/dist/config.js +5 -6
- package/dist/escape.js +2 -2
- package/dist/fold.d.ts +53 -6
- package/dist/fold.js +140 -136
- package/dist/hover.js +1 -1
- package/dist/indent.d.ts +5 -1
- package/dist/indent.js +2 -1
- package/dist/inlay.js +1 -1
- package/dist/javascript.d.ts +1 -0
- package/dist/javascript.js +2 -4
- package/dist/keybindings.js +1 -0
- package/dist/linter.d.ts +1 -1
- package/dist/linter.js +47 -11
- package/dist/lintsource.d.ts +14 -0
- package/dist/lintsource.js +159 -0
- package/dist/lsp.d.ts +3 -0
- package/dist/lsp.js +34 -0
- package/dist/main.min.js +25 -24
- package/dist/matchBrackets.d.ts +1 -1
- package/dist/matchTag.js +2 -2
- package/dist/mediawiki.js +3 -2
- package/dist/mw.min.js +30 -29
- package/dist/mwConfig.js +2 -5
- package/dist/ref.js +1 -1
- package/dist/signature.js +1 -1
- package/dist/statusBar.d.ts +1 -1
- package/dist/token.d.ts +14 -12
- package/dist/token.js +83 -62
- package/dist/vue.d.ts +3 -0
- package/dist/vue.js +14 -0
- package/dist/wiki.min.js +29 -28
- package/i18n/en.json +2 -3
- package/i18n/zh-hans.json +2 -3
- package/i18n/zh-hant.json +2 -3
- package/package.json +21 -12
package/dist/fold.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
1
|
+
import { GutterMarker, ViewPlugin } from '@codemirror/view';
|
|
2
|
+
import { RangeSet } from '@codemirror/state';
|
|
3
|
+
import type { EditorView, Tooltip, ViewUpdate, 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;
|
|
9
12
|
/**
|
|
10
13
|
* Update the stack of opening (+) or closing (-) brackets
|
|
11
14
|
* @param state
|
|
@@ -20,12 +23,56 @@ export declare const braceStackUpdate: (state: EditorState, node: SyntaxNode) =>
|
|
|
20
23
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
21
24
|
*/
|
|
22
25
|
export declare const foldable: (state: EditorState, posOrNode: number | SyntaxNode, tree?: Tree | null, refOnly?: boolean) => DocRange | false;
|
|
26
|
+
/**
|
|
27
|
+
* 创建折叠提示
|
|
28
|
+
* @param state
|
|
29
|
+
*/
|
|
30
|
+
export declare const create: (state: EditorState) => Tooltip | null;
|
|
31
|
+
/**
|
|
32
|
+
* 执行折叠
|
|
33
|
+
* @param view
|
|
34
|
+
* @param effects 折叠
|
|
35
|
+
* @param anchor 光标位置
|
|
36
|
+
*/
|
|
37
|
+
export declare const execute: (view: EditorView, effects: StateEffect<DocRange>[], anchor: number) => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* The rightmost position of all selections, to be updated with folding
|
|
40
|
+
* @param state
|
|
41
|
+
*/
|
|
42
|
+
export declare const getAnchor: (state: EditorState) => number;
|
|
43
|
+
/**
|
|
44
|
+
* 折叠所有模板
|
|
45
|
+
* @param state
|
|
46
|
+
* @param tree 语法树
|
|
47
|
+
* @param effects 折叠
|
|
48
|
+
* @param node 语法树节点
|
|
49
|
+
* @param end 终止位置
|
|
50
|
+
* @param anchor 光标位置
|
|
51
|
+
* @param update 更新光标位置
|
|
52
|
+
* @param refOnly 是否仅检查`<ref>`标签
|
|
53
|
+
*/
|
|
54
|
+
export declare const traverse: (state: EditorState, tree: Tree, effects: StateEffect<DocRange>[], node: SyntaxNode | null, end: number, anchor: number, update: AnchorUpdate, refOnly?: boolean) => number;
|
|
55
|
+
export declare class FoldMarker extends GutterMarker {
|
|
56
|
+
readonly open: boolean;
|
|
57
|
+
constructor(open: boolean);
|
|
58
|
+
eq(other: this): boolean;
|
|
59
|
+
toDOM({ state }: EditorView): HTMLSpanElement;
|
|
60
|
+
}
|
|
61
|
+
export declare const findFold: ({ state }: EditorView, line: BlockInfo) => DocRange | undefined;
|
|
23
62
|
export declare const foldableLine: ({ state, viewport: { to: end }, viewportLineBlocks }: EditorView, { from: f, to: t }: DocRange) => DocRange | false;
|
|
63
|
+
export declare const markers: ViewPlugin<{
|
|
64
|
+
markers: RangeSet<FoldMarker>;
|
|
65
|
+
update({ docChanged, viewportChanged, startState, state, view }: ViewUpdate): void;
|
|
66
|
+
}, undefined>;
|
|
67
|
+
/**
|
|
68
|
+
* 生成折叠命令
|
|
69
|
+
* @param refOnly 是否仅检查`<ref>`标签
|
|
70
|
+
*/
|
|
71
|
+
export declare const foldCommand: (refOnly?: boolean) => Command;
|
|
24
72
|
export declare const foldRef: Command;
|
|
25
|
-
declare const _default: [(e?: Extension | undefined) => Extension
|
|
26
|
-
mediawiki: (Extension | StateField<Tooltip | null>)[];
|
|
27
|
-
}];
|
|
73
|
+
declare const _default: [(e?: Extension | undefined) => Extension];
|
|
28
74
|
export default _default;
|
|
75
|
+
export declare const mediaWikiFold: Extension;
|
|
29
76
|
/**
|
|
30
77
|
* 点击提示折叠模板参数
|
|
31
78
|
* @param view
|
package/dist/fold.js
CHANGED
|
@@ -4,24 +4,32 @@ import { syntaxTree, ensureSyntaxTree, foldEffect, unfoldEffect, foldedRanges, u
|
|
|
4
4
|
import { getRegex } from '@bhsd/common';
|
|
5
5
|
import { tokens } from './config';
|
|
6
6
|
import { matchTag, getTag } from './matchTag';
|
|
7
|
-
const getExtRegex = getRegex(tag => new RegExp(`mw-tag-${tag}(?![a-z])`, 'u'));
|
|
8
|
-
const updateSelection = (pos, { to }) => Math.max(pos, to)
|
|
7
|
+
const getExtRegex = /* @__PURE__ */ getRegex(tag => new RegExp(`mw-tag-${tag}(?![a-z])`, 'u'));
|
|
8
|
+
export const updateSelection = (pos, { to }) => Math.max(pos, to);
|
|
9
|
+
const updateAll = (pos, { from, to }) => from <= pos && to > pos ? to : pos;
|
|
9
10
|
/**
|
|
10
11
|
* Check if a SyntaxNode is among the specified components
|
|
11
12
|
* @param keys The keys of the tokens to check
|
|
12
13
|
*/
|
|
13
|
-
const isComponent = (keys) => (
|
|
14
|
+
const isComponent = (keys) => (node) => keys.some(key => node?.name.includes(tokens[key])),
|
|
14
15
|
/** Check if a SyntaxNode is a template bracket (`{{` or `}}`) */
|
|
15
|
-
isTemplateBracket = isComponent(['templateBracket', 'parserFunctionBracket']),
|
|
16
|
+
isTemplateBracket = /* @__PURE__ */ isComponent(['templateBracket', 'parserFunctionBracket']),
|
|
17
|
+
/** Check if a SyntaxNode is a template name */
|
|
18
|
+
isTemplateName = /* @__PURE__ */ isComponent(['templateName', 'parserFunctionName']),
|
|
16
19
|
/** Check if a SyntaxNode is a template delimiter (`|` or `:`) */
|
|
17
|
-
isDelimiter = isComponent(['templateDelimiter', 'parserFunctionDelimiter']),
|
|
20
|
+
isDelimiter = /* @__PURE__ */ isComponent(['templateDelimiter', 'parserFunctionDelimiter']),
|
|
21
|
+
/**
|
|
22
|
+
* Check if a SyntaxNode is a template delimiter (`|` or `:`), excluding `subst:` and `safesubst:`
|
|
23
|
+
* @param node SyntaxNode
|
|
24
|
+
*/
|
|
25
|
+
isTemplateDelimiter = (node) => isDelimiter(node) && !isTemplateName(node.nextSibling),
|
|
18
26
|
/**
|
|
19
27
|
* Check if a SyntaxNode is part of a template, except for the brackets
|
|
20
28
|
* @param node 语法树节点
|
|
21
29
|
*/
|
|
22
30
|
isTemplate = (node) => /-(?:template|ext)[a-z\d-]+ground/u.test(node.name) && !isTemplateBracket(node),
|
|
23
31
|
/** Check if a SyntaxNode is an extension tag bracket (`<` or `>`) */
|
|
24
|
-
isExtBracket = isComponent(['extTagBracket']),
|
|
32
|
+
isExtBracket = /* @__PURE__ */ isComponent(['extTagBracket']),
|
|
25
33
|
/**
|
|
26
34
|
* Check if a SyntaxNode is part of a extension tag
|
|
27
35
|
* @param node 语法树节点
|
|
@@ -88,7 +96,7 @@ export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
|
88
96
|
}
|
|
89
97
|
let { prevSibling, nextSibling } = node,
|
|
90
98
|
/** The stack of opening (+) or closing (-) brackets */ stack = 1,
|
|
91
|
-
/** The first delimiter */ delimiter =
|
|
99
|
+
/** The first delimiter */ delimiter = isTemplateDelimiter(node) ? node : null,
|
|
92
100
|
/** The start of the closing bracket */ to = 0;
|
|
93
101
|
while (nextSibling) {
|
|
94
102
|
if (isTemplateBracket(nextSibling)) {
|
|
@@ -103,7 +111,7 @@ export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
|
103
111
|
}
|
|
104
112
|
stack += lbrace;
|
|
105
113
|
}
|
|
106
|
-
else if (!delimiter && stack === 1 &&
|
|
114
|
+
else if (!delimiter && stack === 1 && isTemplateDelimiter(nextSibling)) {
|
|
107
115
|
// The first delimiter of the current template so far
|
|
108
116
|
delimiter = nextSibling;
|
|
109
117
|
}
|
|
@@ -124,7 +132,7 @@ export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
|
124
132
|
}
|
|
125
133
|
stack += rbrace;
|
|
126
134
|
}
|
|
127
|
-
else if (stack === -1 &&
|
|
135
|
+
else if (stack === -1 && isTemplateDelimiter(prevSibling)) {
|
|
128
136
|
// The first delimiter of the current template so far
|
|
129
137
|
delimiter = prevSibling;
|
|
130
138
|
}
|
|
@@ -137,7 +145,7 @@ export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
|
137
145
|
* 创建折叠提示
|
|
138
146
|
* @param state
|
|
139
147
|
*/
|
|
140
|
-
const create = (state) => {
|
|
148
|
+
export const create = (state) => {
|
|
141
149
|
const { selection: { main: { head } } } = state, range = foldable(state, head);
|
|
142
150
|
if (range) {
|
|
143
151
|
const { from, to } = range;
|
|
@@ -171,7 +179,7 @@ const create = (state) => {
|
|
|
171
179
|
* @param effects 折叠
|
|
172
180
|
* @param anchor 光标位置
|
|
173
181
|
*/
|
|
174
|
-
const execute = (view, effects, anchor) => {
|
|
182
|
+
export const execute = (view, effects, anchor) => {
|
|
175
183
|
if (effects.length > 0) {
|
|
176
184
|
view.dom.querySelector('.cm-tooltip-fold')?.remove();
|
|
177
185
|
// Fold the template(s) and update the cursor position
|
|
@@ -184,7 +192,7 @@ const execute = (view, effects, anchor) => {
|
|
|
184
192
|
* The rightmost position of all selections, to be updated with folding
|
|
185
193
|
* @param state
|
|
186
194
|
*/
|
|
187
|
-
const getAnchor = (state) => Math.max(...state.selection.ranges.map(({ to }) => to));
|
|
195
|
+
export const getAnchor = (state) => Math.max(...state.selection.ranges.map(({ to }) => to));
|
|
188
196
|
/**
|
|
189
197
|
* 折叠所有模板
|
|
190
198
|
* @param state
|
|
@@ -196,7 +204,7 @@ const getAnchor = (state) => Math.max(...state.selection.ranges.map(({ to }) =>
|
|
|
196
204
|
* @param update 更新光标位置
|
|
197
205
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
198
206
|
*/
|
|
199
|
-
const traverse = (state, tree, effects, node, end, anchor, update, refOnly) => {
|
|
207
|
+
export const traverse = (state, tree, effects, node, end, anchor, update, refOnly) => {
|
|
200
208
|
while (node && node.from <= end) {
|
|
201
209
|
/* eslint-disable no-param-reassign */
|
|
202
210
|
const range = foldable(state, node, tree, refOnly);
|
|
@@ -212,7 +220,7 @@ const traverse = (state, tree, effects, node, end, anchor, update, refOnly) => {
|
|
|
212
220
|
}
|
|
213
221
|
return anchor;
|
|
214
222
|
};
|
|
215
|
-
class FoldMarker extends GutterMarker {
|
|
223
|
+
export class FoldMarker extends GutterMarker {
|
|
216
224
|
constructor(open) {
|
|
217
225
|
super();
|
|
218
226
|
this.open = open;
|
|
@@ -227,8 +235,8 @@ class FoldMarker extends GutterMarker {
|
|
|
227
235
|
return span;
|
|
228
236
|
}
|
|
229
237
|
}
|
|
230
|
-
const canFold = new FoldMarker(true), canUnfold = new FoldMarker(false);
|
|
231
|
-
const findFold = ({ state }, line) => {
|
|
238
|
+
const canFold = /* @__PURE__ */ new FoldMarker(true), canUnfold = /* @__PURE__ */ new FoldMarker(false);
|
|
239
|
+
export const findFold = ({ state }, line) => {
|
|
232
240
|
let found;
|
|
233
241
|
state.field(foldState, false)?.between(line.from, line.to, (from, to) => {
|
|
234
242
|
if (!found && to === line.to) {
|
|
@@ -302,7 +310,7 @@ const buildMarkers = (view) => {
|
|
|
302
310
|
}
|
|
303
311
|
return builder.finish();
|
|
304
312
|
};
|
|
305
|
-
const markers = ViewPlugin.fromClass(class {
|
|
313
|
+
export const markers = /* @__PURE__ */ ViewPlugin.fromClass(class {
|
|
306
314
|
constructor(view) {
|
|
307
315
|
this.markers = buildMarkers(view);
|
|
308
316
|
}
|
|
@@ -321,129 +329,125 @@ const defaultFoldExtension = [foldGutter(), keymap.of(foldKeymap)];
|
|
|
321
329
|
* 生成折叠命令
|
|
322
330
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
323
331
|
*/
|
|
324
|
-
const foldCommand = (refOnly) => view => {
|
|
332
|
+
export const foldCommand = (refOnly) => view => {
|
|
325
333
|
const { state } = view, tree = syntaxTree(state), effects = [], anchor = traverse(state, tree, effects, tree.topNode.firstChild, Infinity, getAnchor(state), updateAll, refOnly);
|
|
326
334
|
return execute(view, effects, anchor);
|
|
327
335
|
};
|
|
328
|
-
export const foldRef = foldCommand(true);
|
|
329
|
-
export default [
|
|
330
|
-
|
|
331
|
-
{
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
// Unfold the template and redraw the selections
|
|
345
|
-
view.dispatch({ effects: unfoldEffect.of({ from, to }), selection });
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
return element;
|
|
350
|
-
},
|
|
351
|
-
}),
|
|
352
|
-
/** @see https://codemirror.net/examples/tooltip/ */
|
|
353
|
-
StateField.define({
|
|
354
|
-
create,
|
|
355
|
-
update(tooltip, { state, docChanged, selection }) {
|
|
356
|
-
if (docChanged) {
|
|
357
|
-
return null;
|
|
336
|
+
export const foldRef = /* @__PURE__ */ foldCommand(true);
|
|
337
|
+
export default [(e = defaultFoldExtension) => e];
|
|
338
|
+
export const mediaWikiFold = /* @__PURE__ */ (() => [
|
|
339
|
+
codeFolding({
|
|
340
|
+
placeholderDOM(view) {
|
|
341
|
+
const element = document.createElement('span');
|
|
342
|
+
element.textContent = '…';
|
|
343
|
+
element.setAttribute('aria-label', 'folded code');
|
|
344
|
+
element.title = view.state.phrase('unfold');
|
|
345
|
+
element.className = 'cm-foldPlaceholder';
|
|
346
|
+
element.addEventListener('click', ({ target }) => {
|
|
347
|
+
const pos = view.posAtDOM(target), { state } = view, { selection } = state;
|
|
348
|
+
foldedRanges(state).between(pos, pos, (from, to) => {
|
|
349
|
+
if (from === pos) {
|
|
350
|
+
// Unfold the template and redraw the selections
|
|
351
|
+
view.dispatch({ effects: unfoldEffect.of({ from, to }), selection });
|
|
358
352
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
return element;
|
|
356
|
+
},
|
|
357
|
+
}),
|
|
358
|
+
/** @see https://codemirror.net/examples/tooltip/ */
|
|
359
|
+
StateField.define({
|
|
360
|
+
create,
|
|
361
|
+
update(tooltip, { state, docChanged, selection }) {
|
|
362
|
+
if (docChanged) {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
return selection ? create(state) : tooltip;
|
|
366
|
+
},
|
|
367
|
+
provide(f) {
|
|
368
|
+
return showTooltip.from(f);
|
|
369
|
+
},
|
|
370
|
+
}),
|
|
371
|
+
keymap.of([
|
|
372
|
+
{
|
|
373
|
+
// Fold the template at the selection/cursor
|
|
374
|
+
key: 'Ctrl-Shift-[',
|
|
375
|
+
mac: 'Cmd-Alt-[',
|
|
376
|
+
run(view) {
|
|
377
|
+
const { state } = view, tree = syntaxTree(state), effects = [];
|
|
378
|
+
let anchor = getAnchor(state);
|
|
379
|
+
for (const { from, to, empty } of state.selection.ranges) {
|
|
380
|
+
let node;
|
|
381
|
+
if (empty) {
|
|
382
|
+
// No selection, try both sides of the cursor position
|
|
383
|
+
node = tree.resolve(from, -1);
|
|
384
|
+
}
|
|
385
|
+
if (!node || node.name === 'Document') {
|
|
386
|
+
node = tree.resolve(from, 1);
|
|
387
|
+
}
|
|
388
|
+
anchor = traverse(state, tree, effects, node, to, anchor, updateSelection);
|
|
389
|
+
}
|
|
390
|
+
return execute(view, effects, anchor);
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
// Fold all templates in the document
|
|
395
|
+
key: 'Ctrl-Alt-[',
|
|
396
|
+
run: foldCommand(),
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
// Fold all `<ref>` tags in the document
|
|
400
|
+
key: 'Mod-Alt-,',
|
|
401
|
+
run: foldRef,
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
// Unfold the template at the selection/cursor
|
|
405
|
+
key: 'Ctrl-Shift-]',
|
|
406
|
+
mac: 'Cmd-Alt-]',
|
|
407
|
+
run(view) {
|
|
408
|
+
const { state } = view, { selection } = state, effects = [], folded = foldedRanges(state);
|
|
409
|
+
for (const { from, to } of selection.ranges) {
|
|
410
|
+
// Unfold any folded range at the selection
|
|
411
|
+
folded.between(from, to, (i, j) => {
|
|
412
|
+
effects.push(unfoldEffect.of({ from: i, to: j }));
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
if (effects.length > 0) {
|
|
416
|
+
// Unfold the template(s) and redraw the selections
|
|
417
|
+
view.dispatch({ effects, selection });
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
return false;
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
{ key: 'Ctrl-Alt-]', run: unfoldAll },
|
|
424
|
+
]),
|
|
425
|
+
markers,
|
|
426
|
+
gutter({
|
|
427
|
+
class: 'cm-foldGutter',
|
|
428
|
+
markers(view) {
|
|
429
|
+
return view.plugin(markers)?.markers ?? RangeSet.empty;
|
|
430
|
+
},
|
|
431
|
+
initialSpacer() {
|
|
432
|
+
return new FoldMarker(false);
|
|
433
|
+
},
|
|
434
|
+
domEventHandlers: {
|
|
435
|
+
click(view, line) {
|
|
436
|
+
const folded = findFold(view, line);
|
|
437
|
+
if (folded) {
|
|
438
|
+
view.dispatch({ effects: unfoldEffect.of(folded) });
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
const range = foldableLine(view, line);
|
|
442
|
+
if (range) {
|
|
443
|
+
view.dispatch({ effects: foldEffect.of(range) });
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
return false;
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
}),
|
|
450
|
+
])();
|
|
447
451
|
/**
|
|
448
452
|
* 点击提示折叠模板参数
|
|
449
453
|
* @param view
|
package/dist/hover.js
CHANGED
package/dist/indent.d.ts
CHANGED
package/dist/indent.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const noDetectionLangs = new Set(['plain', 'mediawiki', 'html']);
|
|
2
|
+
const getLines = (text) => text.children?.flatMap(getLines) ?? text.text;
|
|
2
3
|
/**
|
|
3
4
|
* 检测文本的缩进方式
|
|
4
5
|
* @param text 文本内容
|
|
@@ -9,7 +10,7 @@ export const detectIndent = (text, defaultIndent, lang) => {
|
|
|
9
10
|
if (noDetectionLangs.has(lang)) {
|
|
10
11
|
return defaultIndent;
|
|
11
12
|
}
|
|
12
|
-
const lineSpaces = [], lines = typeof text === 'string' ? text.split('\n') : text
|
|
13
|
+
const lineSpaces = [], lines = typeof text === 'string' ? text.split('\n') : getLines(text);
|
|
13
14
|
let tabLines = 0;
|
|
14
15
|
for (const line of lines) {
|
|
15
16
|
if (!line.trim()) {
|
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/javascript.d.ts
CHANGED
package/dist/javascript.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import { javascript as js, javascriptLanguage, scopeCompletionSource } from '@codemirror/lang-javascript';
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
javascriptLanguage.data.of({ autocomplete: scopeCompletionSource(globalThis) }),
|
|
5
|
-
];
|
|
2
|
+
export const jsCompletion = javascriptLanguage.data.of({ autocomplete: scopeCompletionSource(globalThis) });
|
|
3
|
+
export default () => [js(), jsCompletion];
|
package/dist/keybindings.js
CHANGED
|
@@ -2,6 +2,7 @@ export const keybindings = [
|
|
|
2
2
|
{ key: 'Ctrl-8', pre: '<blockquote>', post: '</blockquote>', desc: 'blockquote' },
|
|
3
3
|
{ key: 'Mod-.', pre: '<sup>', post: '</sup>', desc: 'sup' },
|
|
4
4
|
{ key: 'Mod-,', pre: '<sub>', post: '</sub>', desc: 'sub' },
|
|
5
|
+
{ key: 'Ctrl-,', pre: '<sub>', post: '</sub>', desc: 'sub' },
|
|
5
6
|
{ key: 'Mod-Shift-6', pre: '<code>', post: '</code>', desc: 'code' },
|
|
6
7
|
{ key: 'Ctrl-Shift-5', pre: '<s>', post: '</s>', desc: 's' },
|
|
7
8
|
{ key: 'Mod-u', pre: '<u>', post: '</u>', desc: 'u' },
|
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,17 +1,38 @@
|
|
|
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 范围
|
|
7
|
-
* @param
|
|
8
|
-
* @param
|
|
8
|
+
* @param lineOrOffset 行号或相对位置
|
|
9
|
+
* @param columnOrPrefix 列号或前缀
|
|
9
10
|
*/
|
|
10
|
-
const offsetAt = (range,
|
|
11
|
-
if (
|
|
11
|
+
const offsetAt = (range, lineOrOffset, columnOrPrefix) => {
|
|
12
|
+
if (typeof columnOrPrefix === 'string') {
|
|
13
|
+
return Math.min(range[1], range[0] + Math.max(0, lineOrOffset - columnOrPrefix.length));
|
|
14
|
+
}
|
|
15
|
+
else if (lineOrOffset === -2) {
|
|
12
16
|
return range[0];
|
|
13
17
|
}
|
|
14
|
-
return
|
|
18
|
+
return lineOrOffset === 0 ? range[1] : range[0] + columnOrPrefix;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* 获取伪CSS代码块的前缀
|
|
22
|
+
* @param token AST 节点
|
|
23
|
+
* @param token.type 节点类型
|
|
24
|
+
* @param token.tag 节点标签
|
|
25
|
+
* @param i 节点序号
|
|
26
|
+
*/
|
|
27
|
+
const getPrefix = ({ type, tag }, i) => `${type === 'ext-attr' ? 'div' : tag}#${i}{\n`;
|
|
28
|
+
/**
|
|
29
|
+
* 将偏移量转换为位置
|
|
30
|
+
* @param code 代码字符串
|
|
31
|
+
* @param index 偏移量
|
|
32
|
+
*/
|
|
33
|
+
const indexToPos = (code, index) => {
|
|
34
|
+
const lines = code.slice(0, index).split('\n');
|
|
35
|
+
return { line: lines.length - 1, character: lines[lines.length - 1].length };
|
|
15
36
|
};
|
|
16
37
|
/**
|
|
17
38
|
* 获取 Wikitext LSP
|
|
@@ -22,16 +43,16 @@ export const getWikiLinter = async (opt, obj) => {
|
|
|
22
43
|
await getWikiparse(opt?.['getConfig'], opt?.['i18n']);
|
|
23
44
|
const lsp = getLSP(obj, opt?.['include']);
|
|
24
45
|
return async (text, config) => {
|
|
25
|
-
const diagnostics = (await lsp.provideDiagnostics(text)).filter(({ code, severity }) => Number(config?.[code] ??
|
|
46
|
+
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
47
|
if (tokens.length === 0) {
|
|
27
48
|
return diagnostics;
|
|
28
49
|
}
|
|
29
50
|
const cssLint = await getCssLinter();
|
|
30
51
|
return [
|
|
31
52
|
...diagnostics,
|
|
32
|
-
...(await cssLint(tokens.map((
|
|
33
|
-
.replace(/\n/gu, ' ')}\n}`).join('\n'))).map(({ line, column, endLine, endColumn, rule, severity, text: message }) => {
|
|
34
|
-
const i = Math.ceil(line / 3), { range } = tokens[i - 1].childNodes[1].childNodes[0], from = offsetAt(range, line - 3 * i, column - 1);
|
|
53
|
+
...(await cssLint(tokens.map((token, i) => `${getPrefix(token, i)}${sanitizeInlineStyle(token.childNodes[1].childNodes[0].data)
|
|
54
|
+
.replace(/\n/gu, ' ')}\n}`).join('\n'), config?.['css'])).map(({ line, column, endLine, endColumn, rule, severity, text: message, fix }) => {
|
|
55
|
+
const i = Math.ceil(line / 3), prefix = getPrefix(tokens[i - 1], i), { range } = tokens[i - 1].childNodes[1].childNodes[0], from = offsetAt(range, line - 3 * i, column - 1);
|
|
35
56
|
return {
|
|
36
57
|
from,
|
|
37
58
|
to: endLine === undefined ? from : offsetAt(range, endLine - 3 * i, endColumn - 1),
|
|
@@ -39,6 +60,21 @@ export const getWikiLinter = async (opt, obj) => {
|
|
|
39
60
|
source: 'Stylelint',
|
|
40
61
|
code: rule,
|
|
41
62
|
message,
|
|
63
|
+
...fix
|
|
64
|
+
? {
|
|
65
|
+
data: [
|
|
66
|
+
{
|
|
67
|
+
range: {
|
|
68
|
+
start: indexToPos(text, offsetAt(range, fix.range[0], prefix)),
|
|
69
|
+
end: indexToPos(text, offsetAt(range, fix.range[1], prefix)),
|
|
70
|
+
},
|
|
71
|
+
newText: fix.text,
|
|
72
|
+
title: 'Fix: Stylelint',
|
|
73
|
+
fix: true,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
}
|
|
77
|
+
: {},
|
|
42
78
|
};
|
|
43
79
|
}),
|
|
44
80
|
];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EditorView } from '@codemirror/view';
|
|
2
|
+
import type { EditorState, Text } from '@codemirror/state';
|
|
3
|
+
import type { Diagnostic } from '@codemirror/lint';
|
|
4
|
+
import type { Option, LiveOption } from './linter';
|
|
5
|
+
export type LintSource = ((state: EditorState) => Diagnostic[] | Promise<Diagnostic[]>) & {
|
|
6
|
+
fixer?: (doc: Text, rule?: string) => string | Promise<string>;
|
|
7
|
+
};
|
|
8
|
+
export type LintSourceGetter = (opt?: Option | LiveOption, view?: EditorView) => LintSource | Promise<LintSource>;
|
|
9
|
+
export declare const getWikiLintSource: LintSourceGetter;
|
|
10
|
+
export declare const getJsLintSource: LintSourceGetter;
|
|
11
|
+
export declare const getCssLintSource: LintSourceGetter;
|
|
12
|
+
export declare const getVueLintSource: LintSourceGetter;
|
|
13
|
+
export declare const getJsonLintSource: LintSourceGetter;
|
|
14
|
+
export declare const getLuaLintSource: LintSourceGetter;
|