@codemirror/lint 0.19.2 → 0.19.3
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 +8 -0
- package/dist/index.cjs +156 -13
- package/dist/index.d.ts +16 -3
- package/dist/index.js +156 -15
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.19.3 (2021-11-09)
|
|
2
|
+
|
|
3
|
+
### New features
|
|
4
|
+
|
|
5
|
+
Export a function `lintGutter` which returns an extension that installs a gutter marking lines with diagnostics.
|
|
6
|
+
|
|
7
|
+
The package now exports the effect used to update the diagnostics (`setDiagnosticsEffect`).
|
|
8
|
+
|
|
1
9
|
## 0.19.2 (2021-09-29)
|
|
2
10
|
|
|
3
11
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,8 @@ var view = require('@codemirror/view');
|
|
|
6
6
|
var state = require('@codemirror/state');
|
|
7
7
|
var tooltip = require('@codemirror/tooltip');
|
|
8
8
|
var panel = require('@codemirror/panel');
|
|
9
|
+
var gutter = require('@codemirror/gutter');
|
|
10
|
+
var rangeset = require('@codemirror/rangeset');
|
|
9
11
|
var elt = require('crelt');
|
|
10
12
|
|
|
11
13
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -51,9 +53,9 @@ function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
|
|
|
51
53
|
});
|
|
52
54
|
return found;
|
|
53
55
|
}
|
|
54
|
-
function maybeEnableLint(state$1, effects
|
|
56
|
+
function maybeEnableLint(state$1, effects) {
|
|
55
57
|
return state$1.field(lintState, false) ? effects : effects.concat(state.StateEffect.appendConfig.of([
|
|
56
|
-
lintState
|
|
58
|
+
lintState,
|
|
57
59
|
view.EditorView.decorations.compute([lintState], state => {
|
|
58
60
|
let { selected, panel } = state.field(lintState);
|
|
59
61
|
return !selected || !panel || selected.from == selected.to ? view.Decoration.none : view.Decoration.set([
|
|
@@ -66,13 +68,18 @@ function maybeEnableLint(state$1, effects, getState) {
|
|
|
66
68
|
}
|
|
67
69
|
/**
|
|
68
70
|
Returns a transaction spec which updates the current set of
|
|
69
|
-
diagnostics
|
|
71
|
+
diagnostics, and enables the lint extension if if wasn't already
|
|
72
|
+
active.
|
|
70
73
|
*/
|
|
71
74
|
function setDiagnostics(state, diagnostics) {
|
|
72
75
|
return {
|
|
73
|
-
effects: maybeEnableLint(state, [setDiagnosticsEffect.of(diagnostics)]
|
|
76
|
+
effects: maybeEnableLint(state, [setDiagnosticsEffect.of(diagnostics)])
|
|
74
77
|
};
|
|
75
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
The state effect that updates the set of active diagnostics. Can
|
|
81
|
+
be useful when writing an extension that needs to track these.
|
|
82
|
+
*/
|
|
76
83
|
const setDiagnosticsEffect = state.StateEffect.define();
|
|
77
84
|
const togglePanel = state.StateEffect.define();
|
|
78
85
|
const movePanelSelection = state.StateEffect.define();
|
|
@@ -131,17 +138,20 @@ function lintTooltip(view, pos, side) {
|
|
|
131
138
|
end: stackEnd,
|
|
132
139
|
above: view.state.doc.lineAt(stackStart).to < stackEnd,
|
|
133
140
|
create() {
|
|
134
|
-
return { dom:
|
|
141
|
+
return { dom: diagnosticsTooltip(view, found) };
|
|
135
142
|
}
|
|
136
143
|
};
|
|
137
144
|
}
|
|
145
|
+
function diagnosticsTooltip(view, diagnostics) {
|
|
146
|
+
return elt__default['default']("ul", { class: "cm-tooltip-lint" }, diagnostics.map(d => renderDiagnostic(view, d, false)));
|
|
147
|
+
}
|
|
138
148
|
/**
|
|
139
149
|
Command to open and focus the lint panel.
|
|
140
150
|
*/
|
|
141
151
|
const openLintPanel = (view) => {
|
|
142
152
|
let field = view.state.field(lintState, false);
|
|
143
153
|
if (!field || !field.panel)
|
|
144
|
-
view.dispatch({ effects: maybeEnableLint(view.state, [togglePanel.of(true)]
|
|
154
|
+
view.dispatch({ effects: maybeEnableLint(view.state, [togglePanel.of(true)]) });
|
|
145
155
|
let panel$1 = panel.getPanel(view, LintPanel.open);
|
|
146
156
|
if (panel$1)
|
|
147
157
|
panel$1.dom.querySelector(".cm-panel-lint ul").focus();
|
|
@@ -478,13 +488,11 @@ class LintPanel {
|
|
|
478
488
|
}
|
|
479
489
|
static open(view) { return new LintPanel(view); }
|
|
480
490
|
}
|
|
491
|
+
function svg(content, attrs = `viewBox="0 0 40 40"`) {
|
|
492
|
+
return `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" ${attrs}>${encodeURIComponent(content)}</svg>')`;
|
|
493
|
+
}
|
|
481
494
|
function underline(color) {
|
|
482
|
-
|
|
483
|
-
return "none";
|
|
484
|
-
let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="6" height="3">
|
|
485
|
-
<path d="m0 3 l2 -2 l1 0 l2 2 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>
|
|
486
|
-
</svg>`;
|
|
487
|
-
return `url('data:image/svg+xml;base64,${btoa(svg)}')`;
|
|
495
|
+
return svg(`<path d="m0 2.5 l2 -1.5 l1 0 l2 1.5 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>`, `width="6" height="3"`);
|
|
488
496
|
}
|
|
489
497
|
const baseTheme = view.EditorView.baseTheme({
|
|
490
498
|
".cm-diagnostic": {
|
|
@@ -511,7 +519,8 @@ const baseTheme = view.EditorView.baseTheme({
|
|
|
511
519
|
},
|
|
512
520
|
".cm-lintRange": {
|
|
513
521
|
backgroundPosition: "left bottom",
|
|
514
|
-
backgroundRepeat: "repeat-x"
|
|
522
|
+
backgroundRepeat: "repeat-x",
|
|
523
|
+
paddingBottom: "0.7px",
|
|
515
524
|
},
|
|
516
525
|
".cm-lintRange-error": { backgroundImage: underline("#d11") },
|
|
517
526
|
".cm-lintRange-warning": { backgroundImage: underline("orange") },
|
|
@@ -570,12 +579,146 @@ const baseTheme = view.EditorView.baseTheme({
|
|
|
570
579
|
}
|
|
571
580
|
}
|
|
572
581
|
});
|
|
582
|
+
class LintGutterMarker extends gutter.GutterMarker {
|
|
583
|
+
constructor(diagnostics) {
|
|
584
|
+
super();
|
|
585
|
+
this.diagnostics = diagnostics;
|
|
586
|
+
this.severity = diagnostics.reduce((max, d) => {
|
|
587
|
+
let s = d.severity;
|
|
588
|
+
return s == "error" || s == "warning" && max == "info" ? s : max;
|
|
589
|
+
}, "info");
|
|
590
|
+
}
|
|
591
|
+
toDOM(view) {
|
|
592
|
+
let elt = document.createElement("div");
|
|
593
|
+
elt.className = "cm-lint-marker cm-lint-marker-" + this.severity;
|
|
594
|
+
elt.onmouseover = () => gutterMarkerMouseOver(view, elt, this.diagnostics);
|
|
595
|
+
return elt;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function trackHoverOn(view, marker) {
|
|
599
|
+
let mousemove = (event) => {
|
|
600
|
+
let rect = marker.getBoundingClientRect();
|
|
601
|
+
if (event.clientX > rect.left - 10 /* Margin */ && event.clientX < rect.right + 10 /* Margin */ &&
|
|
602
|
+
event.clientY > rect.top - 10 /* Margin */ && event.clientY < rect.bottom + 10 /* Margin */)
|
|
603
|
+
return;
|
|
604
|
+
for (let target = event.target; target; target = target.parentNode) {
|
|
605
|
+
if (target.nodeType == 1 && target.classList.contains("cm-tooltip-lint"))
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
window.removeEventListener("mousemove", mousemove);
|
|
609
|
+
if (view.state.field(lintGutterTooltip))
|
|
610
|
+
view.dispatch({ effects: setLintGutterTooltip.of(null) });
|
|
611
|
+
};
|
|
612
|
+
window.addEventListener("mousemove", mousemove);
|
|
613
|
+
}
|
|
614
|
+
function gutterMarkerMouseOver(view, marker, diagnostics) {
|
|
615
|
+
function hovered() {
|
|
616
|
+
let line = view.visualLineAtHeight(marker.getBoundingClientRect().top + 5);
|
|
617
|
+
const linePos = view.coordsAtPos(line.from), markerRect = marker.getBoundingClientRect();
|
|
618
|
+
if (linePos) {
|
|
619
|
+
view.dispatch({ effects: setLintGutterTooltip.of({
|
|
620
|
+
pos: line.from,
|
|
621
|
+
above: false,
|
|
622
|
+
create() {
|
|
623
|
+
return {
|
|
624
|
+
dom: diagnosticsTooltip(view, diagnostics),
|
|
625
|
+
offset: { x: markerRect.left - linePos.left, y: 0 }
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
}) });
|
|
629
|
+
}
|
|
630
|
+
marker.onmouseout = marker.onmousemove = null;
|
|
631
|
+
trackHoverOn(view, marker);
|
|
632
|
+
}
|
|
633
|
+
let hoverTimeout = setTimeout(hovered, 600 /* Time */);
|
|
634
|
+
marker.onmouseout = () => {
|
|
635
|
+
clearTimeout(hoverTimeout);
|
|
636
|
+
marker.onmouseout = marker.onmousemove = null;
|
|
637
|
+
};
|
|
638
|
+
marker.onmousemove = () => {
|
|
639
|
+
clearTimeout(hoverTimeout);
|
|
640
|
+
hoverTimeout = setTimeout(hovered, 600 /* Time */);
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
function markersForDiagnostics(doc, diagnostics) {
|
|
644
|
+
let byLine = Object.create(null);
|
|
645
|
+
for (let diagnostic of diagnostics) {
|
|
646
|
+
let line = doc.lineAt(diagnostic.from);
|
|
647
|
+
(byLine[line.from] || (byLine[line.from] = [])).push(diagnostic);
|
|
648
|
+
}
|
|
649
|
+
let markers = [];
|
|
650
|
+
for (let line in byLine) {
|
|
651
|
+
markers.push(new LintGutterMarker(byLine[line]).range(+line));
|
|
652
|
+
}
|
|
653
|
+
return rangeset.RangeSet.of(markers, true);
|
|
654
|
+
}
|
|
655
|
+
const lintGutterExtension = gutter.gutter({
|
|
656
|
+
class: "cm-gutter-lint",
|
|
657
|
+
markers: view => view.state.field(lintGutterMarkers),
|
|
658
|
+
});
|
|
659
|
+
const lintGutterMarkers = state.StateField.define({
|
|
660
|
+
create() {
|
|
661
|
+
return rangeset.RangeSet.empty;
|
|
662
|
+
},
|
|
663
|
+
update(markers, tr) {
|
|
664
|
+
markers = markers.map(tr.changes);
|
|
665
|
+
for (let effect of tr.effects)
|
|
666
|
+
if (effect.is(setDiagnosticsEffect)) {
|
|
667
|
+
markers = markersForDiagnostics(tr.state.doc, effect.value);
|
|
668
|
+
}
|
|
669
|
+
return markers;
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
const setLintGutterTooltip = state.StateEffect.define();
|
|
673
|
+
const lintGutterTooltip = state.StateField.define({
|
|
674
|
+
create() { return null; },
|
|
675
|
+
update(tooltip, tr) {
|
|
676
|
+
if (tooltip && tr.docChanged)
|
|
677
|
+
tooltip = Object.assign(Object.assign({}, tooltip), { pos: tr.changes.mapPos(tooltip.pos) });
|
|
678
|
+
return tr.effects.reduce((t, e) => e.is(setLintGutterTooltip) ? e.value : t, tooltip);
|
|
679
|
+
},
|
|
680
|
+
provide: field => tooltip.showTooltip.from(field)
|
|
681
|
+
});
|
|
682
|
+
const lintGutterTheme = view.EditorView.baseTheme({
|
|
683
|
+
".cm-gutter-lint": {
|
|
684
|
+
width: "1.4em",
|
|
685
|
+
"& .cm-gutterElement": {
|
|
686
|
+
padding: "0 .2em",
|
|
687
|
+
display: "flex",
|
|
688
|
+
flexDirection: "column",
|
|
689
|
+
justifyContent: "center",
|
|
690
|
+
}
|
|
691
|
+
},
|
|
692
|
+
".cm-lint-marker": {
|
|
693
|
+
width: "1em",
|
|
694
|
+
height: "1em",
|
|
695
|
+
},
|
|
696
|
+
".cm-lint-marker-info": {
|
|
697
|
+
content: svg(`<path fill="#aaf" stroke="#77e" stroke-width="6" stroke-linejoin="round" d="M5 5L35 5L35 35L5 35Z"/>`)
|
|
698
|
+
},
|
|
699
|
+
".cm-lint-marker-warning": {
|
|
700
|
+
content: svg(`<path fill="#fe8" stroke="#fd7" stroke-width="6" stroke-linejoin="round" d="M20 6L37 35L3 35Z"/>`),
|
|
701
|
+
},
|
|
702
|
+
".cm-lint-marker-error:before": {
|
|
703
|
+
content: svg(`<circle cx="20" cy="20" r="15" fill="#f87" stroke="#f43" stroke-width="6"/>`)
|
|
704
|
+
},
|
|
705
|
+
});
|
|
706
|
+
/**
|
|
707
|
+
Returns an extension that installs a gutter showing markers for
|
|
708
|
+
each line that has diagnostics, which can be hovered over to see
|
|
709
|
+
the diagnostics.
|
|
710
|
+
*/
|
|
711
|
+
function lintGutter() {
|
|
712
|
+
return [lintGutterMarkers, lintGutterExtension, lintGutterTheme, lintGutterTooltip];
|
|
713
|
+
}
|
|
573
714
|
|
|
574
715
|
exports.closeLintPanel = closeLintPanel;
|
|
575
716
|
exports.diagnosticCount = diagnosticCount;
|
|
576
717
|
exports.forceLinting = forceLinting;
|
|
718
|
+
exports.lintGutter = lintGutter;
|
|
577
719
|
exports.lintKeymap = lintKeymap;
|
|
578
720
|
exports.linter = linter;
|
|
579
721
|
exports.nextDiagnostic = nextDiagnostic;
|
|
580
722
|
exports.openLintPanel = openLintPanel;
|
|
581
723
|
exports.setDiagnostics = setDiagnostics;
|
|
724
|
+
exports.setDiagnosticsEffect = setDiagnosticsEffect;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as _codemirror_state from '@codemirror/state';
|
|
2
2
|
import { EditorState, TransactionSpec, Extension } from '@codemirror/state';
|
|
3
|
+
import { EditorView, Command, KeyBinding } from '@codemirror/view';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
Describes a problem or hint for a piece of code.
|
|
@@ -52,10 +53,16 @@ interface Action {
|
|
|
52
53
|
}
|
|
53
54
|
/**
|
|
54
55
|
Returns a transaction spec which updates the current set of
|
|
55
|
-
diagnostics
|
|
56
|
+
diagnostics, and enables the lint extension if if wasn't already
|
|
57
|
+
active.
|
|
56
58
|
*/
|
|
57
59
|
declare function setDiagnostics(state: EditorState, diagnostics: readonly Diagnostic[]): TransactionSpec;
|
|
58
60
|
/**
|
|
61
|
+
The state effect that updates the set of active diagnostics. Can
|
|
62
|
+
be useful when writing an extension that needs to track these.
|
|
63
|
+
*/
|
|
64
|
+
declare const setDiagnosticsEffect: _codemirror_state.StateEffectType<readonly Diagnostic[]>;
|
|
65
|
+
/**
|
|
59
66
|
Returns the number of active lint diagnostics in the given state.
|
|
60
67
|
*/
|
|
61
68
|
declare function diagnosticCount(state: EditorState): number;
|
|
@@ -96,5 +103,11 @@ Forces any linters [configured](https://codemirror.net/6/docs/ref/#lint.linter)
|
|
|
96
103
|
editor is idle to run right away.
|
|
97
104
|
*/
|
|
98
105
|
declare function forceLinting(view: EditorView): void;
|
|
106
|
+
/**
|
|
107
|
+
Returns an extension that installs a gutter showing markers for
|
|
108
|
+
each line that has diagnostics, which can be hovered over to see
|
|
109
|
+
the diagnostics.
|
|
110
|
+
*/
|
|
111
|
+
declare function lintGutter(): Extension;
|
|
99
112
|
|
|
100
|
-
export { Action, Diagnostic, closeLintPanel, diagnosticCount, forceLinting, lintKeymap, linter, nextDiagnostic, openLintPanel, setDiagnostics };
|
|
113
|
+
export { Action, Diagnostic, closeLintPanel, diagnosticCount, forceLinting, lintGutter, lintKeymap, linter, nextDiagnostic, openLintPanel, setDiagnostics, setDiagnosticsEffect };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Decoration, EditorView, ViewPlugin, logException, WidgetType } from '@codemirror/view';
|
|
2
2
|
import { StateEffect, StateField, Facet } from '@codemirror/state';
|
|
3
|
-
import { hoverTooltip } from '@codemirror/tooltip';
|
|
3
|
+
import { hoverTooltip, showTooltip } from '@codemirror/tooltip';
|
|
4
4
|
import { showPanel, getPanel } from '@codemirror/panel';
|
|
5
|
+
import { gutter, GutterMarker } from '@codemirror/gutter';
|
|
6
|
+
import { RangeSet } from '@codemirror/rangeset';
|
|
5
7
|
import elt from 'crelt';
|
|
6
8
|
|
|
7
9
|
class SelectedDiagnostic {
|
|
@@ -43,9 +45,9 @@ function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
|
|
|
43
45
|
});
|
|
44
46
|
return found;
|
|
45
47
|
}
|
|
46
|
-
function maybeEnableLint(state, effects
|
|
48
|
+
function maybeEnableLint(state, effects) {
|
|
47
49
|
return state.field(lintState, false) ? effects : effects.concat(StateEffect.appendConfig.of([
|
|
48
|
-
lintState
|
|
50
|
+
lintState,
|
|
49
51
|
EditorView.decorations.compute([lintState], state => {
|
|
50
52
|
let { selected, panel } = state.field(lintState);
|
|
51
53
|
return !selected || !panel || selected.from == selected.to ? Decoration.none : Decoration.set([
|
|
@@ -58,13 +60,18 @@ function maybeEnableLint(state, effects, getState) {
|
|
|
58
60
|
}
|
|
59
61
|
/**
|
|
60
62
|
Returns a transaction spec which updates the current set of
|
|
61
|
-
diagnostics
|
|
63
|
+
diagnostics, and enables the lint extension if if wasn't already
|
|
64
|
+
active.
|
|
62
65
|
*/
|
|
63
66
|
function setDiagnostics(state, diagnostics) {
|
|
64
67
|
return {
|
|
65
|
-
effects: maybeEnableLint(state, [setDiagnosticsEffect.of(diagnostics)]
|
|
68
|
+
effects: maybeEnableLint(state, [setDiagnosticsEffect.of(diagnostics)])
|
|
66
69
|
};
|
|
67
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
The state effect that updates the set of active diagnostics. Can
|
|
73
|
+
be useful when writing an extension that needs to track these.
|
|
74
|
+
*/
|
|
68
75
|
const setDiagnosticsEffect = /*@__PURE__*/StateEffect.define();
|
|
69
76
|
const togglePanel = /*@__PURE__*/StateEffect.define();
|
|
70
77
|
const movePanelSelection = /*@__PURE__*/StateEffect.define();
|
|
@@ -123,17 +130,20 @@ function lintTooltip(view, pos, side) {
|
|
|
123
130
|
end: stackEnd,
|
|
124
131
|
above: view.state.doc.lineAt(stackStart).to < stackEnd,
|
|
125
132
|
create() {
|
|
126
|
-
return { dom:
|
|
133
|
+
return { dom: diagnosticsTooltip(view, found) };
|
|
127
134
|
}
|
|
128
135
|
};
|
|
129
136
|
}
|
|
137
|
+
function diagnosticsTooltip(view, diagnostics) {
|
|
138
|
+
return elt("ul", { class: "cm-tooltip-lint" }, diagnostics.map(d => renderDiagnostic(view, d, false)));
|
|
139
|
+
}
|
|
130
140
|
/**
|
|
131
141
|
Command to open and focus the lint panel.
|
|
132
142
|
*/
|
|
133
143
|
const openLintPanel = (view) => {
|
|
134
144
|
let field = view.state.field(lintState, false);
|
|
135
145
|
if (!field || !field.panel)
|
|
136
|
-
view.dispatch({ effects: maybeEnableLint(view.state, [togglePanel.of(true)]
|
|
146
|
+
view.dispatch({ effects: maybeEnableLint(view.state, [togglePanel.of(true)]) });
|
|
137
147
|
let panel = getPanel(view, LintPanel.open);
|
|
138
148
|
if (panel)
|
|
139
149
|
panel.dom.querySelector(".cm-panel-lint ul").focus();
|
|
@@ -470,13 +480,11 @@ class LintPanel {
|
|
|
470
480
|
}
|
|
471
481
|
static open(view) { return new LintPanel(view); }
|
|
472
482
|
}
|
|
483
|
+
function svg(content, attrs = `viewBox="0 0 40 40"`) {
|
|
484
|
+
return `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" ${attrs}>${encodeURIComponent(content)}</svg>')`;
|
|
485
|
+
}
|
|
473
486
|
function underline(color) {
|
|
474
|
-
|
|
475
|
-
return "none";
|
|
476
|
-
let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="6" height="3">
|
|
477
|
-
<path d="m0 3 l2 -2 l1 0 l2 2 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>
|
|
478
|
-
</svg>`;
|
|
479
|
-
return `url('data:image/svg+xml;base64,${btoa(svg)}')`;
|
|
487
|
+
return svg(`<path d="m0 2.5 l2 -1.5 l1 0 l2 1.5 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>`, `width="6" height="3"`);
|
|
480
488
|
}
|
|
481
489
|
const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|
482
490
|
".cm-diagnostic": {
|
|
@@ -503,7 +511,8 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|
|
503
511
|
},
|
|
504
512
|
".cm-lintRange": {
|
|
505
513
|
backgroundPosition: "left bottom",
|
|
506
|
-
backgroundRepeat: "repeat-x"
|
|
514
|
+
backgroundRepeat: "repeat-x",
|
|
515
|
+
paddingBottom: "0.7px",
|
|
507
516
|
},
|
|
508
517
|
".cm-lintRange-error": { backgroundImage: /*@__PURE__*/underline("#d11") },
|
|
509
518
|
".cm-lintRange-warning": { backgroundImage: /*@__PURE__*/underline("orange") },
|
|
@@ -562,5 +571,137 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|
|
562
571
|
}
|
|
563
572
|
}
|
|
564
573
|
});
|
|
574
|
+
class LintGutterMarker extends GutterMarker {
|
|
575
|
+
constructor(diagnostics) {
|
|
576
|
+
super();
|
|
577
|
+
this.diagnostics = diagnostics;
|
|
578
|
+
this.severity = diagnostics.reduce((max, d) => {
|
|
579
|
+
let s = d.severity;
|
|
580
|
+
return s == "error" || s == "warning" && max == "info" ? s : max;
|
|
581
|
+
}, "info");
|
|
582
|
+
}
|
|
583
|
+
toDOM(view) {
|
|
584
|
+
let elt = document.createElement("div");
|
|
585
|
+
elt.className = "cm-lint-marker cm-lint-marker-" + this.severity;
|
|
586
|
+
elt.onmouseover = () => gutterMarkerMouseOver(view, elt, this.diagnostics);
|
|
587
|
+
return elt;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
function trackHoverOn(view, marker) {
|
|
591
|
+
let mousemove = (event) => {
|
|
592
|
+
let rect = marker.getBoundingClientRect();
|
|
593
|
+
if (event.clientX > rect.left - 10 /* Margin */ && event.clientX < rect.right + 10 /* Margin */ &&
|
|
594
|
+
event.clientY > rect.top - 10 /* Margin */ && event.clientY < rect.bottom + 10 /* Margin */)
|
|
595
|
+
return;
|
|
596
|
+
for (let target = event.target; target; target = target.parentNode) {
|
|
597
|
+
if (target.nodeType == 1 && target.classList.contains("cm-tooltip-lint"))
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
window.removeEventListener("mousemove", mousemove);
|
|
601
|
+
if (view.state.field(lintGutterTooltip))
|
|
602
|
+
view.dispatch({ effects: setLintGutterTooltip.of(null) });
|
|
603
|
+
};
|
|
604
|
+
window.addEventListener("mousemove", mousemove);
|
|
605
|
+
}
|
|
606
|
+
function gutterMarkerMouseOver(view, marker, diagnostics) {
|
|
607
|
+
function hovered() {
|
|
608
|
+
let line = view.visualLineAtHeight(marker.getBoundingClientRect().top + 5);
|
|
609
|
+
const linePos = view.coordsAtPos(line.from), markerRect = marker.getBoundingClientRect();
|
|
610
|
+
if (linePos) {
|
|
611
|
+
view.dispatch({ effects: setLintGutterTooltip.of({
|
|
612
|
+
pos: line.from,
|
|
613
|
+
above: false,
|
|
614
|
+
create() {
|
|
615
|
+
return {
|
|
616
|
+
dom: diagnosticsTooltip(view, diagnostics),
|
|
617
|
+
offset: { x: markerRect.left - linePos.left, y: 0 }
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
}) });
|
|
621
|
+
}
|
|
622
|
+
marker.onmouseout = marker.onmousemove = null;
|
|
623
|
+
trackHoverOn(view, marker);
|
|
624
|
+
}
|
|
625
|
+
let hoverTimeout = setTimeout(hovered, 600 /* Time */);
|
|
626
|
+
marker.onmouseout = () => {
|
|
627
|
+
clearTimeout(hoverTimeout);
|
|
628
|
+
marker.onmouseout = marker.onmousemove = null;
|
|
629
|
+
};
|
|
630
|
+
marker.onmousemove = () => {
|
|
631
|
+
clearTimeout(hoverTimeout);
|
|
632
|
+
hoverTimeout = setTimeout(hovered, 600 /* Time */);
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
function markersForDiagnostics(doc, diagnostics) {
|
|
636
|
+
let byLine = Object.create(null);
|
|
637
|
+
for (let diagnostic of diagnostics) {
|
|
638
|
+
let line = doc.lineAt(diagnostic.from);
|
|
639
|
+
(byLine[line.from] || (byLine[line.from] = [])).push(diagnostic);
|
|
640
|
+
}
|
|
641
|
+
let markers = [];
|
|
642
|
+
for (let line in byLine) {
|
|
643
|
+
markers.push(new LintGutterMarker(byLine[line]).range(+line));
|
|
644
|
+
}
|
|
645
|
+
return RangeSet.of(markers, true);
|
|
646
|
+
}
|
|
647
|
+
const lintGutterExtension = /*@__PURE__*/gutter({
|
|
648
|
+
class: "cm-gutter-lint",
|
|
649
|
+
markers: view => view.state.field(lintGutterMarkers),
|
|
650
|
+
});
|
|
651
|
+
const lintGutterMarkers = /*@__PURE__*/StateField.define({
|
|
652
|
+
create() {
|
|
653
|
+
return RangeSet.empty;
|
|
654
|
+
},
|
|
655
|
+
update(markers, tr) {
|
|
656
|
+
markers = markers.map(tr.changes);
|
|
657
|
+
for (let effect of tr.effects)
|
|
658
|
+
if (effect.is(setDiagnosticsEffect)) {
|
|
659
|
+
markers = markersForDiagnostics(tr.state.doc, effect.value);
|
|
660
|
+
}
|
|
661
|
+
return markers;
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
const setLintGutterTooltip = /*@__PURE__*/StateEffect.define();
|
|
665
|
+
const lintGutterTooltip = /*@__PURE__*/StateField.define({
|
|
666
|
+
create() { return null; },
|
|
667
|
+
update(tooltip, tr) {
|
|
668
|
+
if (tooltip && tr.docChanged)
|
|
669
|
+
tooltip = Object.assign(Object.assign({}, tooltip), { pos: tr.changes.mapPos(tooltip.pos) });
|
|
670
|
+
return tr.effects.reduce((t, e) => e.is(setLintGutterTooltip) ? e.value : t, tooltip);
|
|
671
|
+
},
|
|
672
|
+
provide: field => showTooltip.from(field)
|
|
673
|
+
});
|
|
674
|
+
const lintGutterTheme = /*@__PURE__*/EditorView.baseTheme({
|
|
675
|
+
".cm-gutter-lint": {
|
|
676
|
+
width: "1.4em",
|
|
677
|
+
"& .cm-gutterElement": {
|
|
678
|
+
padding: "0 .2em",
|
|
679
|
+
display: "flex",
|
|
680
|
+
flexDirection: "column",
|
|
681
|
+
justifyContent: "center",
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
".cm-lint-marker": {
|
|
685
|
+
width: "1em",
|
|
686
|
+
height: "1em",
|
|
687
|
+
},
|
|
688
|
+
".cm-lint-marker-info": {
|
|
689
|
+
content: /*@__PURE__*/svg(`<path fill="#aaf" stroke="#77e" stroke-width="6" stroke-linejoin="round" d="M5 5L35 5L35 35L5 35Z"/>`)
|
|
690
|
+
},
|
|
691
|
+
".cm-lint-marker-warning": {
|
|
692
|
+
content: /*@__PURE__*/svg(`<path fill="#fe8" stroke="#fd7" stroke-width="6" stroke-linejoin="round" d="M20 6L37 35L3 35Z"/>`),
|
|
693
|
+
},
|
|
694
|
+
".cm-lint-marker-error:before": {
|
|
695
|
+
content: /*@__PURE__*/svg(`<circle cx="20" cy="20" r="15" fill="#f87" stroke="#f43" stroke-width="6"/>`)
|
|
696
|
+
},
|
|
697
|
+
});
|
|
698
|
+
/**
|
|
699
|
+
Returns an extension that installs a gutter showing markers for
|
|
700
|
+
each line that has diagnostics, which can be hovered over to see
|
|
701
|
+
the diagnostics.
|
|
702
|
+
*/
|
|
703
|
+
function lintGutter() {
|
|
704
|
+
return [lintGutterMarkers, lintGutterExtension, lintGutterTheme, lintGutterTooltip];
|
|
705
|
+
}
|
|
565
706
|
|
|
566
|
-
export { closeLintPanel, diagnosticCount, forceLinting, lintKeymap, linter, nextDiagnostic, openLintPanel, setDiagnostics };
|
|
707
|
+
export { closeLintPanel, diagnosticCount, forceLinting, lintGutter, lintKeymap, linter, nextDiagnostic, openLintPanel, setDiagnostics, setDiagnosticsEffect };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemirror/lint",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.3",
|
|
4
4
|
"description": "Linting support for the CodeMirror code editor",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "cm-runtests",
|
|
@@ -26,9 +26,11 @@
|
|
|
26
26
|
"sideEffects": false,
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"@codemirror/gutter": "^0.19.4",
|
|
29
30
|
"@codemirror/panel": "^0.19.0",
|
|
30
|
-
"@codemirror/
|
|
31
|
-
"@codemirror/
|
|
31
|
+
"@codemirror/rangeset": "^0.19.1",
|
|
32
|
+
"@codemirror/state": "^0.19.4",
|
|
33
|
+
"@codemirror/tooltip": "^0.19.5",
|
|
32
34
|
"@codemirror/view": "^0.19.0",
|
|
33
35
|
"crelt": "^1.0.5"
|
|
34
36
|
},
|