Skip to content

Commit 955fc3b

Browse files
committed
fix: generic code action matching, use lodash uniqBy, add comments
1 parent d718e85 commit 955fc3b

1 file changed

Lines changed: 44 additions & 23 deletions

File tree

  • packages/dbml-parse/src/services/code_actions
Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
import { uniqBy } from 'lodash-es';
12
import type Compiler from '@/compiler';
23
import type { QuickFix } from '@/core/types/errors';
34
import type {
45
CodeActionProvider, CodeActionList, CodeAction, CodeActionContext,
5-
TextModel, Range, CancellationToken, WorkspaceEdit,
6+
TextModel, Range, CancellationToken, WorkspaceEdit, MarkerData,
67
} from '../types';
78
import { Uri } from '../types';
9+
import { getEditorRange } from '../utils';
810

11+
// Provides quick fixes for diagnostics that have attached QuickFix data.
12+
// Monaco calls this when the user hovers over or clicks on a marker.
913
export default class DBMLCodeActionProvider implements CodeActionProvider {
1014
private compiler: Compiler;
1115

@@ -15,37 +19,46 @@ export default class DBMLCodeActionProvider implements CodeActionProvider {
1519

1620
provideCodeActions (
1721
model: TextModel,
18-
range: Range,
19-
_context: CodeActionContext,
22+
_range: Range,
23+
context: CodeActionContext,
2024
_token: CancellationToken,
2125
): CodeActionList | undefined {
22-
const hints = this.compiler.interpretProject().getHints();
23-
const overlapping = hints.filter((hint) => {
24-
if (!hint.quickFixes?.length) return false;
25-
const startLine = hint.nodeOrToken.startPos.line + 1;
26-
const endLine = hint.nodeOrToken.endPos.line + 1;
27-
return startLine <= range.endLineNumber && endLine >= range.startLineNumber;
28-
});
26+
// Only proceed if Monaco passed markers at the cursor position.
27+
if (!context.markers.length) return undefined;
2928

30-
if (!overlapping.length) return undefined;
29+
// Collect all hints that have quick fixes attached.
30+
const hints = this.compiler.interpretProject().getHints()
31+
.filter((h) => h.quickFixes?.length);
32+
if (!hints.length) return undefined;
3133

34+
// Match each marker to its corresponding hint by exact position,
35+
// then collect the quick fixes.
3236
const actions: CodeAction[] = [];
33-
const seen = new Set<string>();
34-
for (const hint of overlapping) {
35-
for (const fix of hint.quickFixes ?? []) {
36-
if (seen.has(fix.title)) continue;
37-
seen.add(fix.title);
38-
actions.push(this.quickFixToCodeAction(fix, model));
37+
38+
for (const marker of context.markers) {
39+
for (const hint of hints) {
40+
const range = getEditorRange(model, hint.nodeOrToken);
41+
if (range.startLineNumber !== marker.startLineNumber
42+
|| range.startColumn !== marker.startColumn
43+
|| range.endLineNumber !== marker.endLineNumber
44+
|| range.endColumn !== marker.endColumn) continue;
45+
46+
for (const fix of hint.quickFixes ?? []) {
47+
actions.push(this.quickFixToCodeAction(fix, model, marker));
48+
}
3949
}
4050
}
4151

42-
if (!actions.length) return undefined;
43-
return { actions, dispose () {} };
52+
// Deduplicate by title since the same fix may appear on
53+
// multiple hints (ref node + column declaration).
54+
const unique = uniqBy(actions, (a) => a.title);
55+
if (!unique.length) return undefined;
56+
return { actions: unique, dispose () {} };
4457
}
4558

46-
private quickFixToCodeAction (fix: QuickFix, model: TextModel): CodeAction {
47-
const uri = model.uri;
48-
const resource = Uri.parse(fix.filepath.toUri({ protocol: uri.scheme }));
59+
// Convert a QuickFix (offset-based) to a Monaco CodeAction (line/column-based).
60+
private quickFixToCodeAction (fix: QuickFix, model: TextModel, marker: MarkerData): CodeAction {
61+
const resource = Uri.parse(fix.filepath.toUri({ protocol: model.uri.scheme }));
4962
const edit: WorkspaceEdit = {
5063
edits: fix.edits.map((e) => {
5164
const startPos = model.getPositionAt(e.start);
@@ -65,6 +78,14 @@ export default class DBMLCodeActionProvider implements CodeActionProvider {
6578
};
6679
}),
6780
};
68-
return { title: fix.title, edit };
81+
82+
// Link the action to the marker so Monaco shows it as a quick fix.
83+
return {
84+
title: fix.title,
85+
edit,
86+
diagnostics: [
87+
marker,
88+
],
89+
};
6990
}
7091
}

0 commit comments

Comments
 (0)