@bhsd/codemirror-mediawiki 2.28.2 → 2.29.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 +15 -2
- package/dist/bidi.js +84 -0
- package/dist/codemirror.js +608 -0
- package/dist/color.js +52 -0
- package/dist/config.js +119 -0
- package/dist/css.js +30 -0
- package/dist/escape.js +35 -0
- package/dist/fold.js +445 -0
- package/dist/hover.js +52 -0
- package/dist/indent.js +50 -0
- package/dist/inlay.js +68 -0
- package/dist/javascript.js +5 -0
- package/dist/keybindings.js +35 -0
- package/dist/keymap.js +36 -0
- package/dist/linter.d.ts +1 -0
- package/dist/linter.js +134 -0
- package/dist/lua.js +428 -0
- package/dist/main.min.js +25 -29
- package/dist/matchBrackets.d.ts +7 -0
- package/dist/matchBrackets.js +58 -0
- package/dist/matchTag.js +139 -0
- package/dist/mediawiki.js +443 -0
- package/dist/mw.min.js +31 -35
- package/dist/openLinks.js +97 -0
- package/dist/ref.js +85 -0
- package/dist/signature.js +69 -0
- package/dist/static.js +46 -0
- package/dist/statusBar.js +138 -0
- package/dist/token.js +1888 -0
- package/dist/wiki.min.js +33 -37
- package/i18n/en.json +1 -1
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/package.json +19 -18
- package/dist/keybindings.d.mts +0 -15
- package/dist/keybindings.mjs +0 -34
- package/dist/linter.d.mts +0 -43
- package/dist/linter.mjs +0 -132
- /package/dist/{mwConfig.d.mts → mwConfig.d.ts} +0 -0
- /package/dist/{mwConfig.mjs → mwConfig.js} +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { EditorView } from '@codemirror/view';
|
|
2
|
+
import { ensureSyntaxTree } from '@codemirror/language';
|
|
3
|
+
import { tokens } from './config';
|
|
4
|
+
import { hasTag } from './mediawiki';
|
|
5
|
+
const { vendor, userAgent, maxTouchPoints, platform } = navigator;
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
7
|
+
export const isMac = vendor?.includes('Apple Computer')
|
|
8
|
+
&& (userAgent.includes('Mobile/') || maxTouchPoints > 2)
|
|
9
|
+
|| platform.includes('Mac');
|
|
10
|
+
const modKey = isMac ? 'metaKey' : 'ctrlKey', key = isMac ? 'Meta' : 'Control', tags = ['extLinkProtocol', 'extLink', 'freeExtLinkProtocol', 'freeExtLink', 'magicLink', 'pageName'], links = ['extlink-protocol', 'extlink', 'free-extlink-protocol', 'free-extlink', 'magic-link'], wikiLinks = [
|
|
11
|
+
'template-name',
|
|
12
|
+
'link-pagename',
|
|
13
|
+
'parserfunction.cm-mw-pagename',
|
|
14
|
+
'exttag-attribute-value.cm-mw-pagename',
|
|
15
|
+
'file-text.cm-mw-pagename',
|
|
16
|
+
];
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
18
|
+
globalThis.document?.addEventListener('keydown', e => {
|
|
19
|
+
if (e.key === key) {
|
|
20
|
+
for (const ele of document.querySelectorAll('.cm-content')) {
|
|
21
|
+
ele.style.setProperty('--codemirror-cursor', 'pointer');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
26
|
+
globalThis.document?.addEventListener('keyup', e => {
|
|
27
|
+
if (e.key === key) {
|
|
28
|
+
for (const ele of document.querySelectorAll('.cm-content')) {
|
|
29
|
+
ele.style.removeProperty('--codemirror-cursor');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const wrapURL = (url) => url.startsWith('//') ? location.protocol + url : url;
|
|
34
|
+
export const mouseEventListener = (e, view, langConfig) => {
|
|
35
|
+
if (!e[modKey]
|
|
36
|
+
|| !(e.target instanceof Element && getComputedStyle(e.target).textDecorationLine === 'underline')) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const position = view.posAtCoords(e);
|
|
40
|
+
if (!position) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const { state } = view, tree = ensureSyntaxTree(state, position);
|
|
44
|
+
if (!tree) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
let node = tree.resolve(position, -1);
|
|
48
|
+
if (node.name.includes(tokens.linkToSection)) {
|
|
49
|
+
node = node.prevSibling;
|
|
50
|
+
}
|
|
51
|
+
else if (!hasTag(new Set(node.name.split('_')), tags)) {
|
|
52
|
+
node = tree.resolve(position, 1);
|
|
53
|
+
}
|
|
54
|
+
const { name, from, to } = node;
|
|
55
|
+
if (name.includes(tokens.pageName) && typeof langConfig?.titleParser === 'function') {
|
|
56
|
+
return langConfig.titleParser(state, node);
|
|
57
|
+
}
|
|
58
|
+
else if (name.includes('-extlink-protocol')) {
|
|
59
|
+
return wrapURL(state.sliceDoc(from, node.nextSibling.to));
|
|
60
|
+
}
|
|
61
|
+
else if (/-extlink(?:_|$)/u.test(name)) {
|
|
62
|
+
return wrapURL(state.sliceDoc(node.prevSibling.from, to));
|
|
63
|
+
}
|
|
64
|
+
else if (name.includes(tokens.magicLink)) {
|
|
65
|
+
const link = state.sliceDoc(from, to);
|
|
66
|
+
if (link.startsWith('RFC')) {
|
|
67
|
+
return `https://datatracker.ietf.org/doc/html/rfc${link.slice(3).trim()}`;
|
|
68
|
+
}
|
|
69
|
+
else if (link.startsWith('PMID')) {
|
|
70
|
+
return `https://pubmed.ncbi.nlm.nih.gov/${link.slice(4).trim()}`;
|
|
71
|
+
}
|
|
72
|
+
else if (typeof langConfig?.isbnParser === 'function') {
|
|
73
|
+
return langConfig.isbnParser(link);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
};
|
|
78
|
+
export default ({ langConfig }) => [
|
|
79
|
+
EditorView.domEventHandlers({
|
|
80
|
+
mousedown(e, view) {
|
|
81
|
+
if (e.button !== 0) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
const url = mouseEventListener(e, view, langConfig);
|
|
85
|
+
if (url) {
|
|
86
|
+
open(url, '_blank');
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
EditorView.theme({
|
|
93
|
+
[[...links, ...langConfig?.titleParser ? wikiLinks : []].map(type => `.cm-mw-${type}`).join()]: {
|
|
94
|
+
cursor: 'var(--codemirror-cursor)',
|
|
95
|
+
},
|
|
96
|
+
}),
|
|
97
|
+
];
|
package/dist/ref.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { hoverTooltip, EditorView } from '@codemirror/view';
|
|
2
|
+
import { ensureSyntaxTree } from '@codemirror/language';
|
|
3
|
+
import { getLSP } from '@bhsd/common';
|
|
4
|
+
import { getTag } from './matchTag';
|
|
5
|
+
import { tokens } from './config';
|
|
6
|
+
import { indexToPos, posToIndex } from './hover';
|
|
7
|
+
const trees = new WeakMap();
|
|
8
|
+
/**
|
|
9
|
+
* 获取节点内容
|
|
10
|
+
* @param state
|
|
11
|
+
* @param node 语法树节点
|
|
12
|
+
* @param node.from 起始位置
|
|
13
|
+
* @param node.to 结束位置
|
|
14
|
+
*/
|
|
15
|
+
const getName = (state, { from, to }) => state.sliceDoc(from, to).trim();
|
|
16
|
+
export default (cm) => [
|
|
17
|
+
hoverTooltip(async (view, pos, side) => {
|
|
18
|
+
const { state } = view, node = ensureSyntaxTree(state, pos)?.resolve(pos, side);
|
|
19
|
+
if (node && /-exttag-(?!bracket)/u.test(node.name)) {
|
|
20
|
+
const tag = getTag(state, node);
|
|
21
|
+
if (!tag) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const { name, selfClosing, first, last, to } = tag;
|
|
25
|
+
if (name === 'ref' && selfClosing) {
|
|
26
|
+
let prevSibling = last, nextSibling = null;
|
|
27
|
+
while (prevSibling && prevSibling.from > first.to) {
|
|
28
|
+
const key = getName(state, prevSibling);
|
|
29
|
+
if (prevSibling.name.split('_').includes(tokens.extTagAttribute)
|
|
30
|
+
&& /(?:^|\s)name(?:$|[\s=])/iu.test(key)) {
|
|
31
|
+
if (/(?:^|\s)name\s*=/iu.test(key)) {
|
|
32
|
+
({ nextSibling } = prevSibling);
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
({ prevSibling } = prevSibling);
|
|
37
|
+
}
|
|
38
|
+
if (nextSibling?.name.includes(tokens.extTagAttributeValue)) {
|
|
39
|
+
let target = getName(state, nextSibling);
|
|
40
|
+
const quote = target.charAt(0);
|
|
41
|
+
if (quote === '"' || quote === "'") {
|
|
42
|
+
target = target.slice(1, target.slice(-1) === quote ? -1 : undefined).trim();
|
|
43
|
+
}
|
|
44
|
+
if (target) {
|
|
45
|
+
const { doc } = state, ref = await getLSP(view, false, cm.getWikiConfig)
|
|
46
|
+
?.provideDefinition(doc.toString(), indexToPos(doc, first.to));
|
|
47
|
+
return {
|
|
48
|
+
pos,
|
|
49
|
+
end: to,
|
|
50
|
+
above: true,
|
|
51
|
+
create() {
|
|
52
|
+
const dom = document.createElement('div');
|
|
53
|
+
dom.className = 'cm-tooltip-ref';
|
|
54
|
+
dom.style.font = getComputedStyle(view.contentDOM).font;
|
|
55
|
+
if (ref) {
|
|
56
|
+
const { range: { start, end } } = ref[0], anchor = posToIndex(doc, start), head = posToIndex(doc, end);
|
|
57
|
+
dom.textContent = state.sliceDoc(anchor, head);
|
|
58
|
+
dom.addEventListener('click', () => {
|
|
59
|
+
view.dispatch({
|
|
60
|
+
selection: { anchor, head },
|
|
61
|
+
scrollIntoView: true,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
dom.textContent = state.phrase('No definition found');
|
|
67
|
+
}
|
|
68
|
+
return { dom };
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}),
|
|
77
|
+
EditorView.updateListener.of(({ view, docChanged }) => {
|
|
78
|
+
if (docChanged) {
|
|
79
|
+
const tree = trees.get(view);
|
|
80
|
+
if (tree) {
|
|
81
|
+
tree.docChanged = true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}),
|
|
85
|
+
];
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { EditorView, showTooltip } from '@codemirror/view';
|
|
2
|
+
import { StateField, StateEffect } from '@codemirror/state';
|
|
3
|
+
import { getLSP } from '@bhsd/common';
|
|
4
|
+
import { indexToPos, createTooltipView } from './hover';
|
|
5
|
+
const stateEffect = StateEffect.define(), field = StateField.define({
|
|
6
|
+
create() {
|
|
7
|
+
return undefined;
|
|
8
|
+
},
|
|
9
|
+
update(oldValue, { state: { doc, selection: { main: { head } } }, effects }) {
|
|
10
|
+
const text = doc.toString();
|
|
11
|
+
for (const effect of effects) {
|
|
12
|
+
if (effect.is(stateEffect)) {
|
|
13
|
+
const { value } = effect;
|
|
14
|
+
if (head === value.cursor && text === value.text) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return oldValue;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
export default (cm) => [
|
|
23
|
+
field,
|
|
24
|
+
EditorView.updateListener.of(({ view, state, docChanged, selectionSet }) => {
|
|
25
|
+
if (docChanged || selectionSet && state.field(field)?.signatureHelp?.signatures.length) {
|
|
26
|
+
const { doc, selection: { main } } = state, { head: cursor } = main, text = doc.toString();
|
|
27
|
+
if (!main.empty) {
|
|
28
|
+
view.dispatch({
|
|
29
|
+
effects: stateEffect.of({ text, cursor }),
|
|
30
|
+
});
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
(async () => {
|
|
34
|
+
view.dispatch({
|
|
35
|
+
effects: stateEffect.of({
|
|
36
|
+
text,
|
|
37
|
+
cursor,
|
|
38
|
+
signatureHelp: await getLSP(view, false, cm.getWikiConfig)
|
|
39
|
+
?.provideSignatureHelp(text, indexToPos(doc, cursor)),
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
})();
|
|
43
|
+
}
|
|
44
|
+
}),
|
|
45
|
+
showTooltip.from(field, (value) => {
|
|
46
|
+
if (!value) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const { cursor, signatureHelp } = value;
|
|
50
|
+
if (!signatureHelp || signatureHelp.signatures.length === 0) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const { signatures, activeParameter: active } = signatureHelp;
|
|
54
|
+
return {
|
|
55
|
+
pos: cursor,
|
|
56
|
+
above: true,
|
|
57
|
+
create(view) {
|
|
58
|
+
return createTooltipView(view, signatures.map(({ label, parameters, activeParameter = active }) => {
|
|
59
|
+
if (activeParameter < 0 || activeParameter >= parameters.length) {
|
|
60
|
+
return label;
|
|
61
|
+
}
|
|
62
|
+
const colon = label.indexOf(':'), parts = label.slice(colon + 1, -2).split('|');
|
|
63
|
+
parts[activeParameter] = `<b>${parts[activeParameter]}</b>`;
|
|
64
|
+
return `${label.slice(0, colon)}:${parts.join('|')}}}`;
|
|
65
|
+
}).join('<br>'));
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}),
|
|
69
|
+
];
|
package/dist/static.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const tagModes = {
|
|
2
|
+
onlyinclude: 'mediawiki',
|
|
3
|
+
includeonly: 'mediawiki',
|
|
4
|
+
noinclude: 'mediawiki',
|
|
5
|
+
pre: 'text/pre',
|
|
6
|
+
nowiki: 'text/nowiki',
|
|
7
|
+
indicator: 'mediawiki',
|
|
8
|
+
poem: 'mediawiki',
|
|
9
|
+
ref: 'mediawiki',
|
|
10
|
+
references: 'text/references',
|
|
11
|
+
gallery: 'text/gallery',
|
|
12
|
+
poll: 'mediawiki',
|
|
13
|
+
tabs: 'mediawiki',
|
|
14
|
+
tab: 'mediawiki',
|
|
15
|
+
choose: 'text/choose',
|
|
16
|
+
option: 'mediawiki',
|
|
17
|
+
combobox: 'text/combobox',
|
|
18
|
+
combooption: 'mediawiki',
|
|
19
|
+
inputbox: 'text/inputbox',
|
|
20
|
+
templatedata: 'json',
|
|
21
|
+
mapframe: 'json',
|
|
22
|
+
maplink: 'json',
|
|
23
|
+
graph: 'json',
|
|
24
|
+
};
|
|
25
|
+
export const getStaticMwConfig = ({ variable, parserFunction: [p0, p1, ...p2], protocol, nsid, functionHook, variants, redirection, ext, doubleUnderscore: [d0, d1, d2, d3], img, }, modes) => ({
|
|
26
|
+
tags: Object.fromEntries(ext.map(s => [s, true])),
|
|
27
|
+
tagModes: modes,
|
|
28
|
+
doubleUnderscore: [
|
|
29
|
+
Object.fromEntries((d2 && d0.length === 0 ? Object.keys(d2) : d0).map(s => [`__${s}__`, true])),
|
|
30
|
+
Object.fromEntries((d3 && d1.length === 0 ? Object.keys(d3) : d1).map(s => [`__${s}__`, true])),
|
|
31
|
+
],
|
|
32
|
+
functionHooks: functionHook,
|
|
33
|
+
variableIDs: variable,
|
|
34
|
+
functionSynonyms: [
|
|
35
|
+
{
|
|
36
|
+
...p0,
|
|
37
|
+
...Object.fromEntries(p2.flat().map(s => [s, s])),
|
|
38
|
+
},
|
|
39
|
+
Array.isArray(p1) ? Object.fromEntries(p1.map(s => [s, s.toLowerCase()])) : { ...p1 },
|
|
40
|
+
],
|
|
41
|
+
urlProtocols: `${protocol}|//`,
|
|
42
|
+
nsid,
|
|
43
|
+
img: Object.fromEntries(Object.entries(img).map(([k, v]) => [k, `img_${v}`])),
|
|
44
|
+
variants,
|
|
45
|
+
redirection,
|
|
46
|
+
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { showPanel } from '@codemirror/view';
|
|
2
|
+
import { nextDiagnostic, setDiagnosticsEffect } from '@codemirror/lint';
|
|
3
|
+
function getLintMarker(view, severity, menu) {
|
|
4
|
+
const marker = document.createElement('div'), icon = document.createElement('div');
|
|
5
|
+
marker.className = `cm-status-${severity}`;
|
|
6
|
+
if (severity === 'fix') {
|
|
7
|
+
icon.className = 'cm-status-fix-disabled';
|
|
8
|
+
marker.title = 'Fix all';
|
|
9
|
+
marker.append(icon);
|
|
10
|
+
if (menu) {
|
|
11
|
+
marker.addEventListener('click', ({ clientX, clientY }) => {
|
|
12
|
+
if (icon.className === 'cm-status-fix-enabled') {
|
|
13
|
+
const { bottom, left } = view.dom.getBoundingClientRect();
|
|
14
|
+
menu.style.bottom = `${bottom - clientY + 5}px`;
|
|
15
|
+
menu.style.left = `${clientX - 20 - left}px`;
|
|
16
|
+
menu.style.display = 'block';
|
|
17
|
+
menu.focus();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
icon.className = `cm-lint-marker-${severity}`;
|
|
24
|
+
const count = document.createElement('div');
|
|
25
|
+
count.textContent = '0';
|
|
26
|
+
marker.append(icon, count);
|
|
27
|
+
marker.addEventListener('click', () => {
|
|
28
|
+
if (marker.parentElement?.classList.contains('cm-status-worker-enabled')) {
|
|
29
|
+
nextDiagnostic(view);
|
|
30
|
+
view.focus();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return marker;
|
|
35
|
+
}
|
|
36
|
+
const updateDiagnosticsCount = (diagnostics, s, marker) => {
|
|
37
|
+
marker.lastChild.textContent = String(diagnostics.filter(({ severity }) => severity === s).length);
|
|
38
|
+
};
|
|
39
|
+
const hasFix = (diagnostic) => diagnostic.actions?.some(({ name }) => name === 'fix');
|
|
40
|
+
const updateDiagnosticMessage = (view, allDiagnostics, main, msg, menu) => {
|
|
41
|
+
const diagnostics = allDiagnostics.filter(({ from, to }) => from <= main.to && to >= main.from), diagnostic = diagnostics.find(({ from, to }) => from <= main.head && to >= main.head) ?? diagnostics[0];
|
|
42
|
+
if (diagnostic) {
|
|
43
|
+
msg.textContent = diagnostic.message;
|
|
44
|
+
if (diagnostic.actions) {
|
|
45
|
+
msg.append(...diagnostic.actions.map(({ name, apply }) => {
|
|
46
|
+
const button = document.createElement('button');
|
|
47
|
+
button.type = 'button';
|
|
48
|
+
button.className = 'cm-diagnosticAction';
|
|
49
|
+
button.textContent = name;
|
|
50
|
+
button.addEventListener('click', e => {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
apply(view, diagnostic.from, diagnostic.to);
|
|
53
|
+
});
|
|
54
|
+
return button;
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
msg.textContent = '';
|
|
60
|
+
}
|
|
61
|
+
if (menu) {
|
|
62
|
+
menu.replaceChildren(...[
|
|
63
|
+
...new Set(diagnostics.filter(hasFix)
|
|
64
|
+
.map(({ message }) => / \(([^()]+)\)$/u.exec(message)?.[1])
|
|
65
|
+
.filter(Boolean)),
|
|
66
|
+
].map(rule => {
|
|
67
|
+
const option = document.createElement('div');
|
|
68
|
+
option.textContent = `Fix all ${rule} problems`;
|
|
69
|
+
option.dataset['rule'] = rule;
|
|
70
|
+
return option;
|
|
71
|
+
}), menu.lastChild);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
75
|
+
export default (fixer) => showPanel.of(view => {
|
|
76
|
+
let diagnostics = [], menu;
|
|
77
|
+
if (fixer) {
|
|
78
|
+
const optionAll = document.createElement('div');
|
|
79
|
+
optionAll.textContent = 'Fix all auto-fixable problems';
|
|
80
|
+
menu = document.createElement('div');
|
|
81
|
+
menu.className = 'cm-status-fix-menu';
|
|
82
|
+
menu.tabIndex = -1;
|
|
83
|
+
menu.append(optionAll);
|
|
84
|
+
menu.addEventListener('click', ({ target }) => {
|
|
85
|
+
if (target === menu) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
(async () => {
|
|
89
|
+
const { doc } = view.state, output = await fixer(doc, target.dataset['rule']);
|
|
90
|
+
if (output !== doc.toString()) {
|
|
91
|
+
view.dispatch({
|
|
92
|
+
changes: { from: 0, to: doc.length, insert: output },
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
view.focus();
|
|
96
|
+
})();
|
|
97
|
+
});
|
|
98
|
+
menu.addEventListener('focusout', () => {
|
|
99
|
+
menu.style.display = 'none';
|
|
100
|
+
});
|
|
101
|
+
view.dom.append(menu);
|
|
102
|
+
}
|
|
103
|
+
const dom = document.createElement('div'), worker = document.createElement('div'), message = document.createElement('div'), position = document.createElement('div'), error = getLintMarker(view, 'error'), warning = getLintMarker(view, 'warning'), fix = getLintMarker(view, 'fix', menu);
|
|
104
|
+
worker.className = 'cm-status-worker';
|
|
105
|
+
worker.append(error, warning, fix);
|
|
106
|
+
message.className = 'cm-status-message';
|
|
107
|
+
position.className = 'cm-status-line';
|
|
108
|
+
position.textContent = '0:0';
|
|
109
|
+
dom.className = 'cm-panel cm-panel-status';
|
|
110
|
+
dom.append(worker, message, position);
|
|
111
|
+
return {
|
|
112
|
+
dom,
|
|
113
|
+
update({ state: { selection: { main }, doc }, transactions, docChanged, selectionSet }) {
|
|
114
|
+
for (const tr of transactions) {
|
|
115
|
+
for (const effect of tr.effects) {
|
|
116
|
+
if (effect.is(setDiagnosticsEffect)) {
|
|
117
|
+
diagnostics = effect.value;
|
|
118
|
+
const fixable = Boolean(fixer) && diagnostics.some(hasFix), { classList } = fix.firstChild;
|
|
119
|
+
classList.toggle('cm-status-fix-enabled', fixable);
|
|
120
|
+
classList.toggle('cm-status-fix-disabled', !fixable);
|
|
121
|
+
worker.classList.toggle('cm-status-worker-enabled', diagnostics.length > 0);
|
|
122
|
+
updateDiagnosticsCount(diagnostics, 'error', error);
|
|
123
|
+
updateDiagnosticsCount(diagnostics, 'warning', warning);
|
|
124
|
+
updateDiagnosticMessage(view, diagnostics, main, message, menu);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (docChanged || selectionSet) {
|
|
129
|
+
updateDiagnosticMessage(view, diagnostics, main, message, menu);
|
|
130
|
+
const { number, from } = doc.lineAt(main.head);
|
|
131
|
+
position.textContent = `${number}:${main.head - from}`;
|
|
132
|
+
if (!main.empty) {
|
|
133
|
+
position.textContent += ` (${main.to - main.from})`;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
});
|