๐ A lightweight adapter for integrating completion services with Monaco Editor's inline completion system.
Installation โข Quick Start โข Documentation โข Contributing
- ๐ป Ghost Text Display - Inline suggestions with keyboard navigation
- โก High Performance - Debouncing, caching, and optimized for large files
- ๐ฏ Type Safety - Comprehensive TypeScript support
- ๐จ Theme Support - Dark and light themes with customization options
- ๐ Event System - Rich analytics and error tracking
- ๐งฉ React Integration - Pre-built components and hooks
npm install @ydb-platform/monaco-ghost monaco-editor
import React, { useCallback } from 'react';
import MonacoEditor from 'react-monaco-editor';
import * as monaco from 'monaco-editor';
import { useMonacoGhost } from '@ydb-platform/monaco-ghost';
function MyCustomEditor() {
// Java-specific API implementation
const javaApi = {
getCodeAssistSuggestions: async () => ({
Suggests: [{ Text: 'System.out.println("Hello, World!");' }],
RequestId: 'demo-request',
}),
};
// Java-specific configuration
const javaConfig = {
debounceTime: 200,
textLimits: {
beforeCursor: 8000,
afterCursor: 1000,
},
suggestionCache: {
enabled: true,
},
};
const eventHandlers = {
onCompletionAccept: text => console.log('Accepted:', text),
onCompletionDecline: (text, reason, otherSuggestions) =>
console.log('Declined:', text, reason, otherSuggestions),
onCompletionIgnore: (text, otherSuggestions) => console.log('Ignored:', text, otherSuggestions),
onCompletionError: error => console.error('Error:', error),
};
const { registerMonacoGhost, dispose } = useMonacoGhost({
api: javaApi,
eventHandlers,
config: javaConfig,
});
const editorDidMount = useCallback(
(editor: monaco.editor.IStandaloneCodeEditor) => {
registerMonacoGhost(editor);
},
[registerMonacoGhost]
);
const options = {
selectOnLineNumbers: true,
minimap: { enabled: false },
automaticLayout: true,
fontSize: 14,
lineNumbers: 'on',
scrollBeyondLastLine: false,
roundedSelection: false,
padding: { top: 10 },
};
return (
<MonacoEditor
width="800"
height="600"
language="java"
theme="vs-dark" // or "vs-light"
value="// Your Java code here"
options={options}
editorDidMount={editorDidMount}
/>
);
}
Using the pre-built editor component
// Using the pre-built editor component
import { MonacoEditor } from '@ydb-platform/monaco-ghost';
function MyApp() {
// SQL-specific API implementation
const sqlApi = {
getCodeAssistSuggestions: async () => ({
Suggests: [{ Text: 'SELECT * FROM users;' }],
RequestId: 'demo-request',
}),
};
// SQL-specific configuration
const sqlConfig = {
debounceTime: 200,
textLimits: {
beforeCursor: 8000,
afterCursor: 1000,
},
suggestionCache: {
enabled: true,
},
};
return (
<MonacoEditor
initialValue="-- Your SQL code here"
language="sql"
theme="vs-dark" // or "vs-light"
api={sqlApi}
config={sqlConfig}
onCompletionAccept={text => console.log('Accepted:', text)}
onCompletionDecline={(text, reason, otherSuggestions) =>
console.log('Declined:', text, reason, otherSuggestions)
}
onCompletionIgnore={(text, otherSuggestions) =>
console.log('Ignored:', text, otherSuggestions)
}
onCompletionError={error => console.error('Error:', error)}
editorOptions={{
minimap: { enabled: false },
fontSize: 14,
}}
/>
);
}
View Vanilla JavaScript implementation
import * as monaco from 'monaco-editor';
import {
createCodeCompletionService,
registerCompletionCommands,
} from '@ydb-platform/monaco-ghost';
// Create language-specific API implementation
const sqlApi = {
getCodeAssistSuggestions: async data => {
// Call your completion service
// Return suggestions in the expected format
return {
Suggests: [{ Text: 'SELECT * FROM users;' }],
RequestId: 'request-id',
};
},
};
// Configure the adapter with language-specific settings
const sqlConfig = {
debounceTime: 200,
textLimits: {
beforeCursor: 8000,
afterCursor: 1000,
},
suggestionCache: {
enabled: true,
},
};
// Create provider for SQL
const sqlCompletionProvider = createCodeCompletionService(sqlApi, sqlConfig);
// Subscribe to completion events with type safety
sqlCompletionProvider.events.on('completion:accept', data => {
console.log('Completion accepted:', data.acceptedText);
});
sqlCompletionProvider.events.on('completion:decline', data => {
console.log(
'Completion declined:',
data.suggestionText,
'reason:',
data.reason,
'other suggestions:',
data.otherSuggestions
);
});
sqlCompletionProvider.events.on('completion:ignore', data => {
console.log(
'Completion ignored:',
data.suggestionText,
'other suggestions:',
data.otherSuggestions
);
});
sqlCompletionProvider.events.on('completion:error', error => {
console.error('Completion error:', error);
});
// Register with Monaco for SQL
monaco.languages.registerInlineCompletionsProvider(['sql'], sqlCompletionProvider);
// Register commands (assuming you have an editor instance)
registerCompletionCommands(monaco, sqlCompletionProvider, editor);
Key | Action |
---|---|
Tab |
Accept current suggestion |
Escape |
Decline current suggestion |
Alt+] |
Cycle to next suggestion |
Alt+[ |
Cycle to previous suggestion |
interface CodeCompletionConfig {
// Required when using hooks
language?: string; // The language this configuration applies to (e.g., 'sql', 'java')
// Performance settings
debounceTime?: number; // Time in ms to debounce API calls (default: 200)
// Text limits
textLimits?: {
beforeCursor?: number; // Characters to include before cursor (default: 8000)
afterCursor?: number; // Characters to include after cursor (default: 1000)
};
// Cache settings
suggestionCache?: {
enabled?: boolean; // Whether to enable suggestion caching (default: true)
};
}
View API Interface details
interface ICodeCompletionAPI {
getCodeAssistSuggestions(data: PromptFile[]): Promise<Suggestions>;
}
export interface PromptPosition {
lineNumber: number;
column: number;
}
export interface PromptFragment {
text: string;
start: PromptPosition;
end: PromptPosition;
}
export interface PromptFile {
path: string;
fragments: PromptFragment[];
cursorPosition: PromptPosition;
}
export interface Suggestions {
items: string[];
requestId?: string;
}
View Events documentation
The completion service emits four types of events with rich data:
interface CompletionAcceptEvent {
requestId: string;
acceptedText: string;
}
completionProvider.events.on('completion:accept', (data: CompletionAcceptEvent) => {
console.log('Accepted:', data.acceptedText);
});
interface CompletionDeclineEvent {
requestId: string;
suggestionText: string;
reason: string;
hitCount: number;
otherSuggestions: string[];
}
completionProvider.events.on('completion:decline', (data: CompletionDeclineEvent) => {
console.log('Declined:', data.suggestionText, 'reason:', data.reason);
console.log('Other suggestions:', data.otherSuggestions);
console.log('Times shown:', data.hitCount);
});
interface CompletionIgnoreEvent {
requestId: string;
suggestionText: string;
otherSuggestions: string[];
}
completionProvider.events.on('completion:ignore', (data: CompletionIgnoreEvent) => {
console.log('Ignored:', data.suggestionText);
console.log('Other suggestions:', data.otherSuggestions);
});
completionProvider.events.on('completion:error', (error: Error) => {
console.error('Completion error:', error);
});
# Install dependencies
npm install
# Start Storybook for development
npm run storybook
# Run tests
npm run test
# Run tests with coverage
npm run test:coverage
The package uses a hybrid build system:
- TypeScript (tsc) for type checking and declaration files
- esbuild for fast, optimized builds
Output Formats:
- CommonJS:
dist/cjs/index.js
- ES Modules:
dist/esm/index.js
- TypeScript Declarations:
dist/types/index.d.ts
View Build Commands
# Type checking only
npm run type-check
# Build type declarations
npm run build:types
# Build CommonJS version
npm run build:cjs
# Build ES Modules version
npm run build:esm
# Full build (all formats)
npm run build
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
View Development Guidelines
- Handle text limits appropriately
- Maintain cursor position accuracy
- Consider edge cases
- Support partial text acceptance
- Wrap API calls in try-catch blocks
- Fail gracefully on errors
- Log issues without breaking editor
- Emit error events for monitoring
- Use debouncing for API calls
- Implement efficient caching
- Track suggestion hit counts
- Clean up resources properly
- Add tests for new features
- Maintain backward compatibility
- Test edge cases
- Verify event handling
Apache-2.0 - see LICENSE file for details.