@codemirror/lint 6.2.0 → 6.2.2

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,15 @@
1
+ ## 6.2.2 (2023-06-05)
2
+
3
+ ### Bug fixes
4
+
5
+ Make sure lint gutter tooltips are properly closed when the content of their line changes.
6
+
7
+ ## 6.2.1 (2023-04-13)
8
+
9
+ ### Bug fixes
10
+
11
+ The `linter` function now eagerly includes all lint-related extensions, rather than appending them to the configuration as-needed, so that turning off linting by clearing the compartment that contains it works properly.
12
+
1
13
  ## 6.2.0 (2023-02-27)
2
14
 
3
15
  ### New features
package/dist/index.cjs CHANGED
@@ -55,20 +55,11 @@ function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
55
55
  return found;
56
56
  }
57
57
  function hideTooltip(tr, tooltip) {
58
- return !!(tr.effects.some(e => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(tooltip.pos));
58
+ let line = tr.startState.doc.lineAt(tooltip.pos);
59
+ return !!(tr.effects.some(e => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(line.from, line.to));
59
60
  }
60
61
  function maybeEnableLint(state$1, effects) {
61
- return state$1.field(lintState, false) ? effects : effects.concat(state.StateEffect.appendConfig.of([
62
- lintState,
63
- view.EditorView.decorations.compute([lintState], state => {
64
- let { selected, panel } = state.field(lintState);
65
- return !selected || !panel || selected.from == selected.to ? view.Decoration.none : view.Decoration.set([
66
- activeMark.range(selected.from, selected.to)
67
- ]);
68
- }),
69
- view.hoverTooltip(lintTooltip, { hideOn: hideTooltip }),
70
- baseTheme
71
- ]));
62
+ return state$1.field(lintState, false) ? effects : effects.concat(state.StateEffect.appendConfig.of(lintExtensions));
72
63
  }
73
64
  /**
74
65
  Returns a transaction spec which updates the current set of
@@ -256,8 +247,7 @@ const lintConfig = state.Facet.define({
256
247
  }, {
257
248
  needsRefresh: (a, b) => !a ? b : !b ? a : u => a(u) || b(u)
258
249
  }));
259
- },
260
- enables: lintPlugin
250
+ }
261
251
  });
262
252
  /**
263
253
  Given a diagnostic source, this function returns an extension that
@@ -265,7 +255,11 @@ enables linting with that source. It will be called whenever the
265
255
  editor is idle (after its content changed).
266
256
  */
267
257
  function linter(source, config = {}) {
268
- return lintConfig.of({ source, config });
258
+ return [
259
+ lintConfig.of({ source, config }),
260
+ lintPlugin,
261
+ lintExtensions
262
+ ];
269
263
  }
270
264
  /**
271
265
  Forces any linters [configured](https://codemirror.net/6/docs/ref/#lint.linter) to run when the
@@ -619,8 +613,8 @@ class LintGutterMarker extends view.GutterMarker {
619
613
  function trackHoverOn(view, marker) {
620
614
  let mousemove = (event) => {
621
615
  let rect = marker.getBoundingClientRect();
622
- if (event.clientX > rect.left - 10 /* Hover.Margin */ && event.clientX < rect.right + 10 /* Hover.Margin */ &&
623
- event.clientY > rect.top - 10 /* Hover.Margin */ && event.clientY < rect.bottom + 10 /* Hover.Margin */)
616
+ if (event.clientX > rect.left - 10 /* Margin */ && event.clientX < rect.right + 10 /* Margin */ &&
617
+ event.clientY > rect.top - 10 /* Margin */ && event.clientY < rect.bottom + 10 /* Margin */)
624
618
  return;
625
619
  for (let target = event.target; target; target = target.parentNode) {
626
620
  if (target.nodeType == 1 && target.classList.contains("cm-tooltip-lint"))
@@ -727,10 +721,21 @@ const lintGutterTheme = view.EditorView.baseTheme({
727
721
  content: svg(`<circle cx="20" cy="20" r="15" fill="#f87" stroke="#f43" stroke-width="6"/>`)
728
722
  },
729
723
  });
724
+ const lintExtensions = [
725
+ lintState,
726
+ view.EditorView.decorations.compute([lintState], state => {
727
+ let { selected, panel } = state.field(lintState);
728
+ return !selected || !panel || selected.from == selected.to ? view.Decoration.none : view.Decoration.set([
729
+ activeMark.range(selected.from, selected.to)
730
+ ]);
731
+ }),
732
+ view.hoverTooltip(lintTooltip, { hideOn: hideTooltip }),
733
+ baseTheme
734
+ ];
730
735
  const lintGutterConfig = state.Facet.define({
731
736
  combine(configs) {
732
737
  return state.combineConfig(configs, {
733
- hoverTime: 300 /* Hover.Time */,
738
+ hoverTime: 300 /* Time */,
734
739
  markerFilter: null,
735
740
  tooltipFilter: null
736
741
  });
@@ -0,0 +1,163 @@
1
+ import * as _codemirror_state from '@codemirror/state';
2
+ import { EditorState, TransactionSpec, Extension } from '@codemirror/state';
3
+ import { EditorView, Command, KeyBinding, ViewUpdate } from '@codemirror/view';
4
+
5
+ /**
6
+ Describes a problem or hint for a piece of code.
7
+ */
8
+ interface Diagnostic {
9
+ /**
10
+ The start position of the relevant text.
11
+ */
12
+ from: number;
13
+ /**
14
+ The end position. May be equal to `from`, though actually
15
+ covering text is preferable.
16
+ */
17
+ to: number;
18
+ /**
19
+ The severity of the problem. This will influence how it is
20
+ displayed.
21
+ */
22
+ severity: "info" | "warning" | "error";
23
+ /**
24
+ An optional source string indicating where the diagnostic is
25
+ coming from. You can put the name of your linter here, if
26
+ applicable.
27
+ */
28
+ source?: string;
29
+ /**
30
+ The message associated with this diagnostic.
31
+ */
32
+ message: string;
33
+ /**
34
+ An optional custom rendering function that displays the message
35
+ as a DOM node.
36
+ */
37
+ renderMessage?: () => Node;
38
+ /**
39
+ An optional array of actions that can be taken on this
40
+ diagnostic.
41
+ */
42
+ actions?: readonly Action[];
43
+ }
44
+ /**
45
+ An action associated with a diagnostic.
46
+ */
47
+ interface Action {
48
+ /**
49
+ The label to show to the user. Should be relatively short.
50
+ */
51
+ name: string;
52
+ /**
53
+ The function to call when the user activates this action. Is
54
+ given the diagnostic's _current_ position, which may have
55
+ changed since the creation of the diagnostic, due to editing.
56
+ */
57
+ apply: (view: EditorView, from: number, to: number) => void;
58
+ }
59
+ declare type DiagnosticFilter = (diagnostics: readonly Diagnostic[]) => Diagnostic[];
60
+ interface LintConfig {
61
+ /**
62
+ Time to wait (in milliseconds) after a change before running
63
+ the linter. Defaults to 750ms.
64
+ */
65
+ delay?: number;
66
+ /**
67
+ Optional predicate that can be used to indicate when diagnostics
68
+ need to be recomputed. Linting is always re-done on document
69
+ changes.
70
+ */
71
+ needsRefresh?: null | ((update: ViewUpdate) => boolean);
72
+ /**
73
+ Optional filter to determine which diagnostics produce markers
74
+ in the content.
75
+ */
76
+ markerFilter?: null | DiagnosticFilter;
77
+ /**
78
+ Filter applied to a set of diagnostics shown in a tooltip. No
79
+ tooltip will appear if the empty set is returned.
80
+ */
81
+ tooltipFilter?: null | DiagnosticFilter;
82
+ }
83
+ interface LintGutterConfig {
84
+ /**
85
+ The delay before showing a tooltip when hovering over a lint gutter marker.
86
+ */
87
+ hoverTime?: number;
88
+ /**
89
+ Optional filter determining which diagnostics show a marker in
90
+ the gutter.
91
+ */
92
+ markerFilter?: null | DiagnosticFilter;
93
+ /**
94
+ Optional filter for diagnostics displayed in a tooltip, which
95
+ can also be used to prevent a tooltip appearing.
96
+ */
97
+ tooltipFilter?: null | DiagnosticFilter;
98
+ }
99
+ /**
100
+ Returns a transaction spec which updates the current set of
101
+ diagnostics, and enables the lint extension if if wasn't already
102
+ active.
103
+ */
104
+ declare function setDiagnostics(state: EditorState, diagnostics: readonly Diagnostic[]): TransactionSpec;
105
+ /**
106
+ The state effect that updates the set of active diagnostics. Can
107
+ be useful when writing an extension that needs to track these.
108
+ */
109
+ declare const setDiagnosticsEffect: _codemirror_state.StateEffectType<readonly Diagnostic[]>;
110
+ /**
111
+ Returns the number of active lint diagnostics in the given state.
112
+ */
113
+ declare function diagnosticCount(state: EditorState): number;
114
+ /**
115
+ Command to open and focus the lint panel.
116
+ */
117
+ declare const openLintPanel: Command;
118
+ /**
119
+ Command to close the lint panel, when open.
120
+ */
121
+ declare const closeLintPanel: Command;
122
+ /**
123
+ Move the selection to the next diagnostic.
124
+ */
125
+ declare const nextDiagnostic: Command;
126
+ /**
127
+ A set of default key bindings for the lint functionality.
128
+
129
+ - Ctrl-Shift-m (Cmd-Shift-m on macOS): [`openLintPanel`](https://codemirror.net/6/docs/ref/#lint.openLintPanel)
130
+ - F8: [`nextDiagnostic`](https://codemirror.net/6/docs/ref/#lint.nextDiagnostic)
131
+ */
132
+ declare const lintKeymap: readonly KeyBinding[];
133
+ /**
134
+ The type of a function that produces diagnostics.
135
+ */
136
+ declare type LintSource = (view: EditorView) => readonly Diagnostic[] | Promise<readonly Diagnostic[]>;
137
+ /**
138
+ Given a diagnostic source, this function returns an extension that
139
+ enables linting with that source. It will be called whenever the
140
+ editor is idle (after its content changed).
141
+ */
142
+ declare function linter(source: LintSource, config?: LintConfig): Extension;
143
+ /**
144
+ Forces any linters [configured](https://codemirror.net/6/docs/ref/#lint.linter) to run when the
145
+ editor is idle to run right away.
146
+ */
147
+ declare function forceLinting(view: EditorView): void;
148
+ /**
149
+ Returns an extension that installs a gutter showing markers for
150
+ each line that has diagnostics, which can be hovered over to see
151
+ the diagnostics.
152
+ */
153
+ declare function lintGutter(config?: LintGutterConfig): Extension;
154
+ /**
155
+ Iterate over the marked diagnostics for the given editor state,
156
+ calling `f` for each of them. Note that, if the document changed
157
+ since the diagnostics were created, the `Diagnostic` object will
158
+ hold the original outdated position, whereas the `to` and `from`
159
+ arguments hold the diagnostic's current position.
160
+ */
161
+ declare function forEachDiagnostic(state: EditorState, f: (d: Diagnostic, from: number, to: number) => void): void;
162
+
163
+ export { Action, Diagnostic, LintSource, closeLintPanel, diagnosticCount, forEachDiagnostic, forceLinting, lintGutter, lintKeymap, linter, nextDiagnostic, openLintPanel, setDiagnostics, setDiagnosticsEffect };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Decoration, showPanel, EditorView, ViewPlugin, logException, gutter, showTooltip, getPanel, WidgetType, hoverTooltip, GutterMarker } from '@codemirror/view';
1
+ import { Decoration, showPanel, EditorView, ViewPlugin, logException, gutter, showTooltip, hoverTooltip, getPanel, WidgetType, GutterMarker } from '@codemirror/view';
2
2
  import { StateEffect, StateField, Facet, combineConfig, RangeSet } from '@codemirror/state';
3
3
  import elt from 'crelt';
4
4
 
@@ -47,20 +47,11 @@ function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
47
47
  return found;
48
48
  }
49
49
  function hideTooltip(tr, tooltip) {
50
- return !!(tr.effects.some(e => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(tooltip.pos));
50
+ let line = tr.startState.doc.lineAt(tooltip.pos);
51
+ return !!(tr.effects.some(e => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(line.from, line.to));
51
52
  }
52
53
  function maybeEnableLint(state, effects) {
53
- return state.field(lintState, false) ? effects : effects.concat(StateEffect.appendConfig.of([
54
- lintState,
55
- EditorView.decorations.compute([lintState], state => {
56
- let { selected, panel } = state.field(lintState);
57
- return !selected || !panel || selected.from == selected.to ? Decoration.none : Decoration.set([
58
- activeMark.range(selected.from, selected.to)
59
- ]);
60
- }),
61
- hoverTooltip(lintTooltip, { hideOn: hideTooltip }),
62
- baseTheme
63
- ]));
54
+ return state.field(lintState, false) ? effects : effects.concat(StateEffect.appendConfig.of(lintExtensions));
64
55
  }
65
56
  /**
66
57
  Returns a transaction spec which updates the current set of
@@ -248,8 +239,7 @@ const lintConfig = /*@__PURE__*/Facet.define({
248
239
  }, {
249
240
  needsRefresh: (a, b) => !a ? b : !b ? a : u => a(u) || b(u)
250
241
  }));
251
- },
252
- enables: lintPlugin
242
+ }
253
243
  });
