A robust TypeScript editor component built on Monaco Editor with ANTLR4 integration. Features enhanced error handling, automatic resource cleanup, and stable resizing capabilities.
- π§ Robust Error Handling: Automatically handles Monaco disposal errors without user intervention
- π Stable Resizing: Editor maintains cursor position and selection during layout changes
- π§Ή Automatic Cleanup: Prevents memory leaks with intelligent resource management
- β‘ Performance Optimized: Minimal remounts and efficient provider management
- π¨ Monaco Integration: Full Monaco Editor features with syntax highlighting and autocomplete
- π ANTLR4 Support: Built-in support for ANTLR4 grammars and tools
yarn add @making-sense/antlr-editoryarn add @making-sense/antlr-editor @making-sense/vtl-2-1-antlr-tools-ts @making-sense/vtl-2-1-monaco-tools-tsimport { AntlrEditor } from "@making-sense/antlr-editor";
import * as VTLTools from "@making-sense/vtl-2-1-antlr-tools-ts";
import { getSuggestionsFromRange, monarchDefinition } from "@making-sense/vtl-2-1-monaco-tools-ts";
const customTools = { ...VTLTools, getSuggestionsFromRange, monarchDefinition };
const MyEditor = () => {
const [script, setScript] = useState("");
return (
<AntlrEditor
script={script}
setScript={setScript}
tools={customTools}
height="400px"
width="100%"
theme="vs-dark"
shortcuts={{
"ctrl+s, meta+s": () => console.log("Save"),
"ctrl+enter, meta+enter": () => console.log("Run")
}}
displayFooter={true}
/>
);
};import { AntlrEditor, cleanupProviders } from "@making-sense/antlr-editor";
const AdvancedEditor = () => {
const [script, setScript] = useState("");
// Manual cleanup for advanced scenarios
useEffect(() => {
return () => {
cleanupProviders();
};
}, []);
return (
<AntlrEditor
script={script}
setScript={setScript}
tools={customTools}
height="100%"
width="100%"
theme="vs-dark"
options={{
lineNumbers: "on",
minimap: { enabled: true },
readOnly: false
}}
shortcuts={{
"ctrl+s, meta+s": handleSave,
"ctrl+enter, meta+enter": handleRun
}}
onListErrors={(errors) => {
console.log("Validation errors:", errors);
}}
displayFooter={true}
/>
);
};| Prop | Type | Default | Description |
|---|---|---|---|
script |
string |
'' |
The script content to display |
setScript |
(value: string) => void |
- | Callback for script changes |
tools |
Tools |
- | Required - ANTLR4 tools configuration |
height |
string |
'50vh' |
Editor height (CSS value) |
width |
string |
'100%' |
Editor width (CSS value) |
theme |
string |
'vs-dark' |
Monaco theme (vs-dark, vs-light, etc.) |
options |
Monaco.editor.IStandaloneEditorConstructionOptions |
{} |
Monaco editor options |
shortcuts |
Record<string, () => void> |
- | Keyboard shortcuts |
FooterComponent |
React.FC<{ cursor: CursorType }> |
- | Custom footer component |
displayFooter |
boolean |
true |
Whether to show footer |
onListErrors |
(errors: Error[]) => void |
- | Error callback |
variables |
Variables |
{} |
Variables for autocomplete |
variablesInputURLs |
string[] |
[] |
URLs to fetch variables from |
customFetcher |
(url: string) => Promise<any> |
fetch |
Custom fetch function |
The tools prop requires an ANTLR4 configuration object:
interface Tools {
id: string; // Language identifier
initialRule: string; // Starting rule name
grammar: string; // Grammar definition
Lexer: Antlr4Lexer; // ANTLR4 Lexer class
Parser: Antlr4Parser; // ANTLR4 Parser class
monarchDefinition?: any; // Monaco syntax highlighting
getSuggestionsFromRange?: any; // Custom suggestions
}const variables = {
"var1": { "type": "STRING", "role": "IDENTIFIER" },
"var2": { "type": "INTEGER", "role": "MEASURE" },
"var3": { "type": "NUMBER", "role": "DIMENSION" }
};const shortcuts = {
"ctrl+s, meta+s": () => handleSave(),
"ctrl+enter, meta+enter": () => handleRun(),
"ctrl+z, meta+z": () => handleUndo(),
"ctrl+y, meta+y": () => handleRedo()
};Always ensure the editor container has a defined height:
// β
Good
<div style={{ height: "400px" }}>
<AntlrEditor height="100%" />
</div>
// β Avoid
<div>
<AntlrEditor height="auto" />
</div>The editor handles Monaco disposal errors automatically, but you can add custom error handling:
const handleErrors = (errors) => {
// Handle validation errors
setValidationErrors(errors);
};
<AntlrEditor
onListErrors={handleErrors}
// ... other props
/>For large scripts or frequent updates, consider debouncing:
const [script, setScript] = useState("");
const [debouncedScript, setDebouncedScript] = useState("");
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedScript(script);
}, 300);
return () => clearTimeout(timer);
}, [script]);
<AntlrEditor
script={debouncedScript}
setScript={setScript}
// ... other props
/>Support both light and dark themes:
const { isDarkMode } = useTheme();
<AntlrEditor
theme={isDarkMode ? "vs-dark" : "vs-light"}
// ... other props
/>const customFetcher = (url) => {
return fetch(url, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
};
<AntlrEditor
customFetcher={customFetcher}
variablesInputURLs={["https://api.example.com/variables"]}
// ... other props
/>yarn storybook# Clone and setup
git clone https://github.com/Making-Sense-Info/ANTLR-Editor
cd ANTLR-Editor
yarn
# Start test app in watch mode
yarn start-test-app
# Link to external project
yarn link-in-app test-appOpen test-enhanced-editor.html in your browser to test:
- Editor resizing without remounting
- Layout changes and stability
- Error handling and recovery
- Cursor position preservation
-
"InstantiationService has been disposed" errors
- The editor handles these automatically
- If you still see them, ensure you're using the latest version
-
Editor not resizing properly
- Make sure the container has a defined height
- Check that the
heightprop is set correctly
-
Memory leaks
- The editor includes automatic cleanup
- For manual cleanup, use
cleanupProviders()
-
Cursor position lost during resize
- This is now handled automatically
- The editor maintains state during layout changes
Enable debug logging:
// In browser console
localStorage.setItem("debug", "antlr-editor:*");- Chrome 80+
- Firefox 75+
- Safari 13+
- Edge 80+
Same as the main ANTLR Editor package.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
Check out the Storybook stories for comprehensive examples:
- Basic editor setup
- Resizing and layout tests
- Error handling scenarios
- Custom theming and styling