1+ import { uniqBy } from 'lodash-es' ;
12import type Compiler from '@/compiler' ;
23import type { QuickFix } from '@/core/types/errors' ;
34import type {
45 CodeActionProvider , CodeActionList , CodeAction , CodeActionContext ,
5- TextModel , Range , CancellationToken , WorkspaceEdit ,
6+ TextModel , Range , CancellationToken , WorkspaceEdit , MarkerData ,
67} from '../types' ;
78import { 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.
913export 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