254
244
  /**
255
245
  Given a diagnostic source, this function returns an extension that
@@ -257,7 +247,11 @@ enables linting with that source. It will be called whenever the
257
247
  editor is idle (after its content changed).
258
248
  */
259
249
  function linter(source, config = {}) {
260
- return lintConfig.of({ source, config });
250
+ return [
251
+ lintConfig.of({ source, config }),
252
+ lintPlugin,
253
+ lintExtensions
254
+ ];
261
255
  }
262
256
  /**
263
257
  Forces any linters [configured](https://codemirror.net/6/docs/ref/#lint.linter) to run when the
@@ -611,8 +605,8 @@ class LintGutterMarker extends GutterMarker {
611
605
  function trackHoverOn(view, marker) {
612
606
  let mousemove = (event) => {
613
607
  let rect = marker.getBoundingClientRect();
614
- if (event.clientX > rect.left - 10 /* Hover.Margin */ && event.clientX < rect.right + 10 /* Hover.Margin */ &&
615
- event.clientY > rect.top - 10 /* Hover.Margin */ && event.clientY < rect.bottom + 10 /* Hover.Margin */)
608
+ if (event.clientX > rect.left - 10 /* Margin */ && event.clientX < rect.right + 10 /* Margin */ &&
609
+ event.clientY > rect.top - 10 /* Margin */ && event.clientY < rect.bottom + 10 /* Margin */)
616
610
  return;
