Skip to content

Commit 588f262

Browse files
Copilotcyanzhong
andauthored
"Ignore" to unflag all occurrences (#45)
* Initial plan * fix: ignore all same-word diagnostics when clicking Ignore Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com> * remove lintKind check, handle empty problemText fallback, add ignoreDiagnostic tests Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
1 parent 7a21016 commit 588f262

2 files changed

Lines changed: 89 additions & 3 deletions

File tree

src/card.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ export function ignoreDiagnostic(view: EditorView, diag: Diagnostic, extraEffect
3535
}
3636
const { diagnostics } = view.state.field(diagnosticsField);
3737
const filtered = diagnostics.filter(d =>
38-
!(d.from === diag.from && d.to === diag.to && d.lintKind === diag.lintKind),
38+
diag.problemText
39+
? d.problemText !== diag.problemText
40+
: !(d.from === diag.from && d.to === diag.to && d.lintKind === diag.lintKind),
3941
);
4042
view.dispatch({ effects: [setDiagnosticsEffect.of(filtered), ...extraEffects] });
4143
}

tests/card.test.ts

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,89 @@
1-
import { describe, expect, it } from 'vitest';
2-
import { cardContentCSS } from '../src/card';
1+
import { describe, expect, it, vi } from 'vitest';
2+
import { EditorState } from '@codemirror/state';
3+
import type { EditorView } from '@codemirror/view';
4+
import { diagnosticsField, setDiagnosticsEffect } from '../src/decoration';
5+
import type { Diagnostic } from '../src/decoration';
6+
7+
vi.mock('../src/lint', () => ({
8+
shouldAddToDict: false,
9+
addToDictionary: vi.fn(),
10+
}));
11+
12+
// Import after mock so the module picks up the mocked lint
13+
const { cardContentCSS, ignoreDiagnostic } = await import('../src/card');
14+
15+
function makeDiag(overrides: Partial<Diagnostic> & { from: number; to: number }): Diagnostic {
16+
return {
17+
lintKind: 'Spelling',
18+
title: 'Spelling',
19+
messageHtml: '<p>Unknown word</p>',
20+
problemText: 'MarkEdit',
21+
actions: [],
22+
...overrides,
23+
};
24+
}
25+
26+
function createMockView(diagnostics: Diagnostic[]) {
27+
const state = EditorState.create({ extensions: [diagnosticsField] })
28+
.update({ effects: setDiagnosticsEffect.of(diagnostics) }).state;
29+
30+
let dispatched: Diagnostic[] | undefined;
31+
const view = {
32+
state,
33+
dispatch(tr: { effects: unknown[] }) {
34+
for (const e of tr.effects) {
35+
if ((e as { is: (t: unknown) => boolean }).is(setDiagnosticsEffect)) {
36+
dispatched = (e as { value: Diagnostic[] }).value;
37+
}
38+
}
39+
},
40+
} as unknown as EditorView;
41+
42+
return { view, getDispatched: () => dispatched };
43+
}
44+
45+
describe('ignoreDiagnostic', () => {
46+
it('removes all diagnostics with the same problemText', () => {
47+
const d1 = makeDiag({ from: 0, to: 8 });
48+
const d2 = makeDiag({ from: 20, to: 28 });
49+
const d3 = makeDiag({ from: 40, to: 48 });
50+
const { view, getDispatched } = createMockView([d1, d2, d3]);
51+
52+
ignoreDiagnostic(view, d1);
53+
expect(getDispatched()).toHaveLength(0);
54+
});
55+
56+
it('removes same problemText across different lintKinds', () => {
57+
const d1 = makeDiag({ from: 0, to: 8, lintKind: 'Spelling' });
58+
const d2 = makeDiag({ from: 20, to: 28, lintKind: 'Style' });
59+
const { view, getDispatched } = createMockView([d1, d2]);
60+
61+
ignoreDiagnostic(view, d1);
62+
expect(getDispatched()).toHaveLength(0);
63+
});
64+
65+
it('keeps diagnostics with different problemText', () => {
66+
const d1 = makeDiag({ from: 0, to: 8, problemText: 'MarkEdit' });
67+
const d2 = makeDiag({ from: 20, to: 25, problemText: 'other' });
68+
const { view, getDispatched } = createMockView([d1, d2]);
69+
70+
ignoreDiagnostic(view, d1);
71+
const remaining = getDispatched()!;
72+
expect(remaining).toHaveLength(1);
73+
expect(remaining[0].problemText).toBe('other');
74+
});
75+
76+
it('falls back to positional match when problemText is empty', () => {
77+
const d1 = makeDiag({ from: 0, to: 5, problemText: '', lintKind: 'Grammar' });
78+
const d2 = makeDiag({ from: 10, to: 15, problemText: '', lintKind: 'Grammar' });
79+
const { view, getDispatched } = createMockView([d1, d2]);
80+
81+
ignoreDiagnostic(view, d1);
82+
const remaining = getDispatched()!;
83+
expect(remaining).toHaveLength(1);
84+
expect(remaining[0].from).toBe(10);
85+
});
86+
});
387

488
describe('cardContentCSS', () => {
589
it('includes message, button, ignore, and actions styles', () => {

0 commit comments

Comments
 (0)