@bhsd/codemirror-mediawiki 3.12.1 → 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/dist/codemirror.js +5 -5
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/escape.js +3 -3
- package/dist/fold.d.ts +4 -4
- package/dist/fold.js +18 -18
- package/dist/hover.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/inlay.js +2 -2
- package/dist/javascript.js +8 -4
- 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.js +10 -10
- package/dist/main.min.js +31 -30
- package/dist/matchBrackets.d.ts +3 -11
- package/dist/matchBrackets.js +49 -35
- package/dist/matchTag.d.ts +5 -5
- package/dist/matchTag.js +4 -4
- package/dist/mediawiki.d.ts +1 -2
- package/dist/mediawiki.js +4 -9
- package/dist/mw.min.js +33 -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 +9 -3
- package/dist/token.d.ts +8 -5
- package/dist/token.js +16 -3
- package/dist/util.d.ts +3 -2
- package/dist/util.js +7 -6
- package/dist/wiki.min.js +33 -32
- package/i18n/en.json +1 -1
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/package.json +4 -7
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,4 +1,4 @@
|
|
|
1
1
|
import { Decoration } from '@codemirror/view';
|
|
2
|
-
export declare const
|
|
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";
|
|
3
3
|
export declare const isWMF: boolean;
|
|
4
4
|
export declare const isMac: boolean;
|
package/dist/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Decoration } from '@codemirror/view';
|
|
2
2
|
import { wmf } from '@bhsd/common';
|
|
3
|
-
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';
|
|
4
4
|
export const isWMF = /* @__PURE__ */ (() => typeof location === 'object'
|
|
5
5
|
&& new RegExp(String.raw `\.(?:${wmf})\.org$`, 'u').test(location.hostname))();
|
|
6
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)) {
|
|
@@ -393,7 +393,7 @@ export const unfoldRef = (view) => {
|
|
|
393
393
|
* @param view
|
|
394
394
|
* @test
|
|
395
395
|
*/
|
|
396
|
-
export const
|
|
396
|
+
export const mySelectedLines = (view) => {
|
|
397
397
|
const lines = [];
|
|
398
398
|
for (const { head } of view.state.selection.ranges) {
|
|
399
399
|
if (lines.some(({ from, to }) => from <= head && to >= head)) {
|
|
@@ -403,7 +403,7 @@ export const selectedLines = (view) => {
|
|
|
403
403
|
}
|
|
404
404
|
return lines;
|
|
405
405
|
};
|
|
406
|
-
const
|
|
406
|
+
const myFoldCode = (view, line) => {
|
|
407
407
|
const range = foldableLine(view, line);
|
|
408
408
|
if (range) {
|
|
409
409
|
view.dispatch({ effects: foldEffect.of(range) });
|
|
@@ -411,8 +411,8 @@ const foldCode = (view, line) => {
|
|
|
411
411
|
}
|
|
412
412
|
return false;
|
|
413
413
|
};
|
|
414
|
-
const
|
|
415
|
-
const folded =
|
|
414
|
+
const myUnfoldCode = (view, line) => {
|
|
415
|
+
const folded = myFindFold(view, line);
|
|
416
416
|
return folded && unfoldEffect.of(folded);
|
|
417
417
|
};
|
|
418
418
|
/**
|
|
@@ -437,8 +437,8 @@ export const foldAt = view => {
|
|
|
437
437
|
if (effects.length > 0) {
|
|
438
438
|
return execute(view, effects, anchor);
|
|
439
439
|
}
|
|
440
|
-
for (const line of
|
|
441
|
-
if (
|
|
440
|
+
for (const line of mySelectedLines(view)) {
|
|
441
|
+
if (myFoldCode(view, line)) {
|
|
442
442
|
return true;
|
|
443
443
|
}
|
|
444
444
|
}
|
|
@@ -515,8 +515,8 @@ export const mediawikiFold = /* @__PURE__ */ (() => [
|
|
|
515
515
|
view.dispatch({ effects, selection });
|
|
516
516
|
return true;
|
|
517
517
|
}
|
|
518
|
-
for (const line of
|
|
519
|
-
const effect =
|
|
518
|
+
for (const line of mySelectedLines(view)) {
|
|
519
|
+
const effect = myUnfoldCode(view, line);
|
|
520
520
|
if (effect) {
|
|
521
521
|
effects.push(effect);
|
|
522
522
|
}
|
|
@@ -537,16 +537,16 @@ export const mediawikiFold = /* @__PURE__ */ (() => [
|
|
|
537
537
|
return view.plugin(markers)?.markers ?? RangeSet.empty;
|
|
538
538
|
},
|
|
539
539
|
initialSpacer() {
|
|
540
|
-
return new
|
|
540
|
+
return new MyFoldMarker(false);
|
|
541
541
|
},
|
|
542
542
|
domEventHandlers: {
|
|
543
543
|
click(view, line) {
|
|
544
|
-
const effects =
|
|
544
|
+
const effects = myUnfoldCode(view, line);
|
|
545
545
|
if (effects) {
|
|
546
546
|
view.dispatch({ effects });
|
|
547
547
|
return true;
|
|
548
548
|
}
|
|
549
|
-
return
|
|
549
|
+
return myFoldCode(view, line);
|
|
550
550
|
},
|
|
551
551
|
},
|
|
552
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/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.js
CHANGED
|
@@ -6,7 +6,7 @@ import { builtin } from './javascript-globals.js';
|
|
|
6
6
|
import { doctagMark } from './constants.js';
|
|
7
7
|
import { markDocTagType, pushDecoration } from './util.js';
|
|
8
8
|
export const jsCompletion = javascriptLanguage.data.of({ autocomplete: scopeCompletionSource(globalThis) });
|
|
9
|
-
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));
|
|
10
10
|
/**
|
|
11
11
|
* 忽略JavaScript正则表达式中的括号匹配
|
|
12
12
|
* @param state
|
|
@@ -61,14 +61,18 @@ export const markGlobalsAndDocTag = (tree, visibleRanges, state, cm) => {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
else if (type.is('BlockComment') && /^\/\*{2}(?!\*)/u.test(name)) {
|
|
64
|
-
const comment = name.slice(2), mtAll = comment.matchAll(/^[ \t]*\*\s*(@[a-z]+)(\s+\{
|
|
64
|
+
const comment = name.slice(2), pos = f + 2, mtAll = comment.matchAll(/^[ \t]*\*\s*(@[a-z]+)(\s+\{)?|\{(@[a-z]+)/dgimu);
|
|
65
65
|
for (const mt of mtAll) {
|
|
66
66
|
if (mt[3]) {
|
|
67
67
|
const [start, end] = mt.indices[3];
|
|
68
|
-
pushDecoration(decorations, doctagMark,
|
|
68
|
+
pushDecoration(decorations, doctagMark, pos + start, pos + end);
|
|
69
69
|
}
|
|
70
70
|
else {
|
|
71
|
-
markDocTagType(decorations,
|
|
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
|
+
}
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
}
|
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;
|
package/dist/keymap.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { EditorSelection } from '@codemirror/state';
|
|
2
|
+
import { syntaxTree } from '@codemirror/language';
|
|
2
3
|
import { keybindings, encapsulateLines } from './keybindings.js';
|
|
4
|
+
const reKartographer = /(?:^|_)mw-tag-map(?:link|frame)(?:$|_)/u;
|
|
3
5
|
/**
|
|
4
6
|
* 生成keymap
|
|
5
7
|
* @param opt 快捷键设置
|
|
@@ -9,11 +11,24 @@ import { keybindings, encapsulateLines } from './keybindings.js';
|
|
|
9
11
|
* @param opt.splitlines 是否分行
|
|
10
12
|
* @test
|
|
11
13
|
*/
|
|
12
|
-
export const
|
|
14
|
+
export const getWikiKeymap = ({ key, pre = '', post = '', splitlines }) => ({
|
|
13
15
|
key,
|
|
14
16
|
run(view) {
|
|
15
|
-
const { state } = view;
|
|
17
|
+
const { state } = view, tree = syntaxTree(state);
|
|
16
18
|
view.dispatch(state.changeByRange(({ from, to }) => {
|
|
19
|
+
if (key === 'Mod-/'
|
|
20
|
+
&& reKartographer.test(tree.resolveInner(from, 1).name)
|
|
21
|
+
&& reKartographer.test(tree.resolveInner(to, -1).name)) {
|
|
22
|
+
// JSONC comment
|
|
23
|
+
if (from === to) {
|
|
24
|
+
pre = '//';
|
|
25
|
+
post = '';
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
pre = '/*';
|
|
29
|
+
post = '*/';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
17
32
|
if (splitlines) {
|
|
18
33
|
const start = state.doc.lineAt(from).from, end = state.doc.lineAt(to).to, insert = encapsulateLines(state.sliceDoc(start, end), pre, post);
|
|
19
34
|
return {
|
|
@@ -31,4 +46,4 @@ export const getKeymap = ({ key, pre = '', post = '', splitlines }) => ({
|
|
|
31
46
|
},
|
|
32
47
|
preventDefault: true,
|
|
33
48
|
});
|
|
34
|
-
export default keybindings.map(
|
|
49
|
+
export default keybindings.map(getWikiKeymap);
|
package/dist/lint.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const myFindDiagnostic = (deco, head, anchor = head) => {
|
|
2
2
|
let found;
|
|
3
3
|
deco.between(head, Infinity, (_, __, { spec: { diagnostics } }) => {
|
|
4
4
|
const next = diagnostics.sort((a, b) => a.from - b.from || a.to - b.to)
|
|
@@ -16,7 +16,7 @@ const findDiagnostic = (deco, head, anchor = head) => {
|
|
|
16
16
|
* @param cm CodeMirror6 实例
|
|
17
17
|
*/
|
|
18
18
|
export const nextDiagnostic = (cm) => {
|
|
19
|
-
const view = cm.view, { state } = view, { diagnostics } = state.field(cm.getLintExtension()[2][0]), { from, to } = state.selection.main, next =
|
|
19
|
+
const view = cm.view, { state } = view, { diagnostics } = state.field(cm.getLintExtension()[2][0]), { from, to } = state.selection.main, next = myFindDiagnostic(diagnostics, from, to) ?? myFindDiagnostic(diagnostics, 0);
|
|
20
20
|
if (!next || next.from === from && next.to === to) {
|
|
21
21
|
return false;
|
|
22
22
|
}
|
package/dist/lintsource.js
CHANGED
|
@@ -4,7 +4,7 @@ import { javascriptLanguage } from '@codemirror/lang-javascript';
|
|
|
4
4
|
import { sanitizeInlineStyle, lintJSON } from '@bhsd/common';
|
|
5
5
|
import { getWikiLinter, getJsLinter, getCssLinter, getLuaLinter, stylelintRepo, eslintRepo, luacheckRepo, isStylelintConfig, } from './linter.js';
|
|
6
6
|
import { posToIndex, toConfigGetter, } from './util.js';
|
|
7
|
-
import {
|
|
7
|
+
import { baseData } from './constants.js';
|
|
8
8
|
import { vue } from './javascript-globals.js';
|
|
9
9
|
/**
|
|
10
10
|
* 获取Linter选项
|
|
@@ -67,7 +67,7 @@ const wikiLintSource = async (wikiLint, text, opt, doc, f = 0, t) => (await wiki
|
|
|
67
67
|
* @test
|
|
68
68
|
*/
|
|
69
69
|
export const getWikiLintSource = (articlePath) => async (opt, v) => {
|
|
70
|
-
const options = { ...await getOpt(opt), cdn:
|
|
70
|
+
const options = { ...await getOpt(opt), cdn: baseData.CDN };
|
|
71
71
|
if (articlePath) {
|
|
72
72
|
options.getConfig = toConfigGetter(options.getConfig, articlePath);
|
|
73
73
|
}
|
|
@@ -113,7 +113,7 @@ const jsLintSource = (esLint, code, opt, doc, f = 0, t) => esLint(code, opt)
|
|
|
113
113
|
* @test
|
|
114
114
|
*/
|
|
115
115
|
export const getJsLintSource = async (opt) => {
|
|
116
|
-
const { CDN } =
|
|
116
|
+
const { CDN } = baseData, esLint = await getJsLinter(CDN && `${CDN}/${eslintRepo}`);
|
|
117
117
|
const lintSource = async ({ doc }) => jsLintSource(esLint, doc.toString(), await getOpt(opt), doc);
|
|
118
118
|
lintSource.fixer = (doc, rule) => esLint.fixer(doc.toString(), rule);
|
|
119
119
|
Object.defineProperty(lintSource, 'config', {
|
|
@@ -156,7 +156,7 @@ const cssLintSource = async (styleLint, code, opt, doc, f = 0, t) => {
|
|
|
156
156
|
* @test
|
|
157
157
|
*/
|
|
158
158
|
export const getCssLintSource = async (opt) => {
|
|
159
|
-
const { CDN } =
|
|
159
|
+
const { CDN } = baseData, styleLint = await getCssLinter(CDN && `${CDN}/${stylelintRepo}`);
|
|
160
160
|
const lintSource = async ({ doc }) => cssLintSource(styleLint, doc.toString(), await getOpt(opt), doc);
|
|
161
161
|
lintSource.fixer = async (doc, rule) => styleLint.fixer(doc.toString(), rule);
|
|
162
162
|
Object.defineProperty(lintSource, 'config', {
|
|
@@ -180,7 +180,7 @@ const stylelintConfigVue = /* #__PURE__ */ (() => ({
|
|
|
180
180
|
}))();
|
|
181
181
|
/** @implements */
|
|
182
182
|
const getVueOrHtmlLintSource = (rules, globals) => async (opt) => {
|
|
183
|
-
const { CDN } =
|
|
183
|
+
const { CDN } = baseData, styleLint = await getCssLinter(CDN && `${CDN}/${stylelintRepo}`), esLint = await getJsLinter(CDN && `${CDN}/${eslintRepo}`);
|
|
184
184
|
const lintSource = async (state) => {
|
|
185
185
|
const { doc } = state, option = await getOpt(opt, true) ?? {};
|
|
186
186
|
let js = option['js'], css = option['css'];
|
|
@@ -228,7 +228,7 @@ export const getVueLintSource = /* #__PURE__ */ getVueOrHtmlLintSource(stylelint
|
|
|
228
228
|
* @test
|
|
229
229
|
*/
|
|
230
230
|
export const getHTMLLintSource = async (opt, view, language) => {
|
|
231
|
-
const vueLintSource = await getVueOrHtmlLintSource()(opt), wikiLint = await getWikiLinter({ include: false, ...await getOpt(opt), cdn:
|
|
231
|
+
const vueLintSource = await getVueOrHtmlLintSource()(opt), wikiLint = await getWikiLinter({ include: false, ...await getOpt(opt), cdn: baseData.CDN }, view);
|
|
232
232
|
const lintSource = async (state) => {
|
|
233
233
|
const { doc } = state, option = await getOpt(opt, true) ?? {}, wiki = option['wiki'];
|
|
234
234
|
return [
|
|
@@ -255,7 +255,7 @@ export const getJsonLintSource = () => ({ doc }) => lintJSON(doc.toString())
|
|
|
255
255
|
* @test
|
|
256
256
|
*/
|
|
257
257
|
export const getLuaLintSource = async () => {
|
|
258
|
-
const { CDN } =
|
|
258
|
+
const { CDN } = baseData, luaLint = await getLuaLinter(CDN && `${CDN}/${luacheckRepo}`);
|
|
259
259
|
return async ({ doc }) => (await luaLint(doc.toString()))
|
|
260
260
|
.map(({ line, column, end_column, msg: message, severity }) => ({
|
|
261
261
|
source: 'Luacheck',
|
package/dist/lua.js
CHANGED
|
@@ -218,7 +218,7 @@ const map = {
|
|
|
218
218
|
},
|
|
219
219
|
ext: 4,
|
|
220
220
|
},
|
|
221
|
-
},
|
|
221
|
+
}, luaBuiltin = ['false', 'nil', 'true'], luaBuiltins = luaBuiltin.map(label => ({ label, type: 'constant' })), tables = [
|
|
222
222
|
'_G',
|
|
223
223
|
...Object.keys(globals),
|
|
224
224
|
].map(label => ({ label, type: 'namespace' })), constants = [
|
|
@@ -268,7 +268,7 @@ const map = {
|
|
|
268
268
|
'do',
|
|
269
269
|
'until',
|
|
270
270
|
'goto',
|
|
271
|
-
].map(label => ({ label, type: 'keyword' })),
|
|
271
|
+
].map(label => ({ label, type: 'keyword' })), luaKeywords = [
|
|
272
272
|
...[
|
|
273
273
|
'if',
|
|
274
274
|
'while',
|
|
@@ -306,14 +306,14 @@ const map = {
|
|
|
306
306
|
detail: 'in loop',
|
|
307
307
|
type: 'keyword',
|
|
308
308
|
}),
|
|
309
|
-
],
|
|
309
|
+
], excludedTypes = new Set(['variableName', 'variableName.standard', 'keyword']), lang = StreamLanguage.define(lua);
|
|
310
310
|
/**
|
|
311
311
|
* @implements
|
|
312
312
|
* @test
|
|
313
313
|
*/
|
|
314
314
|
const source = context => {
|
|
315
315
|
const { state, pos } = context, node = syntaxTree(state).resolveInner(pos, -1);
|
|
316
|
-
if (!
|
|
316
|
+
if (!excludedTypes.has(node.name)) {
|
|
317
317
|
return null;
|
|
318
318
|
}
|
|
319
319
|
const match = context.matchBefore(/(?:(?:^|\S|\.\.)\s+|^|[^\w\s]|\.\.)\w+$|\.{1,2}$/u);
|
|
@@ -382,7 +382,7 @@ const source = context => {
|
|
|
382
382
|
case ',':
|
|
383
383
|
return {
|
|
384
384
|
from,
|
|
385
|
-
options: [...
|
|
385
|
+
options: [...luaBuiltins, ...constants, ...tables, ...unary],
|
|
386
386
|
validFor,
|
|
387
387
|
};
|
|
388
388
|
case '}':
|
|
@@ -397,7 +397,7 @@ const source = context => {
|
|
|
397
397
|
case '':
|
|
398
398
|
return {
|
|
399
399
|
from,
|
|
400
|
-
options: [...
|
|
400
|
+
options: [...luaKeywords, ...blocks, ...unary, ...constants, ...tables, ...luaBuiltins],
|
|
401
401
|
validFor,
|
|
402
402
|
};
|
|
403
403
|
default:
|
|
@@ -406,9 +406,9 @@ const source = context => {
|
|
|
406
406
|
return {
|
|
407
407
|
from,
|
|
408
408
|
options: prevSibling?.name !== 'keyword'
|
|
409
|
-
||
|
|
409
|
+
|| luaBuiltin.includes(sliceDoc(state, prevSibling))
|
|
410
410
|
? [...binary, ...blocks]
|
|
411
|
-
: [...
|
|
411
|
+
: [...luaBuiltins, ...constants, ...tables, ...unary, ...blocks],
|
|
412
412
|
validFor,
|
|
413
413
|
};
|
|
414
414
|
}
|
|
@@ -455,9 +455,9 @@ export const markDocTag = (tree, visibleRanges, state) => {
|
|
|
455
455
|
|| firstLine.startsWith('---')
|
|
456
456
|
&& !(firstLine.endsWith('--') && /[^-]/u.test(firstLine))) {
|
|
457
457
|
while (node.name === 'comment') {
|
|
458
|
-
const comment = sliceDoc(state, node), mt = /^\s*(?:-{2,}\s*)?(@[a-z]+)(\s+\{
|
|
458
|
+
const comment = sliceDoc(state, node), mt = /^\s*(?:-{2,}\s*)?(@[a-z]+)(\s+\{)?/diu.exec(comment);
|
|
459
459
|
if (mt) {
|
|
460
|
-
markDocTagType(decorations, node.from, mt);
|
|
460
|
+
markDocTagType(decorations, node.from, mt, 1);
|
|
461
461
|
}
|
|
462
462
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
463
463
|
const { nextSibling } = node;
|