Sign in to your developer account
Publish extensions, see downloads, and manage everything from one place.
Your session is remembered on this device — next time you go straight in.
Your extensions
No extensions yet
Publish your first extension — it appears in the editor, ready to install.
How to build an extension
An extension is a small folder of code that runs inside Empire Code Editor and talks to it through the nova API. This guide walks through everything — the files, the API, full examples, packaging and publishing.
1. Folder structure
An extension is a folder. The only required file is extension.js — the code that runs. You can add a manifest and other files next to it.
my-extension/
extension.js ← required: the code
nova-extension.json ← optional: name, version, contributions
themes/
my-theme.json ← optional: files your code imports
You do not have to write the manifest yourself — the Dev Area fills in the name, description and icon for you. Add a manifest only when you want to declare contributions (like a theme) without code.
2. Your first extension
extension.js exports an activate function. The editor calls it with the nova API when the extension is turned on, and deactivate when it is turned off. Both CommonJS and ES-module syntax work.
CommonJS:
module.exports = {
activate(nova) {
nova.commands.register('hello.world', 'Hello: Say Hi', () => {
nova.window.showMessage('Hello from my extension!');
});
},
deactivate() {},
};
ES module (same thing):
export function activate(nova) {
nova.commands.register('hello.world', 'Hello: Say Hi', () => {
nova.window.showMessage('Hello from my extension!');
});
}
export function deactivate() {}
Anything the extension registers through nova is undone automatically when it is disabled.
3. The nova API
Everything your extension can do is on the nova object passed to activate.
Commands
nova.commands.register(id, title, fn) // adds a command (Ctrl+Shift+P) nova.commands.execute(id, ...args) // runs another command
Status bar
const item = nova.statusBar.add({ text: 'Ready', tooltip: 'My item', command: 'hello.world' });
item.setText('Busy…'); item.show(true); item.dispose();
Editor
nova.editor.getText() // whole file nova.editor.getSelectionText() // current selection nova.editor.getLanguage() // 'lua', 'python', … nova.editor.getFile() // path of the active file nova.editor.insertText(text) // insert at the cursor nova.editor.replaceAll(text) // replace the whole file nova.editor.onDidChangeContent(fn) nova.editor.onDidChangeCursor(fn) nova.editor.onDidSave(fn)
Languages
nova.languages.registerCompletions('lua', [{ label: 'print', insertText: 'print($1)' }]);
nova.languages.registerSnippets('lua', { 'for loop': 'for i=1,10 do\\n\\t$0\\nend' });
nova.languages.registerFormatter('lua', (text) => text.trimEnd());
nova.languages.registerLinter('lua', (text) => [{ line: 1, col: 1, endCol: 5, message: 'Example', severity: 'warning' }]);
Window & output
nova.window.showMessage(msg, 'info' | 'warning' | 'error');
await nova.window.showInput('Your name?');
await nova.window.showQuickPick(['One', 'Two']);
nova.output.show('My Channel', 'some logs');
Theme & settings
nova.theme.set('nova-light'); // switch to a built-in theme
nova.theme.toggle(true); // true = light, false = dark, nothing = flip
nova.theme.register(themeObject, { apply: true }); // add & apply your own theme
nova.theme.list(); // [{ id, label }]
nova.settings.get('fontSize');
nova.settings.update({ fontSize: 15 });
Git, AI & Discord
await nova.git.blame(file, line);
await nova.git.diff();
await nova.ai.complete('Explain this code', 'You are helpful');
nova.discord.setActivity(clientId, { details: 'Coding', state: 'in my project' });
4. Full examples
A light theme
Create themes/my-light.json (the editor's theme format), import it, and apply it. import of a JSON file works.
// extension.js
import theme from './themes/my-light.json';
export function activate(nova) {
nova.theme.register(theme, { apply: true });
}
export function deactivate() {}
// themes/my-light.json
{
"id": "my-light",
"label": "My Light",
"type": "light",
"ui": {
"--bg": "#f3f4f8", "--bg-sidebar": "#f3f4f8", "--bg-panel": "#ffffff",
"--fg": "#2a2f3a", "--fg-muted": "#6a7383", "--border": "#dcdfe7", "--accent": "#2f6bff"
},
"editor": {
"base": "vs",
"inherit": true,
"rules": [
{ "token": "comment", "foreground": "8a93a6", "fontStyle": "italic" },
{ "token": "keyword", "foreground": "2453c9" },
{ "token": "string", "foreground": "1f7a4d" }
],
"colors": { "editor.background": "#ffffff", "editor.foreground": "#2a2f3a" }
}
}
A VS Code theme (with colors and tokenColors) also works — the editor converts it automatically.
A trailing-whitespace cleaner
module.exports = {
activate(nova) {
nova.commands.register('clean.trim', 'Clean: Trim trailing spaces', () => {
nova.editor.replaceAll(nova.editor.getText().replace(/[ \\t]+$/gm, ''));
nova.window.showMessage('Trimmed trailing whitespace.');
});
},
deactivate() {},
};
5. Package & publish
- Put
extension.js(and any files it needs) in a folder. - Zip the folder.
extension.jscan be at the root or inside one wrapping folder — both work. - Back in your extensions, click New extension, fill in the name, description and icon, and upload the .zip.
- It appears in the editor under Extensions as not installed — click Install there to turn it on.
- Need a change? Click Edit code on the card to open
extension.jsin the editor, or upload a new .zip from Edit.