@bhsd/codemirror-mediawiki 2.31.0 → 3.0.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 +181 -32
- package/dist/codemirror.d.ts +72 -47
- package/dist/codemirror.js +169 -208
- package/dist/color.d.ts +1 -6
- package/dist/color.js +1 -8
- package/dist/config.js +4 -4
- package/dist/escape.js +2 -2
- package/dist/fold.d.ts +53 -6
- package/dist/fold.js +130 -133
- package/dist/indent.d.ts +5 -1
- package/dist/indent.js +2 -1
- package/dist/javascript.d.ts +1 -0
- package/dist/javascript.js +2 -4
- package/dist/keybindings.js +1 -0
- package/dist/linter.js +43 -8
- package/dist/lintsource.d.ts +14 -0
- package/dist/lintsource.js +159 -0
- package/dist/main.min.js +25 -24
- package/dist/matchBrackets.d.ts +1 -1
- package/dist/matchTag.js +2 -2
- package/dist/mw.min.js +26 -25
- package/dist/mwConfig.js +0 -3
- package/dist/statusBar.d.ts +1 -1
- package/dist/token.d.ts +1 -1
- package/dist/token.js +11 -16
- package/dist/vue.d.ts +3 -0
- package/dist/vue.js +14 -0
- package/dist/wiki.min.js +25 -24
- package/i18n/en.json +2 -3
- package/i18n/zh-hans.json +2 -3
- package/i18n/zh-hant.json +2 -3
- package/package.json +10 -7
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,19 +4,20 @@ 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
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']),
|
|
16
17
|
/** Check if a SyntaxNode is a template name */
|
|
17
|
-
isTemplateName = isComponent(['templateName', 'parserFunctionName']),
|
|
18
|
+
isTemplateName = /* @__PURE__ */ isComponent(['templateName', 'parserFunctionName']),
|
|
18
19
|
/** Check if a SyntaxNode is a template delimiter (`|` or `:`) */
|
|
19
|
-
isDelimiter = isComponent(['templateDelimiter', 'parserFunctionDelimiter']),
|
|
20
|
+
isDelimiter = /* @__PURE__ */ isComponent(['templateDelimiter', 'parserFunctionDelimiter']),
|
|
20
21
|
/**
|
|
21
22
|
* Check if a SyntaxNode is a template delimiter (`|` or `:`), excluding `subst:` and `safesubst:`
|
|
22
23
|
* @param node SyntaxNode
|
|
@@ -28,7 +29,7 @@ isTemplateDelimiter = (node) => isDelimiter(node) && !isTemplateName(node.nextSi
|
|
|
28
29
|
*/
|
|
29
30
|
isTemplate = (node) => /-(?:template|ext)[a-z\d-]+ground/u.test(node.name) && !isTemplateBracket(node),
|
|
30
31
|
/** Check if a SyntaxNode is an extension tag bracket (`<` or `>`) */
|
|
31
|
-
isExtBracket = isComponent(['extTagBracket']),
|
|
32
|
+
isExtBracket = /* @__PURE__ */ isComponent(['extTagBracket']),
|
|
32
33
|
/**
|
|
33
34
|
* Check if a SyntaxNode is part of a extension tag
|
|
34
35
|
* @param node 语法树节点
|
|
@@ -144,7 +145,7 @@ export const foldable = (state, posOrNode, tree, refOnly = false) => {
|
|
|
144
145
|
* 创建折叠提示
|
|
145
146
|
* @param state
|
|
146
147
|
*/
|
|
147
|
-
const create = (state) => {
|
|
148
|
+
export const create = (state) => {
|
|
148
149
|
const { selection: { main: { head } } } = state, range = foldable(state, head);
|
|
149
150
|
if (range) {
|
|
150
151
|
const { from, to } = range;
|
|
@@ -178,7 +179,7 @@ const create = (state) => {
|
|
|
178
179
|
* @param effects 折叠
|
|
179
180
|
* @param anchor 光标位置
|
|
180
181
|
*/
|
|
181
|
-
const execute = (view, effects, anchor) => {
|
|
182
|
+
export const execute = (view, effects, anchor) => {
|
|
182
183
|
if (effects.length > 0) {
|
|
183
184
|
view.dom.querySelector('.cm-tooltip-fold')?.remove();
|
|
184
185
|
// Fold the template(s) and update the cursor position
|
|
@@ -191,7 +192,7 @@ const execute = (view, effects, anchor) => {
|
|
|
191
192
|
* The rightmost position of all selections, to be updated with folding
|
|
192
193
|
* @param state
|
|
193
194
|
*/
|
|
194
|
-
const getAnchor = (state) => Math.max(...state.selection.ranges.map(({ to }) => to));
|
|
195
|
+
export const getAnchor = (state) => Math.max(...state.selection.ranges.map(({ to }) => to));
|
|
195
196
|
/**
|
|
196
197
|
* 折叠所有模板
|
|
197
198
|
* @param state
|
|
@@ -203,7 +204,7 @@ const getAnchor = (state) => Math.max(...state.selection.ranges.map(({ to }) =>
|
|
|
203
204
|
* @param update 更新光标位置
|
|
204
205
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
205
206
|
*/
|
|
206
|
-
const traverse = (state, tree, effects, node, end, anchor, update, refOnly) => {
|
|
207
|
+
export const traverse = (state, tree, effects, node, end, anchor, update, refOnly) => {
|
|
207
208
|
while (node && node.from <= end) {
|
|
208
209
|
/* eslint-disable no-param-reassign */
|
|
209
210
|
const range = foldable(state, node, tree, refOnly);
|
|
@@ -219,7 +220,7 @@ const traverse = (state, tree, effects, node, end, anchor, update, refOnly) => {
|
|
|
219
220
|
}
|
|
220
221
|
return anchor;
|
|
221
222
|
};
|
|
222
|
-
class FoldMarker extends GutterMarker {
|
|
223
|
+
export class FoldMarker extends GutterMarker {
|
|
223
224
|
constructor(open) {
|
|
224
225
|
super();
|
|
225
226
|
this.open = open;
|
|
@@ -234,8 +235,8 @@ class FoldMarker extends GutterMarker {
|
|
|
234
235
|
return span;
|
|
235
236
|
}
|
|
236
237
|
}
|
|
237
|
-
const canFold = new FoldMarker(true), canUnfold = new FoldMarker(false);
|
|
238
|
-
const findFold = ({ state }, line) => {
|
|
238
|
+
const canFold = /* @__PURE__ */ new FoldMarker(true), canUnfold = /* @__PURE__ */ new FoldMarker(false);
|
|
239
|
+
export const findFold = ({ state }, line) => {
|
|
239
240
|
let found;
|
|
240
241
|
state.field(foldState, false)?.between(line.from, line.to, (from, to) => {
|
|
241
242
|
if (!found && to === line.to) {
|
|
@@ -309,7 +310,7 @@ const buildMarkers = (view) => {
|
|
|
309
310
|
}
|
|
310
311
|
return builder.finish();
|
|
311
312
|
};
|
|
312
|
-
const markers = ViewPlugin.fromClass(class {
|
|
313
|
+
export const markers = /* @__PURE__ */ ViewPlugin.fromClass(class {
|
|
313
314
|
constructor(view) {
|
|
314
315
|
this.markers = buildMarkers(view);
|
|
315
316
|
}
|
|
@@ -328,129 +329,125 @@ const defaultFoldExtension = [foldGutter(), keymap.of(foldKeymap)];
|
|
|
328
329
|
* 生成折叠命令
|
|
329
330
|
* @param refOnly 是否仅检查`<ref>`标签
|
|
330
331
|
*/
|
|
331
|
-
const foldCommand = (refOnly) => view => {
|
|
332
|
+
export const foldCommand = (refOnly) => view => {
|
|
332
333
|
const { state } = view, tree = syntaxTree(state), effects = [], anchor = traverse(state, tree, effects, tree.topNode.firstChild, Infinity, getAnchor(state), updateAll, refOnly);
|
|
333
334
|
return execute(view, effects, anchor);
|
|
334
335
|
};
|
|
335
|
-
export const foldRef = foldCommand(true);
|
|
336
|
-
export default [
|
|
337
|
-
|
|
338
|
-
{
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
// Unfold the template and redraw the selections
|
|
352
|
-
view.dispatch({ effects: unfoldEffect.of({ from, to }), selection });
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
return element;
|
|
357
|
-
},
|
|
358
|
-
}),
|
|
359
|
-
/** @see https://codemirror.net/examples/tooltip/ */
|
|
360
|
-
StateField.define({
|
|
361
|
-
create,
|
|
362
|
-
update(tooltip, { state, docChanged, selection }) {
|
|
363
|
-
if (docChanged) {
|
|
364
|
-
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 });
|
|
365
352
|
}
|
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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
|
+
])();
|
|
454
451
|
/**
|
|
455
452
|
* 点击提示折叠模板参数
|
|
456
453
|
* @param view
|
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/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.js
CHANGED
|
@@ -5,14 +5,34 @@ import { styleLint } from '@bhsd/stylelint-util';
|
|
|
5
5
|
/**
|
|
6
6
|
* 计算位置
|
|
7
7
|
* @param range 范围
|
|
8
|
-
* @param
|
|
9
|
-
* @param
|
|
8
|
+
* @param lineOrOffset 行号或相对位置
|
|
9
|
+
* @param columnOrPrefix 列号或前缀
|
|
10
10
|
*/
|
|
11
|
-
const offsetAt = (range,
|
|
12
|
-
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) {
|
|
13
16
|
return range[0];
|
|
14
17
|
}
|
|
15
|
-
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 };
|
|
16
36
|
};
|
|
17
37
|
/**
|
|
18
38
|
* 获取 Wikitext LSP
|
|
@@ -30,9 +50,9 @@ export const getWikiLinter = async (opt, obj) => {
|
|
|
30
50
|
const cssLint = await getCssLinter();
|
|
31
51
|
return [
|
|
32
52
|
...diagnostics,
|
|
33
|
-
...(await cssLint(tokens.map((
|
|
34
|
-
.replace(/\n/gu, ' ')}\n}`).join('\n'), config?.['css'])).map(({ line, column, endLine, endColumn, rule, severity, text: message }) => {
|
|
35
|
-
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);
|
|
36
56
|
return {
|
|
37
57
|
from,
|
|
38
58
|
to: endLine === undefined ? from : offsetAt(range, endLine - 3 * i, endColumn - 1),
|
|
@@ -40,6 +60,21 @@ export const getWikiLinter = async (opt, obj) => {
|
|
|
40
60
|
source: 'Stylelint',
|
|
41
61
|
code: rule,
|
|
42
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
|
+
: {},
|
|
43
78
|
};
|
|
44
79
|
}),
|
|
45
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;
|