@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 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, getState) {
56
+ function maybeEnableLint(state$1, effects) {
55
57
  return state$1.field(lintState, false) ? effects : effects.concat(state.StateEffect.appendConfig.of([
56
- lintState.init(getState),
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)], () => LintState.init(diagnostics, null, state))
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: elt__default['default']("ul", { class: "cm-tooltip-lint" }, found.map(d => renderDiagnostic(view, d, false))) };
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)], () => LintState.init([], LintPanel.open, view.state)) });
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
- if (typeof btoa != "function")
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 { EditorView, Command, KeyBinding } from '@codemirror/view';
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, getState) {
48
+ function maybeEnableLint(state, effects) {
47
49
  return state.field(lintState, false) ? effects : effects.concat(StateEffect.appendConfig.of([
48
- lintState.init(getState),
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)], () => LintState.init(diagnostics, null, state))
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: elt("ul", { class: "cm-tooltip-lint" }, found.map(d => renderDiagnostic(view, d, false))) };
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)], () => LintState.init([], LintPanel.open, view.state)) });
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
- if (typeof btoa != "function")
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.2",
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/state": "^0.19.0",
31
- "@codemirror/tooltip": "^0.19.0",
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
  },