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