mirror of
https://github.com/chartdb/chartdb.git
synced 2026-02-09 21:19:45 -06:00
fix: add dbml autocomplete (#1017)
This commit is contained in:
17
package-lock.json
generated
17
package-lock.json
generated
@@ -9,7 +9,8 @@
|
||||
"version": "1.19.0",
|
||||
"dependencies": {
|
||||
"@ai-sdk/openai": "^2.0.72",
|
||||
"@dbml/core": "^3.13.9",
|
||||
"@dbml/core": "^3.14.1",
|
||||
"@dbml/parse": "^5.3.0",
|
||||
"@dnd-kit/sortable": "^8.0.0",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@radix-ui/react-accordion": "^1.2.0",
|
||||
@@ -514,7 +515,7 @@
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@dbml/parse": {
|
||||
"node_modules/@dbml/core/node_modules/@dbml/parse": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@dbml/parse/-/parse-3.14.1.tgz",
|
||||
"integrity": "sha512-I906RBlLF04IWQlMUw10EIKimafZ4STb86BC8hGnezb+wJqtAtVLAX8hfbzMDnGpjthm4jg0oddxTLFTZrk80g==",
|
||||
@@ -526,6 +527,18 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@dbml/parse": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@dbml/parse/-/parse-5.3.0.tgz",
|
||||
"integrity": "sha512-A9/kAdb/fdZvHC45L9vDO4k8mFXpLi9ZaFxrEjbZ5sxR/Y/cWRNBiWeiiwakvCbZoQCPbT9sWqfIbdqGy2sFzQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"lodash-es": "^4.17.21"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/accessibility": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/openai": "^2.0.72",
|
||||
"@dbml/core": "^3.13.9",
|
||||
"@dbml/core": "^3.14.1",
|
||||
"@dbml/parse": "^5.3.0",
|
||||
"@dnd-kit/sortable": "^8.0.0",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@radix-ui/react-accordion": "^1.2.0",
|
||||
|
||||
64
src/components/code-snippet/dbml/dbml-completion-provider.ts
Normal file
64
src/components/code-snippet/dbml/dbml-completion-provider.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import type { Monaco } from '@monaco-editor/react';
|
||||
import type { IDisposable } from 'monaco-editor';
|
||||
import { Compiler, services } from '@dbml/parse';
|
||||
|
||||
/**
|
||||
* Creates and manages a DBML completion provider using @dbml/parse.
|
||||
*
|
||||
* The provider maintains a Compiler instance that needs to be kept in sync
|
||||
* with the editor content to provide context-aware completions.
|
||||
*/
|
||||
export interface DBMLCompletionManager {
|
||||
/** Disposable to clean up the completion provider registration */
|
||||
dispose: () => void;
|
||||
/** Update the compiler with new DBML content */
|
||||
updateSource: (content: string) => void;
|
||||
}
|
||||
|
||||
// Trigger characters for DBML completions
|
||||
const TRIGGER_CHARACTERS = [' ', '[', ':', '.', '>', '<', '-'];
|
||||
|
||||
/**
|
||||
* Registers a DBML completion provider with Monaco editor.
|
||||
*
|
||||
* Uses @dbml/parse's built-in DBMLCompletionItemProvider which provides:
|
||||
* - Context-aware keyword suggestions (Table, Ref, Enum, etc.)
|
||||
* - Symbol suggestions based on parsed DBML (table names, column names)
|
||||
* - Field setting suggestions (pk, not null, unique, etc.)
|
||||
* - Ref operator suggestions (>, <, -, <>)
|
||||
*
|
||||
* @param monaco - Monaco editor instance
|
||||
* @param initialContent - Initial DBML content to parse
|
||||
* @returns Manager object with dispose and updateSource methods
|
||||
*/
|
||||
export function registerDBMLCompletionProvider(
|
||||
monaco: Monaco,
|
||||
initialContent: string = ''
|
||||
): DBMLCompletionManager {
|
||||
const compiler = new Compiler();
|
||||
|
||||
// Initialize with content if provided
|
||||
if (initialContent) {
|
||||
compiler.setSource(initialContent);
|
||||
}
|
||||
|
||||
// Create the completion provider from @dbml/parse
|
||||
const completionProvider = new services.DBMLCompletionItemProvider(
|
||||
compiler,
|
||||
TRIGGER_CHARACTERS
|
||||
);
|
||||
|
||||
// Register with Monaco
|
||||
const disposable: IDisposable =
|
||||
monaco.languages.registerCompletionItemProvider(
|
||||
'dbml',
|
||||
completionProvider
|
||||
);
|
||||
|
||||
return {
|
||||
dispose: () => disposable.dispose(),
|
||||
updateSource: (content: string) => {
|
||||
compiler.setSource(content);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -31,7 +31,12 @@ import {
|
||||
clearErrorHighlight,
|
||||
highlightErrorLine,
|
||||
} from '@/components/code-snippet/dbml/utils';
|
||||
import {
|
||||
registerDBMLCompletionProvider,
|
||||
type DBMLCompletionManager,
|
||||
} from '@/components/code-snippet/dbml/dbml-completion-provider';
|
||||
import type * as monaco from 'monaco-editor';
|
||||
import type { Monaco } from '@monaco-editor/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useFullScreenLoader } from '@/hooks/use-full-screen-spinner';
|
||||
|
||||
@@ -58,9 +63,13 @@ export const TableDBML: React.FC<TableDBMLProps> = () => {
|
||||
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>();
|
||||
const decorationsCollection =
|
||||
useRef<monaco.editor.IEditorDecorationsCollection>();
|
||||
const completionManagerRef = useRef<DBMLCompletionManager>();
|
||||
|
||||
const handleEditorDidMount = useCallback(
|
||||
(editor: monaco.editor.IStandaloneCodeEditor) => {
|
||||
(
|
||||
editor: monaco.editor.IStandaloneCodeEditor,
|
||||
monacoInstance: Monaco
|
||||
) => {
|
||||
editorRef.current = editor;
|
||||
decorationsCollection.current =
|
||||
editor.createDecorationsCollection();
|
||||
@@ -86,6 +95,13 @@ export const TableDBML: React.FC<TableDBMLProps> = () => {
|
||||
});
|
||||
|
||||
readOnlyDisposableRef.current = readOnlyDisposable;
|
||||
|
||||
// Register DBML completion provider
|
||||
completionManagerRef.current?.dispose();
|
||||
completionManagerRef.current = registerDBMLCompletionProvider(
|
||||
monacoInstance,
|
||||
editor.getValue()
|
||||
);
|
||||
},
|
||||
[]
|
||||
);
|
||||
@@ -304,6 +320,11 @@ export const TableDBML: React.FC<TableDBMLProps> = () => {
|
||||
dbmlToDisplay,
|
||||
]);
|
||||
|
||||
// Update completion provider when editor content changes
|
||||
useEffect(() => {
|
||||
completionManagerRef.current?.updateSource(editedDbml);
|
||||
}, [editedDbml]);
|
||||
|
||||
useEffect(() => {
|
||||
isMountedRef.current = true;
|
||||
|
||||
@@ -318,6 +339,11 @@ export const TableDBML: React.FC<TableDBMLProps> = () => {
|
||||
readOnlyDisposableRef.current.dispose();
|
||||
readOnlyDisposableRef.current = undefined;
|
||||
}
|
||||
|
||||
if (completionManagerRef.current) {
|
||||
completionManagerRef.current.dispose();
|
||||
completionManagerRef.current = undefined;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
39
src/types/dbml-parse.d.ts
vendored
Normal file
39
src/types/dbml-parse.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Type declarations for @dbml/parse
|
||||
*
|
||||
* The @dbml/parse package has types but they use path aliases (@/) that don't
|
||||
* resolve properly when consumed as a dependency. This module provides the
|
||||
* minimal types needed for the completion provider integration.
|
||||
*/
|
||||
declare module '@dbml/parse' {
|
||||
import type { languages, editor } from 'monaco-editor';
|
||||
|
||||
/**
|
||||
* DBML Compiler - parses and analyzes DBML content
|
||||
*/
|
||||
export class Compiler {
|
||||
constructor();
|
||||
setSource(source: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Completion item provider for Monaco editor
|
||||
*/
|
||||
export class DBMLCompletionItemProvider
|
||||
implements languages.CompletionItemProvider
|
||||
{
|
||||
triggerCharacters?: string[];
|
||||
constructor(compiler: Compiler, triggerCharacters?: string[]);
|
||||
provideCompletionItems(
|
||||
model: editor.ITextModel,
|
||||
position: { lineNumber: number; column: number }
|
||||
): languages.CompletionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Services namespace containing providers
|
||||
*/
|
||||
export namespace services {
|
||||
export { DBMLCompletionItemProvider };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user