617
611
  for (let target = event.target; target; target = target.parentNode) {
618
612
  if (target.nodeType == 1 && target.classList.contains("cm-tooltip-lint"))
@@ -719,10 +713,21 @@ const lintGutterTheme = /*@__PURE__*/EditorView.baseTheme({
719
713
  content: /*@__PURE__*/svg(`<circle cx="20" cy="20" r="15" fill="#f87" stroke="#f43" stroke-width="6"/>`)
720
714
  },
721
715
  });
716
+ const lintExtensions = [
717
+ lintState,
718
+ /*@__PURE__*/EditorView.decorations.compute([lintState], state => {
719
+ let { selected, panel } = state.field(lintState);
720
+ return !selected || !panel || selected.from == selected.to ? Decoration.none : Decoration.set([
721
+ activeMark.range(selected.from, selected.to)
722
+ ]);
723
+ }),
724
+ /*@__PURE__*/hoverTooltip(lintTooltip, { hideOn: hideTooltip }),
725
+ baseTheme
726
+ ];
722
727
  const lintGutterConfig = /*@__PURE__*/Facet.define({
723
728
  combine(configs) {
724
729
  return combineConfig(configs, {
725
- hoverTime: 300 /* Hover.Time */,
730
+ hoverTime: 300 /* Time */,
726
731
  markerFilter: null,
727
732
  tooltipFilter: null
728
733
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/lint",
3
- "version": "6.2.0",
3
+ "version": "6.2.2",
4
4
  "description": "Linting support for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",
@@ -31,7 +31,7 @@
31
31
  "crelt": "^1.0.5"
32
32
  },
33
33
  "devDependencies": {
34
- "@codemirror/buildhelper": "^0.1.0"
34
+ "@codemirror/buildhelper": "^1.0.0"
35
35
  },
36
36
  "repository": {
37
37
  "type": "git",