@codemirror/lint 6.8.3 → 6.8.5
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/CHANGELOG.md +14 -0
- package/dist/index.cjs +139 -63
- package/dist/index.js +138 -62
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 6.8.5 (2025-03-26)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix a regression (since 6.8.4) that broke the `markerFilter` option.
|
|
6
|
+
|
|
7
|
+
## 6.8.4 (2024-11-28)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Don't create overlapping decorations when diagnostics overlap.
|
|
12
|
+
|
|
13
|
+
Fix an issue where block widgets could cause the lint gutter to show diagnostics multiple times.
|
|
14
|
+
|
|
1
15
|
## 6.8.3 (2024-11-21)
|
|
2
16
|
|
|
3
17
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -17,34 +17,75 @@ class LintState {
|
|
|
17
17
|
this.panel = panel;
|
|
18
18
|
this.selected = selected;
|
|
19
19
|
}
|
|
20
|
-
static init(diagnostics, panel, state) {
|
|
20
|
+
static init(diagnostics, panel, state$1) {
|
|
21
21
|
// Filter the list of diagnostics for which to create markers
|
|
22
|
-
let
|
|
23
|
-
let diagnosticFilter = state.facet(lintConfig).markerFilter;
|
|
22
|
+
let diagnosticFilter = state$1.facet(lintConfig).markerFilter;
|
|
24
23
|
if (diagnosticFilter)
|
|
25
|
-
|
|
26
|
-
let
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
diagnostics = diagnosticFilter(diagnostics, state$1);
|
|
25
|
+
let sorted = diagnostics.slice().sort((a, b) => a.from - b.from || a.to - b.to);
|
|
26
|
+
let deco = new state.RangeSetBuilder(), active = [], pos = 0;
|
|
27
|
+
for (let i = 0;;) {
|
|
28
|
+
let next = i == sorted.length ? null : sorted[i];
|
|
29
|
+
if (!next && !active.length)
|
|
30
|
+
break;
|
|
31
|
+
let from, to;
|
|
32
|
+
if (active.length) {
|
|
33
|
+
from = pos;
|
|
34
|
+
to = active.reduce((p, d) => Math.min(p, d.to), next && next.from > from ? next.from : 1e8);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
from = next.from;
|
|
38
|
+
to = next.to;
|
|
39
|
+
active.push(next);
|
|
40
|
+
i++;
|
|
41
|
+
}
|
|
42
|
+
while (i < sorted.length) {
|
|
43
|
+
let next = sorted[i];
|
|
44
|
+
if (next.from == from && (next.to > next.from || next.to == from)) {
|
|
45
|
+
active.push(next);
|
|
46
|
+
i++;
|
|
47
|
+
to = Math.min(next.to, to);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
to = Math.min(next.from, to);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
let sev = maxSeverity(active);
|
|
55
|
+
if (active.some(d => d.from == d.to || (d.from == d.to - 1 && state$1.doc.lineAt(d.from).to == d.from))) {
|
|
56
|
+
deco.add(from, from, view.Decoration.widget({
|
|
57
|
+
widget: new DiagnosticWidget(sev),
|
|
58
|
+
diagnostics: active.slice()
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
let markClass = active.reduce((c, d) => d.markClass ? c + " " + d.markClass : c, "");
|
|
63
|
+
deco.add(from, to, view.Decoration.mark({
|
|
64
|
+
class: "cm-lintRange cm-lintRange-" + sev + markClass,
|
|
65
|
+
diagnostics: active.slice(),
|
|
66
|
+
inclusiveEnd: active.some(a => a.to > to)
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
pos = to;
|
|
70
|
+
for (let i = 0; i < active.length; i++)
|
|
71
|
+
if (active[i].to <= pos)
|
|
72
|
+
active.splice(i--, 1);
|
|
73
|
+
}
|
|
74
|
+
let set = deco.finish();
|
|
75
|
+
return new LintState(set, panel, findDiagnostic(set));
|
|
39
76
|
}
|
|
40
77
|
}
|
|
41
78
|
function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
|
|
42
79
|
let found = null;
|
|
43
80
|
diagnostics.between(after, 1e9, (from, to, { spec }) => {
|
|
44
|
-
if (diagnostic && spec.diagnostic
|
|
81
|
+
if (diagnostic && spec.diagnostics.indexOf(diagnostic) < 0)
|
|
45
82
|
return;
|
|
46
|
-
|
|
47
|
-
|
|
83
|
+
if (!found)
|
|
84
|
+
found = new SelectedDiagnostic(from, to, diagnostic || spec.diagnostics[0]);
|
|
85
|
+
else if (spec.diagnostics.indexOf(found.diagnostic) < 0)
|
|
86
|
+
return false;
|
|
87
|
+
else
|
|
88
|
+
found = new SelectedDiagnostic(found.from, to, found.diagnostic);
|
|
48
89
|
});
|
|
49
90
|
return found;
|
|
50
91
|
}
|
|
@@ -118,24 +159,25 @@ function diagnosticCount(state) {
|
|
|
118
159
|
const activeMark = view.Decoration.mark({ class: "cm-lintRange cm-lintRange-active" });
|
|
119
160
|
function lintTooltip(view, pos, side) {
|
|
120
161
|
let { diagnostics } = view.state.field(lintState);
|
|
121
|
-
let found
|
|
162
|
+
let found, start = -1, end = -1;
|
|
122
163
|
diagnostics.between(pos - (side < 0 ? 1 : 0), pos + (side > 0 ? 1 : 0), (from, to, { spec }) => {
|
|
123
164
|
if (pos >= from && pos <= to &&
|
|
124
165
|
(from == to || ((pos > from || side > 0) && (pos < to || side < 0)))) {
|
|
125
|
-
found
|
|
126
|
-
|
|
127
|
-
|
|
166
|
+
found = spec.diagnostics;
|
|
167
|
+
start = from;
|
|
168
|
+
end = to;
|
|
169
|
+
return false;
|
|
128
170
|
}
|
|
129
171
|
});
|
|
130
172
|
let diagnosticFilter = view.state.facet(lintConfig).tooltipFilter;
|
|
131
|
-
if (diagnosticFilter)
|
|
173
|
+
if (found && diagnosticFilter)
|
|
132
174
|
found = diagnosticFilter(found, view.state);
|
|
133
|
-
if (!found
|
|
175
|
+
if (!found)
|
|
134
176
|
return null;
|
|
135
177
|
return {
|
|
136
|
-
pos:
|
|
137
|
-
end:
|
|
138
|
-
above: view.state.doc.lineAt(
|
|
178
|
+
pos: start,
|
|
179
|
+
end: end,
|
|
180
|
+
above: view.state.doc.lineAt(start).to < end,
|
|
139
181
|
create() {
|
|
140
182
|
return { dom: diagnosticsTooltip(view, found) };
|
|
141
183
|
}
|
|
@@ -272,7 +314,7 @@ function batchResults(promises, sink, error) {
|
|
|
272
314
|
if (collected.length == promises.length)
|
|
273
315
|
sink(collected);
|
|
274
316
|
else
|
|
275
|
-
setTimeout(() => sink(collected), 200);
|
|
317
|
+
timeout = setTimeout(() => sink(collected), 200);
|
|
276
318
|
}, error);
|
|
277
319
|
}
|
|
278
320
|
const lintConfig = state.Facet.define({
|
|
@@ -352,13 +394,13 @@ function renderDiagnostic(view, diagnostic, inPanel) {
|
|
|
352
394
|
}), diagnostic.source && elt("div", { class: "cm-diagnosticSource" }, diagnostic.source));
|
|
353
395
|
}
|
|
354
396
|
class DiagnosticWidget extends view.WidgetType {
|
|
355
|
-
constructor(
|
|
397
|
+
constructor(sev) {
|
|
356
398
|
super();
|
|
357
|
-
this.
|
|
399
|
+
this.sev = sev;
|
|
358
400
|
}
|
|
359
|
-
eq(other) { return other.
|
|
401
|
+
eq(other) { return other.sev == this.sev; }
|
|
360
402
|
toDOM() {
|
|
361
|
-
return elt("span", { class: "cm-lintPoint cm-lintPoint-" + this.
|
|
403
|
+
return elt("span", { class: "cm-lintPoint cm-lintPoint-" + this.sev });
|
|
362
404
|
}
|
|
363
405
|
}
|
|
364
406
|
class PanelItem {
|
|
@@ -441,35 +483,41 @@ class LintPanel {
|
|
|
441
483
|
update() {
|
|
442
484
|
let { diagnostics, selected } = this.view.state.field(lintState);
|
|
443
485
|
let i = 0, needsSync = false, newSelectedItem = null;
|
|
486
|
+
let seen = new Set();
|
|
444
487
|
diagnostics.between(0, this.view.state.doc.length, (_start, _end, { spec }) => {
|
|
445
|
-
let
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
if (found > i) {
|
|
459
|
-
this.items.splice(i, found - i);
|
|
488
|
+
for (let diagnostic of spec.diagnostics) {
|
|
489
|
+
if (seen.has(diagnostic))
|
|
490
|
+
continue;
|
|
491
|
+
seen.add(diagnostic);
|
|
492
|
+
let found = -1, item;
|
|
493
|
+
for (let j = i; j < this.items.length; j++)
|
|
494
|
+
if (this.items[j].diagnostic == diagnostic) {
|
|
495
|
+
found = j;
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
if (found < 0) {
|
|
499
|
+
item = new PanelItem(this.view, diagnostic);
|
|
500
|
+
this.items.splice(i, 0, item);
|
|
460
501
|
needsSync = true;
|
|
461
502
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
503
|
+
else {
|
|
504
|
+
item = this.items[found];
|
|
505
|
+
if (found > i) {
|
|
506
|
+
this.items.splice(i, found - i);
|
|
507
|
+
needsSync = true;
|
|
508
|
+
}
|
|
467
509
|
}
|
|
510
|
+
if (selected && item.diagnostic == selected.diagnostic) {
|
|
511
|
+
if (!item.dom.hasAttribute("aria-selected")) {
|
|
512
|
+
item.dom.setAttribute("aria-selected", "true");
|
|
513
|
+
newSelectedItem = item;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
else if (item.dom.hasAttribute("aria-selected")) {
|
|
517
|
+
item.dom.removeAttribute("aria-selected");
|
|
518
|
+
}
|
|
519
|
+
i++;
|
|
468
520
|
}
|
|
469
|
-
else if (item.dom.hasAttribute("aria-selected")) {
|
|
470
|
-
item.dom.removeAttribute("aria-selected");
|
|
471
|
-
}
|
|
472
|
-
i++;
|
|
473
521
|
});
|
|
474
522
|
while (i < this.items.length && !(this.items.length == 1 && this.items[0].diagnostic.from < 0)) {
|
|
475
523
|
needsSync = true;
|
|
@@ -638,11 +686,22 @@ const baseTheme = view.EditorView.baseTheme({
|
|
|
638
686
|
function severityWeight(sev) {
|
|
639
687
|
return sev == "error" ? 4 : sev == "warning" ? 3 : sev == "info" ? 2 : 1;
|
|
640
688
|
}
|
|
689
|
+
function maxSeverity(diagnostics) {
|
|
690
|
+
let sev = "hint", weight = 1;
|
|
691
|
+
for (let d of diagnostics) {
|
|
692
|
+
let w = severityWeight(d.severity);
|
|
693
|
+
if (w > weight) {
|
|
694
|
+
weight = w;
|
|
695
|
+
sev = d.severity;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return sev;
|
|
699
|
+
}
|
|
641
700
|
class LintGutterMarker extends view.GutterMarker {
|
|
642
701
|
constructor(diagnostics) {
|
|
643
702
|
super();
|
|
644
703
|
this.diagnostics = diagnostics;
|
|
645
|
-
this.severity = diagnostics
|
|
704
|
+
this.severity = maxSeverity(diagnostics);
|
|
646
705
|
}
|
|
647
706
|
toDOM(view) {
|
|
648
707
|
let elt = document.createElement("div");
|
|
@@ -721,7 +780,8 @@ const lintGutterExtension = view.gutter({
|
|
|
721
780
|
widgetMarker: (view, widget, block) => {
|
|
722
781
|
let diagnostics = [];
|
|
723
782
|
view.state.field(lintGutterMarkers).between(block.from, block.to, (from, to, value) => {
|
|
724
|
-
|
|
783
|
+
if (from > block.from && from < block.to)
|
|
784
|
+
diagnostics.push(...value.diagnostics);
|
|
725
785
|
});
|
|
726
786
|
return diagnostics.length ? new LintGutterMarker(diagnostics) : null;
|
|
727
787
|
}
|
|
@@ -812,9 +872,25 @@ arguments hold the diagnostic's current position.
|
|
|
812
872
|
*/
|
|
813
873
|
function forEachDiagnostic(state$1, f) {
|
|
814
874
|
let lState = state$1.field(lintState, false);
|
|
815
|
-
if (lState && lState.diagnostics.size)
|
|
816
|
-
|
|
817
|
-
|
|
875
|
+
if (lState && lState.diagnostics.size) {
|
|
876
|
+
let pending = [], pendingStart = [], lastEnd = -1;
|
|
877
|
+
for (let iter = state.RangeSet.iter([lState.diagnostics]);; iter.next()) {
|
|
878
|
+
for (let i = 0; i < pending.length; i++)
|
|
879
|
+
if (!iter.value || iter.value.spec.diagnostics.indexOf(pending[i]) < 0) {
|
|
880
|
+
f(pending[i], pendingStart[i], lastEnd);
|
|
881
|
+
pending.splice(i, 1);
|
|
882
|
+
pendingStart.splice(i--, 1);
|
|
883
|
+
}
|
|
884
|
+
if (!iter.value)
|
|
885
|
+
break;
|
|
886
|
+
for (let d of iter.value.spec.diagnostics)
|
|
887
|
+
if (pending.indexOf(d) < 0) {
|
|
888
|
+
pending.push(d);
|
|
889
|
+
pendingStart.push(iter.from);
|
|
890
|
+
}
|
|
891
|
+
lastEnd = iter.to;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
818
894
|
}
|
|
819
895
|
|
|
820
896
|
exports.closeLintPanel = closeLintPanel;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Decoration, showPanel, EditorView, ViewPlugin, gutter, showTooltip, hoverTooltip, getPanel, logException, WidgetType, GutterMarker } from '@codemirror/view';
|
|
2
|
-
import { StateEffect, StateField, Facet, combineConfig, RangeSet } from '@codemirror/state';
|
|
2
|
+
import { StateEffect, StateField, Facet, combineConfig, RangeSet, RangeSetBuilder } from '@codemirror/state';
|
|
3
3
|
import elt from 'crelt';
|
|
4
4
|
|
|
5
5
|
class SelectedDiagnostic {
|
|
@@ -17,32 +17,73 @@ class LintState {
|
|
|
17
17
|
}
|
|
18
18
|
static init(diagnostics, panel, state) {
|
|
19
19
|
// Filter the list of diagnostics for which to create markers
|
|
20
|
-
let markedDiagnostics = diagnostics;
|
|
21
20
|
let diagnosticFilter = state.facet(lintConfig).markerFilter;
|
|
22
21
|
if (diagnosticFilter)
|
|
23
|
-
|
|
24
|
-
let
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
diagnostics = diagnosticFilter(diagnostics, state);
|
|
23
|
+
let sorted = diagnostics.slice().sort((a, b) => a.from - b.from || a.to - b.to);
|
|
24
|
+
let deco = new RangeSetBuilder(), active = [], pos = 0;
|
|
25
|
+
for (let i = 0;;) {
|
|
26
|
+
let next = i == sorted.length ? null : sorted[i];
|
|
27
|
+
if (!next && !active.length)
|
|
28
|
+
break;
|
|
29
|
+
let from, to;
|
|
30
|
+
if (active.length) {
|
|
31
|
+
from = pos;
|
|
32
|
+
to = active.reduce((p, d) => Math.min(p, d.to), next && next.from > from ? next.from : 1e8);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
from = next.from;
|
|
36
|
+
to = next.to;
|
|
37
|
+
active.push(next);
|
|
38
|
+
i++;
|
|
39
|
+
}
|
|
40
|
+
while (i < sorted.length) {
|
|
41
|
+
let next = sorted[i];
|
|
42
|
+
if (next.from == from && (next.to > next.from || next.to == from)) {
|
|
43
|
+
active.push(next);
|
|
44
|
+
i++;
|
|
45
|
+
to = Math.min(next.to, to);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
to = Math.min(next.from, to);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let sev = maxSeverity(active);
|
|
53
|
+
if (active.some(d => d.from == d.to || (d.from == d.to - 1 && state.doc.lineAt(d.from).to == d.from))) {
|
|
54
|
+
deco.add(from, from, Decoration.widget({
|
|
55
|
+
widget: new DiagnosticWidget(sev),
|
|
56
|
+
diagnostics: active.slice()
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
let markClass = active.reduce((c, d) => d.markClass ? c + " " + d.markClass : c, "");
|
|
61
|
+
deco.add(from, to, Decoration.mark({
|
|
62
|
+
class: "cm-lintRange cm-lintRange-" + sev + markClass,
|
|
63
|
+
diagnostics: active.slice(),
|
|
64
|
+
inclusiveEnd: active.some(a => a.to > to)
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
pos = to;
|
|
68
|
+
for (let i = 0; i < active.length; i++)
|
|
69
|
+
if (active[i].to <= pos)
|
|
70
|
+
active.splice(i--, 1);
|
|
71
|
+
}
|
|
72
|
+
let set = deco.finish();
|
|
73
|
+
return new LintState(set, panel, findDiagnostic(set));
|
|
37
74
|
}
|
|
38
75
|
}
|
|
39
76
|
function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
|
|
40
77
|
let found = null;
|
|
41
78
|
diagnostics.between(after, 1e9, (from, to, { spec }) => {
|
|
42
|
-
if (diagnostic && spec.diagnostic
|
|
79
|
+
if (diagnostic && spec.diagnostics.indexOf(diagnostic) < 0)
|
|
43
80
|
return;
|
|
44
|
-
|
|
45
|
-
|
|
81
|
+
if (!found)
|
|
82
|
+
found = new SelectedDiagnostic(from, to, diagnostic || spec.diagnostics[0]);
|
|
83
|
+
else if (spec.diagnostics.indexOf(found.diagnostic) < 0)
|
|
84
|
+
return false;
|
|
85
|
+
else
|
|
86
|
+
found = new SelectedDiagnostic(found.from, to, found.diagnostic);
|
|
46
87
|
});
|
|
47
88
|
return found;
|
|
48
89
|
}
|
|
@@ -116,24 +157,25 @@ function diagnosticCount(state) {
|
|
|
116
157
|
const activeMark = /*@__PURE__*/Decoration.mark({ class: "cm-lintRange cm-lintRange-active" });
|
|
117
158
|
function lintTooltip(view, pos, side) {
|
|
118
159
|
let { diagnostics } = view.state.field(lintState);
|
|
119
|
-
let found
|
|
160
|
+
let found, start = -1, end = -1;
|
|
120
161
|
diagnostics.between(pos - (side < 0 ? 1 : 0), pos + (side > 0 ? 1 : 0), (from, to, { spec }) => {
|
|
121
162
|
if (pos >= from && pos <= to &&
|
|
122
163
|
(from == to || ((pos > from || side > 0) && (pos < to || side < 0)))) {
|
|
123
|
-
found
|
|
124
|
-
|
|
125
|
-
|
|
164
|
+
found = spec.diagnostics;
|
|
165
|
+
start = from;
|
|
166
|
+
end = to;
|
|
167
|
+
return false;
|
|
126
168
|
}
|
|
127
169
|
});
|
|
128
170
|
let diagnosticFilter = view.state.facet(lintConfig).tooltipFilter;
|
|
129
|
-
if (diagnosticFilter)
|
|
171
|
+
if (found && diagnosticFilter)
|
|
130
172
|
found = diagnosticFilter(found, view.state);
|
|
131
|
-
if (!found
|
|
173
|
+
if (!found)
|
|
132
174
|
return null;
|
|
133
175
|
return {
|
|
134
|
-
pos:
|
|
135
|
-
end:
|
|
136
|
-
above: view.state.doc.lineAt(
|
|
176
|
+
pos: start,
|
|
177
|
+
end: end,
|
|
178
|
+
above: view.state.doc.lineAt(start).to < end,
|
|
137
179
|
create() {
|
|
138
180
|
return { dom: diagnosticsTooltip(view, found) };
|
|
139
181
|
}
|
|
@@ -270,7 +312,7 @@ function batchResults(promises, sink, error) {
|
|
|
270
312
|
if (collected.length == promises.length)
|
|
271
313
|
sink(collected);
|
|
272
314
|
else
|
|
273
|
-
setTimeout(() => sink(collected), 200);
|
|
315
|
+
timeout = setTimeout(() => sink(collected), 200);
|
|
274
316
|
}, error);
|
|
275
317
|
}
|
|
276
318
|
const lintConfig = /*@__PURE__*/Facet.define({
|
|
@@ -350,13 +392,13 @@ function renderDiagnostic(view, diagnostic, inPanel) {
|
|
|
350
392
|
}), diagnostic.source && elt("div", { class: "cm-diagnosticSource" }, diagnostic.source));
|
|
351
393
|
}
|
|
352
394
|
class DiagnosticWidget extends WidgetType {
|
|
353
|
-
constructor(
|
|
395
|
+
constructor(sev) {
|
|
354
396
|
super();
|
|
355
|
-
this.
|
|
397
|
+
this.sev = sev;
|
|
356
398
|
}
|
|
357
|
-
eq(other) { return other.
|
|
399
|
+
eq(other) { return other.sev == this.sev; }
|
|
358
400
|
toDOM() {
|
|
359
|
-
return elt("span", { class: "cm-lintPoint cm-lintPoint-" + this.
|
|
401
|
+
return elt("span", { class: "cm-lintPoint cm-lintPoint-" + this.sev });
|
|
360
402
|
}
|
|
361
403
|
}
|
|
362
404
|
class PanelItem {
|
|
@@ -439,35 +481,41 @@ class LintPanel {
|
|
|
439
481
|
update() {
|
|
440
482
|
let { diagnostics, selected } = this.view.state.field(lintState);
|
|
441
483
|
let i = 0, needsSync = false, newSelectedItem = null;
|
|
484
|
+
let seen = new Set();
|
|
442
485
|
diagnostics.between(0, this.view.state.doc.length, (_start, _end, { spec }) => {
|
|
443
|
-
let
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
if (found > i) {
|
|
457
|
-
this.items.splice(i, found - i);
|
|
486
|
+
for (let diagnostic of spec.diagnostics) {
|
|
487
|
+
if (seen.has(diagnostic))
|
|
488
|
+
continue;
|
|
489
|
+
seen.add(diagnostic);
|
|
490
|
+
let found = -1, item;
|
|
491
|
+
for (let j = i; j < this.items.length; j++)
|
|
492
|
+
if (this.items[j].diagnostic == diagnostic) {
|
|
493
|
+
found = j;
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
if (found < 0) {
|
|
497
|
+
item = new PanelItem(this.view, diagnostic);
|
|
498
|
+
this.items.splice(i, 0, item);
|
|
458
499
|
needsSync = true;
|
|
459
500
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
501
|
+
else {
|
|
502
|
+
item = this.items[found];
|
|
503
|
+
if (found > i) {
|
|
504
|
+
this.items.splice(i, found - i);
|
|
505
|
+
needsSync = true;
|
|
506
|
+
}
|
|
465
507
|
}
|
|
508
|
+
if (selected && item.diagnostic == selected.diagnostic) {
|
|
509
|
+
if (!item.dom.hasAttribute("aria-selected")) {
|
|
510
|
+
item.dom.setAttribute("aria-selected", "true");
|
|
511
|
+
newSelectedItem = item;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
else if (item.dom.hasAttribute("aria-selected")) {
|
|
515
|
+
item.dom.removeAttribute("aria-selected");
|
|
516
|
+
}
|
|
517
|
+
i++;
|
|
466
518
|
}
|
|
467
|
-
else if (item.dom.hasAttribute("aria-selected")) {
|
|
468
|
-
item.dom.removeAttribute("aria-selected");
|
|
469
|
-
}
|
|
470
|
-
i++;
|
|
471
519
|
});
|
|
472
520
|
while (i < this.items.length && !(this.items.length == 1 && this.items[0].diagnostic.from < 0)) {
|
|
473
521
|
needsSync = true;
|
|
@@ -636,11 +684,22 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|
|
636
684
|
function severityWeight(sev) {
|
|
637
685
|
return sev == "error" ? 4 : sev == "warning" ? 3 : sev == "info" ? 2 : 1;
|
|
638
686
|
}
|
|
687
|
+
function maxSeverity(diagnostics) {
|
|
688
|
+
let sev = "hint", weight = 1;
|
|
689
|
+
for (let d of diagnostics) {
|
|
690
|
+
let w = severityWeight(d.severity);
|
|
691
|
+
if (w > weight) {
|
|
692
|
+
weight = w;
|
|
693
|
+
sev = d.severity;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return sev;
|
|
697
|
+
}
|
|
639
698
|
class LintGutterMarker extends GutterMarker {
|
|
640
699
|
constructor(diagnostics) {
|
|
641
700
|
super();
|
|
642
701
|
this.diagnostics = diagnostics;
|
|
643
|
-
this.severity = diagnostics
|
|
702
|
+
this.severity = maxSeverity(diagnostics);
|
|
644
703
|
}
|
|
645
704
|
toDOM(view) {
|
|
646
705
|
let elt = document.createElement("div");
|
|
@@ -719,7 +778,8 @@ const lintGutterExtension = /*@__PURE__*/gutter({
|
|
|
719
778
|
widgetMarker: (view, widget, block) => {
|
|
720
779
|
let diagnostics = [];
|
|
721
780
|
view.state.field(lintGutterMarkers).between(block.from, block.to, (from, to, value) => {
|
|
722
|
-
|
|
781
|
+
if (from > block.from && from < block.to)
|
|
782
|
+
diagnostics.push(...value.diagnostics);
|
|
723
783
|
});
|
|
724
784
|
return diagnostics.length ? new LintGutterMarker(diagnostics) : null;
|
|
725
785
|
}
|
|
@@ -810,9 +870,25 @@ arguments hold the diagnostic's current position.
|
|
|
810
870
|
*/
|
|
811
871
|
function forEachDiagnostic(state, f) {
|
|
812
872
|
let lState = state.field(lintState, false);
|
|
813
|
-
if (lState && lState.diagnostics.size)
|
|
814
|
-
|
|
815
|
-
|
|
873
|
+
if (lState && lState.diagnostics.size) {
|
|
874
|
+
let pending = [], pendingStart = [], lastEnd = -1;
|
|
875
|
+
for (let iter = RangeSet.iter([lState.diagnostics]);; iter.next()) {
|
|
876
|
+
for (let i = 0; i < pending.length; i++)
|
|
877
|
+
if (!iter.value || iter.value.spec.diagnostics.indexOf(pending[i]) < 0) {
|
|
878
|
+
f(pending[i], pendingStart[i], lastEnd);
|
|
879
|
+
pending.splice(i, 1);
|
|
880
|
+
pendingStart.splice(i--, 1);
|
|
881
|
+
}
|
|
882
|
+
if (!iter.value)
|
|
883
|
+
break;
|
|
884
|
+
for (let d of iter.value.spec.diagnostics)
|
|
885
|
+
if (pending.indexOf(d) < 0) {
|
|
886
|
+
pending.push(d);
|
|
887
|
+
pendingStart.push(iter.from);
|
|
888
|
+
}
|
|
889
|
+
lastEnd = iter.to;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
816
892
|
}
|
|
817
893
|
|
|
818
894
|
export { closeLintPanel, diagnosticCount, forEachDiagnostic, forceLinting, lintGutter, lintKeymap, linter, nextDiagnostic, openLintPanel, previousDiagnostic, setDiagnostics, setDiagnosticsEffect };
|