diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/ast_inspector.ts
similarity index 67%
rename from editors/code/src/commands/syntax_tree.ts
rename to editors/code/src/ast_inspector.ts
index a5446c32724..4fdd167bd5f 100644
--- a/editors/code/src/commands/syntax_tree.ts
+++ b/editors/code/src/ast_inspector.ts
@@ -1,93 +1,15 @@
 import * as vscode from 'vscode';
-import * as ra from '../rust-analyzer-api';
-
-import { Ctx, Cmd, Disposable } from '../ctx';
-import { isRustDocument, RustEditor, isRustEditor, sleep } from '../util';
-
-const AST_FILE_SCHEME = "rust-analyzer";
-
-// Opens the virtual file that will show the syntax tree
-//
-// The contents of the file come from the `TextDocumentContentProvider`
-export function syntaxTree(ctx: Ctx): Cmd {
-    const tdcp = new TextDocumentContentProvider(ctx);
-
-    void new AstInspector(ctx);
-
-    ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider(AST_FILE_SCHEME, tdcp));
-    ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
-        brackets: [["[", ")"]],
-    }));
-
-    return async () => {
-        const editor = vscode.window.activeTextEditor;
-        const rangeEnabled = !!editor && !editor.selection.isEmpty;
-
-        const uri = rangeEnabled
-            ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`)
-            : tdcp.uri;
-
-        const document = await vscode.workspace.openTextDocument(uri);
-
-        tdcp.eventEmitter.fire(uri);
-
-        void await vscode.window.showTextDocument(document, {
-            viewColumn: vscode.ViewColumn.Two,
-            preserveFocus: true
-        });
-    };
-}
-
-class TextDocumentContentProvider implements vscode.TextDocumentContentProvider {
-    readonly uri = vscode.Uri.parse('rust-analyzer://syntaxtree/tree.rast');
-    readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
-
-
-    constructor(private readonly ctx: Ctx) {
-        vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
-        vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions);
-    }
-
-    private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
-        if (isRustDocument(event.document)) {
-            // We need to order this after language server updates, but there's no API for that.
-            // Hence, good old sleep().
-            void sleep(10).then(() => this.eventEmitter.fire(this.uri));
-        }
-    }
-    private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
-        if (editor && isRustEditor(editor)) {
-            this.eventEmitter.fire(this.uri);
-        }
-    }
-
-    provideTextDocumentContent(uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> {
-        const rustEditor = this.ctx.activeRustEditor;
-        if (!rustEditor) return '';
-
-        // When the range based query is enabled we take the range of the selection
-        const range = uri.query === 'range=true' && !rustEditor.selection.isEmpty
-            ? this.ctx.client.code2ProtocolConverter.asRange(rustEditor.selection)
-            : null;
-
-        const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range, };
-        return this.ctx.client.sendRequest(ra.syntaxTree, params, ct);
-    }
-
-    get onDidChange(): vscode.Event<vscode.Uri> {
-        return this.eventEmitter.event;
-    }
-}
 
+import { Ctx, Disposable } from './ctx';
+import { RustEditor, isRustEditor } from './util';
 
 // FIXME: consider implementing this via the Tree View API?
 // https://code.visualstudio.com/api/extension-guides/tree-view
-class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable {
+export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable {
     private readonly astDecorationType = vscode.window.createTextEditorDecorationType({
         borderColor: new vscode.ThemeColor('rust_analyzer.syntaxTreeBorder'),
         borderStyle: "solid",
         borderWidth: "2px",
-
     });
     private rustEditor: undefined | RustEditor;
 
@@ -113,7 +35,7 @@ class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, D
     });
 
     constructor(ctx: Ctx) {
-        ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: AST_FILE_SCHEME }, this));
+        ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: 'rust-analyzer' }, this));
         ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
         vscode.workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, ctx.subscriptions);
         vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
@@ -146,7 +68,7 @@ class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, D
     }
 
     private findAstTextEditor(): undefined | vscode.TextEditor {
-        return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === AST_FILE_SCHEME);
+        return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === 'rust-analyzer');
     }
 
     private setRustEditor(newRustEditor: undefined | RustEditor) {
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
new file mode 100644
index 00000000000..573af5aa580
--- /dev/null
+++ b/editors/code/src/commands.ts
@@ -0,0 +1,370 @@
+import * as vscode from 'vscode';
+import * as lc from 'vscode-languageclient';
+import * as ra from './rust-analyzer-api';
+
+import { Ctx, Cmd } from './ctx';
+import { applySnippetWorkspaceEdit } from './snippets';
+import { spawnSync } from 'child_process';
+import { RunnableQuickPick, selectRunnable, createTask } from './run';
+import { AstInspector } from './ast_inspector';
+import { isRustDocument, sleep, isRustEditor } from './util';
+
+export * from './ast_inspector';
+export * from './run';
+
+export function analyzerStatus(ctx: Ctx): Cmd {
+    const tdcp = new class implements vscode.TextDocumentContentProvider {
+        readonly uri = vscode.Uri.parse('rust-analyzer-status://status');
+        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+
+        provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
+            if (!vscode.window.activeTextEditor) return '';
+
+            return ctx.client.sendRequest(ra.analyzerStatus, null);
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    }();
+
+    let poller: NodeJS.Timer | undefined = undefined;
+
+    ctx.pushCleanup(
+        vscode.workspace.registerTextDocumentContentProvider(
+            'rust-analyzer-status',
+            tdcp,
+        ),
+    );
+
+    ctx.pushCleanup({
+        dispose() {
+            if (poller !== undefined) {
+                clearInterval(poller);
+            }
+        },
+    });
+
+    return async () => {
+        if (poller === undefined) {
+            poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000);
+        }
+        const document = await vscode.workspace.openTextDocument(tdcp.uri);
+        return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
+    };
+}
+
+export function matchingBrace(ctx: Ctx): Cmd {
+    return async () => {
+        const editor = ctx.activeRustEditor;
+        const client = ctx.client;
+        if (!editor || !client) return;
+
+        const response = await client.sendRequest(ra.matchingBrace, {
+            textDocument: { uri: editor.document.uri.toString() },
+            positions: editor.selections.map(s =>
+                client.code2ProtocolConverter.asPosition(s.active),
+            ),
+        });
+        editor.selections = editor.selections.map((sel, idx) => {
+            const active = client.protocol2CodeConverter.asPosition(
+                response[idx],
+            );
+            const anchor = sel.isEmpty ? active : sel.anchor;
+            return new vscode.Selection(anchor, active);
+        });
+        editor.revealRange(editor.selection);
+    };
+}
+
+export function joinLines(ctx: Ctx): Cmd {
+    return async () => {
+        const editor = ctx.activeRustEditor;
+        const client = ctx.client;
+        if (!editor || !client) return;
+
+        const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
+            ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
+            textDocument: { uri: editor.document.uri.toString() },
+        });
+        editor.edit((builder) => {
+            client.protocol2CodeConverter.asTextEdits(items).forEach((edit) => {
+                builder.replace(edit.range, edit.newText);
+            });
+        });
+    };
+}
+
+export function onEnter(ctx: Ctx): Cmd {
+    async function handleKeypress() {
+        const editor = ctx.activeRustEditor;
+        const client = ctx.client;
+
+        if (!editor || !client) return false;
+
+        const change = await client.sendRequest(ra.onEnter, {
+            textDocument: { uri: editor.document.uri.toString() },
+            position: client.code2ProtocolConverter.asPosition(
+                editor.selection.active,
+            ),
+        }).catch(_error => {
+            // client.logFailedRequest(OnEnterRequest.type, error);
+            return null;
+        });
+        if (!change) return false;
+
+        const workspaceEdit = client.protocol2CodeConverter.asWorkspaceEdit(change);
+        await applySnippetWorkspaceEdit(workspaceEdit);
+        return true;
+    }
+
+    return async () => {
+        if (await handleKeypress()) return;
+
+        await vscode.commands.executeCommand('default:type', { text: '\n' });
+    };
+}
+
+export function parentModule(ctx: Ctx): Cmd {
+    return async () => {
+        const editor = ctx.activeRustEditor;
+        const client = ctx.client;
+        if (!editor || !client) return;
+
+        const response = await client.sendRequest(ra.parentModule, {
+            textDocument: { uri: editor.document.uri.toString() },
+            position: client.code2ProtocolConverter.asPosition(
+                editor.selection.active,
+            ),
+        });
+        const loc = response[0];
+        if (loc == null) return;
+
+        const uri = client.protocol2CodeConverter.asUri(loc.uri);
+        const range = client.protocol2CodeConverter.asRange(loc.range);
+
+        const doc = await vscode.workspace.openTextDocument(uri);
+        const e = await vscode.window.showTextDocument(doc);
+        e.selection = new vscode.Selection(range.start, range.start);
+        e.revealRange(range, vscode.TextEditorRevealType.InCenter);
+    };
+}
+
+export function ssr(ctx: Ctx): Cmd {
+    return async () => {
+        const client = ctx.client;
+        if (!client) return;
+
+        const options: vscode.InputBoxOptions = {
+            value: "() ==>> ()",
+            prompt: "Enter request, for example 'Foo($a:expr) ==> Foo::new($a)' ",
+            validateInput: async (x: string) => {
+                try {
+                    await client.sendRequest(ra.ssr, { query: x, parseOnly: true });
+                } catch (e) {
+                    return e.toString();
+                }
+                return null;
+            }
+        };
+        const request = await vscode.window.showInputBox(options);
+        if (!request) return;
+
+        const edit = await client.sendRequest(ra.ssr, { query: request, parseOnly: false });
+
+        await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit));
+    };
+}
+
+export function serverVersion(ctx: Ctx): Cmd {
+    return async () => {
+        const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
+        const commitHash = stdout.slice(`rust-analyzer `.length).trim();
+        const { releaseTag } = ctx.config.package;
+
+        void vscode.window.showInformationMessage(
+            `rust-analyzer version: ${releaseTag ?? "unreleased"} (${commitHash})`
+        );
+    };
+}
+
+export function toggleInlayHints(ctx: Ctx): Cmd {
+    return async () => {
+        await vscode
+            .workspace
+            .getConfiguration(`${ctx.config.rootSection}.inlayHints`)
+            .update('enable', !ctx.config.inlayHints.enable, vscode.ConfigurationTarget.Workspace);
+    };
+}
+
+export function run(ctx: Ctx): Cmd {
+    let prevRunnable: RunnableQuickPick | undefined;
+
+    return async () => {
+        const item = await selectRunnable(ctx, prevRunnable);
+        if (!item) return;
+
+        item.detail = 'rerun';
+        prevRunnable = item;
+        const task = createTask(item.runnable);
+        return await vscode.tasks.executeTask(task);
+    };
+}
+
+// Opens the virtual file that will show the syntax tree
+//
+// The contents of the file come from the `TextDocumentContentProvider`
+export function syntaxTree(ctx: Ctx): Cmd {
+    const tdcp = new class implements vscode.TextDocumentContentProvider {
+        readonly uri = vscode.Uri.parse('rust-analyzer://syntaxtree/tree.rast');
+        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+        constructor() {
+            vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
+            vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions);
+        }
+
+        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
+            if (isRustDocument(event.document)) {
+                // We need to order this after language server updates, but there's no API for that.
+                // Hence, good old sleep().
+                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
+            }
+        }
+        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
+            if (editor && isRustEditor(editor)) {
+                this.eventEmitter.fire(this.uri);
+            }
+        }
+
+        provideTextDocumentContent(uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> {
+            const rustEditor = ctx.activeRustEditor;
+            if (!rustEditor) return '';
+
+            // When the range based query is enabled we take the range of the selection
+            const range = uri.query === 'range=true' && !rustEditor.selection.isEmpty
+                ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection)
+                : null;
+
+            const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range, };
+            return ctx.client.sendRequest(ra.syntaxTree, params, ct);
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    };
+
+    void new AstInspector(ctx);
+
+    ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp));
+    ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
+        brackets: [["[", ")"]],
+    }));
+
+    return async () => {
+        const editor = vscode.window.activeTextEditor;
+        const rangeEnabled = !!editor && !editor.selection.isEmpty;
+
+        const uri = rangeEnabled
+            ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`)
+            : tdcp.uri;
+
+        const document = await vscode.workspace.openTextDocument(uri);
+
+        tdcp.eventEmitter.fire(uri);
+
+        void await vscode.window.showTextDocument(document, {
+            viewColumn: vscode.ViewColumn.Two,
+            preserveFocus: true
+        });
+    };
+}
+
+
+// Opens the virtual file that will show the syntax tree
+//
+// The contents of the file come from the `TextDocumentContentProvider`
+export function expandMacro(ctx: Ctx): Cmd {
+    function codeFormat(expanded: ra.ExpandedMacro): string {
+        let result = `// Recursive expansion of ${expanded.name}! macro\n`;
+        result += '// ' + '='.repeat(result.length - 3);
+        result += '\n\n';
+        result += expanded.expansion;
+
+        return result;
+    }
+
+    const tdcp = new class implements vscode.TextDocumentContentProvider {
+        uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs');
+        eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+        async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
+            const editor = vscode.window.activeTextEditor;
+            const client = ctx.client;
+            if (!editor || !client) return '';
+
+            const position = editor.selection.active;
+
+            const expanded = await client.sendRequest(ra.expandMacro, {
+                textDocument: { uri: editor.document.uri.toString() },
+                position,
+            });
+
+            if (expanded == null) return 'Not available';
+
+            return codeFormat(expanded);
+        }
+
+        get onDidChange(): vscode.Event<vscode.Uri> {
+            return this.eventEmitter.event;
+        }
+    }();
+
+    ctx.pushCleanup(
+        vscode.workspace.registerTextDocumentContentProvider(
+            'rust-analyzer',
+            tdcp,
+        ),
+    );
+
+    return async () => {
+        const document = await vscode.workspace.openTextDocument(tdcp.uri);
+        tdcp.eventEmitter.fire(tdcp.uri);
+        return vscode.window.showTextDocument(
+            document,
+            vscode.ViewColumn.Two,
+            true,
+        );
+    };
+}
+
+export function collectGarbage(ctx: Ctx): Cmd {
+    return async () => ctx.client.sendRequest(ra.collectGarbage, null);
+}
+
+export function showReferences(ctx: Ctx): Cmd {
+    return (uri: string, position: lc.Position, locations: lc.Location[]) => {
+        const client = ctx.client;
+        if (client) {
+            vscode.commands.executeCommand(
+                'editor.action.showReferences',
+                vscode.Uri.parse(uri),
+                client.protocol2CodeConverter.asPosition(position),
+                locations.map(client.protocol2CodeConverter.asLocation),
+            );
+        }
+    };
+}
+
+export function applyActionGroup(_ctx: Ctx): Cmd {
+    return async (actions: { label: string; edit: vscode.WorkspaceEdit }[]) => {
+        const selectedAction = await vscode.window.showQuickPick(actions);
+        if (!selectedAction) return;
+        await applySnippetWorkspaceEdit(selectedAction.edit);
+    };
+}
+
+export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd {
+    return async (edit: vscode.WorkspaceEdit) => {
+        await applySnippetWorkspaceEdit(edit);
+    };
+}
diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts
deleted file mode 100644
index 09daa3402cf..00000000000
--- a/editors/code/src/commands/analyzer_status.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import * as vscode from 'vscode';
-
-import * as ra from '../rust-analyzer-api';
-import { Ctx, Cmd } from '../ctx';
-
-// Shows status of rust-analyzer (for debugging)
-export function analyzerStatus(ctx: Ctx): Cmd {
-    let poller: NodeJS.Timer | undefined = undefined;
-    const tdcp = new TextDocumentContentProvider(ctx);
-
-    ctx.pushCleanup(
-        vscode.workspace.registerTextDocumentContentProvider(
-            'rust-analyzer-status',
-            tdcp,
-        ),
-    );
-
-    ctx.pushCleanup({
-        dispose() {
-            if (poller !== undefined) {
-                clearInterval(poller);
-            }
-        },
-    });
-
-    return async () => {
-        if (poller === undefined) {
-            poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000);
-        }
-        const document = await vscode.workspace.openTextDocument(tdcp.uri);
-        return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
-    };
-}
-
-class TextDocumentContentProvider implements vscode.TextDocumentContentProvider {
-    readonly uri = vscode.Uri.parse('rust-analyzer-status://status');
-    readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
-
-    constructor(private readonly ctx: Ctx) {
-    }
-
-    provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
-        if (!vscode.window.activeTextEditor) return '';
-
-        return this.ctx.client.sendRequest(ra.analyzerStatus, null);
-    }
-
-    get onDidChange(): vscode.Event<vscode.Uri> {
-        return this.eventEmitter.event;
-    }
-}
diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts
deleted file mode 100644
index 23f2ef1d5e3..00000000000
--- a/editors/code/src/commands/expand_macro.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import * as vscode from 'vscode';
-import * as ra from '../rust-analyzer-api';
-
-import { Ctx, Cmd } from '../ctx';
-
-// Opens the virtual file that will show the syntax tree
-//
-// The contents of the file come from the `TextDocumentContentProvider`
-export function expandMacro(ctx: Ctx): Cmd {
-    const tdcp = new TextDocumentContentProvider(ctx);
-    ctx.pushCleanup(
-        vscode.workspace.registerTextDocumentContentProvider(
-            'rust-analyzer',
-            tdcp,
-        ),
-    );
-
-    return async () => {
-        const document = await vscode.workspace.openTextDocument(tdcp.uri);
-        tdcp.eventEmitter.fire(tdcp.uri);
-        return vscode.window.showTextDocument(
-            document,
-            vscode.ViewColumn.Two,
-            true,
-        );
-    };
-}
-
-function codeFormat(expanded: ra.ExpandedMacro): string {
-    let result = `// Recursive expansion of ${expanded.name}! macro\n`;
-    result += '// ' + '='.repeat(result.length - 3);
-    result += '\n\n';
-    result += expanded.expansion;
-
-    return result;
-}
-
-class TextDocumentContentProvider
-    implements vscode.TextDocumentContentProvider {
-    uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs');
-    eventEmitter = new vscode.EventEmitter<vscode.Uri>();
-
-    constructor(private readonly ctx: Ctx) {
-    }
-
-    async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
-        const editor = vscode.window.activeTextEditor;
-        const client = this.ctx.client;
-        if (!editor || !client) return '';
-
-        const position = editor.selection.active;
-
-        const expanded = await client.sendRequest(ra.expandMacro, {
-            textDocument: { uri: editor.document.uri.toString() },
-            position,
-        });
-
-        if (expanded == null) return 'Not available';
-
-        return codeFormat(expanded);
-    }
-
-    get onDidChange(): vscode.Event<vscode.Uri> {
-        return this.eventEmitter.event;
-    }
-}
diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts
deleted file mode 100644
index 0bf1ee6e671..00000000000
--- a/editors/code/src/commands/join_lines.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import * as ra from '../rust-analyzer-api';
-import * as lc from 'vscode-languageclient';
-
-import { Ctx, Cmd } from '../ctx';
-
-export function joinLines(ctx: Ctx): Cmd {
-    return async () => {
-        const editor = ctx.activeRustEditor;
-        const client = ctx.client;
-        if (!editor || !client) return;
-
-        const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
-            ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
-            textDocument: { uri: editor.document.uri.toString() },
-        });
-        editor.edit((builder) => {
-            client.protocol2CodeConverter.asTextEdits(items).forEach((edit) => {
-                builder.replace(edit.range, edit.newText);
-            });
-        });
-    };
-}
diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts
deleted file mode 100644
index 9c418b887c2..00000000000
--- a/editors/code/src/commands/matching_brace.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as vscode from 'vscode';
-import * as ra from '../rust-analyzer-api';
-
-import { Ctx, Cmd } from '../ctx';
-
-export function matchingBrace(ctx: Ctx): Cmd {
-    return async () => {
-        const editor = ctx.activeRustEditor;
-        const client = ctx.client;
-        if (!editor || !client) return;
-
-        const response = await client.sendRequest(ra.matchingBrace, {
-            textDocument: { uri: editor.document.uri.toString() },
-            positions: editor.selections.map(s =>
-                client.code2ProtocolConverter.asPosition(s.active),
-            ),
-        });
-        editor.selections = editor.selections.map((sel, idx) => {
-            const active = client.protocol2CodeConverter.asPosition(
-                response[idx],
-            );
-            const anchor = sel.isEmpty ? active : sel.anchor;
-            return new vscode.Selection(anchor, active);
-        });
-        editor.revealRange(editor.selection);
-    };
-}
diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts
deleted file mode 100644
index a7871c31eed..00000000000
--- a/editors/code/src/commands/on_enter.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import * as vscode from 'vscode';
-import * as ra from '../rust-analyzer-api';
-
-import { Cmd, Ctx } from '../ctx';
-import { applySnippetWorkspaceEdit } from '.';
-
-async function handleKeypress(ctx: Ctx) {
-    const editor = ctx.activeRustEditor;
-    const client = ctx.client;
-
-    if (!editor || !client) return false;
-
-    const change = await client.sendRequest(ra.onEnter, {
-        textDocument: { uri: editor.document.uri.toString() },
-        position: client.code2ProtocolConverter.asPosition(
-            editor.selection.active,
-        ),
-    }).catch(_error => {
-        // client.logFailedRequest(OnEnterRequest.type, error);
-        return null;
-    });
-    if (!change) return false;
-
-    const workspaceEdit = client.protocol2CodeConverter.asWorkspaceEdit(change);
-    await applySnippetWorkspaceEdit(workspaceEdit);
-    return true;
-}
-
-export function onEnter(ctx: Ctx): Cmd {
-    return async () => {
-        if (await handleKeypress(ctx)) return;
-
-        await vscode.commands.executeCommand('default:type', { text: '\n' });
-    };
-}
diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts
deleted file mode 100644
index 8f78ddd71c6..00000000000
--- a/editors/code/src/commands/parent_module.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import * as vscode from 'vscode';
-import * as ra from '../rust-analyzer-api';
-
-import { Ctx, Cmd } from '../ctx';
-
-export function parentModule(ctx: Ctx): Cmd {
-    return async () => {
-        const editor = ctx.activeRustEditor;
-        const client = ctx.client;
-        if (!editor || !client) return;
-
-        const response = await client.sendRequest(ra.parentModule, {
-            textDocument: { uri: editor.document.uri.toString() },
-            position: client.code2ProtocolConverter.asPosition(
-                editor.selection.active,
-            ),
-        });
-        const loc = response[0];
-        if (loc == null) return;
-
-        const uri = client.protocol2CodeConverter.asUri(loc.uri);
-        const range = client.protocol2CodeConverter.asRange(loc.range);
-
-        const doc = await vscode.workspace.openTextDocument(uri);
-        const e = await vscode.window.showTextDocument(doc);
-        e.selection = new vscode.Selection(range.start, range.start);
-        e.revealRange(range, vscode.TextEditorRevealType.InCenter);
-    };
-}
diff --git a/editors/code/src/commands/server_version.ts b/editors/code/src/commands/server_version.ts
deleted file mode 100644
index d64ac726e2c..00000000000
--- a/editors/code/src/commands/server_version.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import * as vscode from "vscode";
-import { spawnSync } from "child_process";
-import { Ctx, Cmd } from '../ctx';
-
-export function serverVersion(ctx: Ctx): Cmd {
-    return async () => {
-        const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
-        const commitHash = stdout.slice(`rust-analyzer `.length).trim();
-        const { releaseTag } = ctx.config.package;
-
-        void vscode.window.showInformationMessage(
-            `rust-analyzer version: ${releaseTag ?? "unreleased"} (${commitHash})`
-        );
-    };
-}
diff --git a/editors/code/src/commands/ssr.ts b/editors/code/src/commands/ssr.ts
deleted file mode 100644
index 5d40a64d28e..00000000000
--- a/editors/code/src/commands/ssr.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import * as vscode from 'vscode';
-import * as ra from "../rust-analyzer-api";
-
-import { Ctx, Cmd } from '../ctx';
-
-export function ssr(ctx: Ctx): Cmd {
-    return async () => {
-        const client = ctx.client;
-        if (!client) return;
-
-        const options: vscode.InputBoxOptions = {
-            value: "() ==>> ()",
-            prompt: "Enter request, for example 'Foo($a:expr) ==> Foo::new($a)' ",
-            validateInput: async (x: string) => {
-                try {
-                    await client.sendRequest(ra.ssr, { query: x, parseOnly: true });
-                } catch (e) {
-                    return e.toString();
-                }
-                return null;
-            }
-        };
-        const request = await vscode.window.showInputBox(options);
-        if (!request) return;
-
-        const edit = await client.sendRequest(ra.ssr, { query: request, parseOnly: false });
-
-        await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit));
-    };
-}
diff --git a/editors/code/src/commands/toggle_inlay_hints.ts b/editors/code/src/commands/toggle_inlay_hints.ts
deleted file mode 100644
index 7606af8d0cb..00000000000
--- a/editors/code/src/commands/toggle_inlay_hints.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import * as vscode from 'vscode';
-import { Ctx, Cmd } from '../ctx';
-
-export function toggleInlayHints(ctx: Ctx): Cmd {
-    return async () => {
-        await vscode
-            .workspace
-            .getConfiguration(`${ctx.config.rootSection}.inlayHints`)
-            .update('enable', !ctx.config.inlayHints.enable, vscode.ConfigurationTarget.Workspace);
-    };
-}
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 0e5a206410e..31ac81ee88d 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -92,7 +92,6 @@ export async function activate(context: vscode.ExtensionContext) {
     ctx.registerCommand('runSingle', commands.runSingle);
     ctx.registerCommand('debugSingle', commands.debugSingle);
     ctx.registerCommand('showReferences', commands.showReferences);
-    ctx.registerCommand('applySourceChange', commands.applySourceChange);
     ctx.registerCommand('applySnippetWorkspaceEdit', commands.applySnippetWorkspaceEditCommand);
     ctx.registerCommand('applyActionGroup', commands.applyActionGroup);
 
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/run.ts
similarity index 88%
rename from editors/code/src/commands/runnables.ts
rename to editors/code/src/run.ts
index 0bd30fb077d..8f0487d74a1 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/run.ts
@@ -1,13 +1,13 @@
 import * as vscode from 'vscode';
 import * as lc from 'vscode-languageclient';
-import * as ra from '../rust-analyzer-api';
+import * as ra from './rust-analyzer-api';
 
-import { Ctx, Cmd } from '../ctx';
-import { startDebugSession, getDebugConfiguration } from '../debug';
+import { Ctx, Cmd } from './ctx';
+import { startDebugSession, getDebugConfiguration } from './debug';
 
 const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }];
 
-async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
+export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
     const editor = ctx.activeRustEditor;
     const client = ctx.client;
     if (!editor || !client) return;
@@ -83,20 +83,6 @@ async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debugg
     });
 }
 
-export function run(ctx: Ctx): Cmd {
-    let prevRunnable: RunnableQuickPick | undefined;
-
-    return async () => {
-        const item = await selectRunnable(ctx, prevRunnable);
-        if (!item) return;
-
-        item.detail = 'rerun';
-        prevRunnable = item;
-        const task = createTask(item.runnable);
-        return await vscode.tasks.executeTask(task);
-    };
-}
-
 export function runSingle(ctx: Ctx): Cmd {
     return async (runnable: ra.Runnable) => {
         const editor = ctx.activeRustEditor;
@@ -165,7 +151,7 @@ export function newDebugConfig(ctx: Ctx): Cmd {
     };
 }
 
-class RunnableQuickPick implements vscode.QuickPickItem {
+export class RunnableQuickPick implements vscode.QuickPickItem {
     public label: string;
     public description?: string | undefined;
     public detail?: string | undefined;
@@ -184,7 +170,7 @@ interface CargoTaskDefinition extends vscode.TaskDefinition {
     env?: { [key: string]: string };
 }
 
-function createTask(spec: ra.Runnable): vscode.Task {
+export function createTask(spec: ra.Runnable): vscode.Task {
     const TASK_SOURCE = 'Rust';
     const definition: CargoTaskDefinition = {
         type: 'cargo',
diff --git a/editors/code/src/commands/index.ts b/editors/code/src/snippets.ts
similarity index 53%
rename from editors/code/src/commands/index.ts
rename to editors/code/src/snippets.ts
index c2a232d5fd8..794530162dc 100644
--- a/editors/code/src/commands/index.ts
+++ b/editors/code/src/snippets.ts
@@ -1,60 +1,6 @@
 import * as vscode from 'vscode';
-import * as lc from 'vscode-languageclient';
-import * as ra from '../rust-analyzer-api';
 
-import { Ctx, Cmd } from '../ctx';
-import * as sourceChange from '../source_change';
-import { assert } from '../util';
-
-export * from './analyzer_status';
-export * from './matching_brace';
-export * from './join_lines';
-export * from './on_enter';
-export * from './parent_module';
-export * from './syntax_tree';
-export * from './expand_macro';
-export * from './runnables';
-export * from './ssr';
-export * from './server_version';
-export * from './toggle_inlay_hints';
-
-export function collectGarbage(ctx: Ctx): Cmd {
-    return async () => ctx.client.sendRequest(ra.collectGarbage, null);
-}
-
-export function showReferences(ctx: Ctx): Cmd {
-    return (uri: string, position: lc.Position, locations: lc.Location[]) => {
-        const client = ctx.client;
-        if (client) {
-            vscode.commands.executeCommand(
-                'editor.action.showReferences',
-                vscode.Uri.parse(uri),
-                client.protocol2CodeConverter.asPosition(position),
-                locations.map(client.protocol2CodeConverter.asLocation),
-            );
-        }
-    };
-}
-
-export function applySourceChange(ctx: Ctx): Cmd {
-    return async (change: ra.SourceChange) => {
-        await sourceChange.applySourceChange(ctx, change);
-    };
-}
-
-export function applyActionGroup(_ctx: Ctx): Cmd {
-    return async (actions: { label: string; edit: vscode.WorkspaceEdit }[]) => {
-        const selectedAction = await vscode.window.showQuickPick(actions);
-        if (!selectedAction) return;
-        await applySnippetWorkspaceEdit(selectedAction.edit);
-    };
-}
-
-export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd {
-    return async (edit: vscode.WorkspaceEdit) => {
-        await applySnippetWorkspaceEdit(edit);
-    };
-}
+import { assert } from './util';
 
 export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
     assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`);
diff --git a/editors/code/src/source_change.ts b/editors/code/src/source_change.ts
deleted file mode 100644
index af8f1df5112..00000000000
--- a/editors/code/src/source_change.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import * as vscode from 'vscode';
-import * as lc from 'vscode-languageclient';
-import * as ra from './rust-analyzer-api';
-
-import { Ctx } from './ctx';
-
-export async function applySourceChange(ctx: Ctx, change: ra.SourceChange) {
-    const client = ctx.client;
-    if (!client) return;
-
-    const wsEdit = client.protocol2CodeConverter.asWorkspaceEdit(
-        change.workspaceEdit,
-    );
-    let created;
-    let moved;
-    if (change.workspaceEdit.documentChanges) {
-        for (const docChange of change.workspaceEdit.documentChanges) {
-            if (lc.CreateFile.is(docChange)) {
-                created = docChange.uri;
-            } else if (lc.RenameFile.is(docChange)) {
-                moved = docChange.newUri;
-            }
-        }
-    }
-    const toOpen = created || moved;
-    const toReveal = change.cursorPosition;
-    await vscode.workspace.applyEdit(wsEdit);
-    if (toOpen) {
-        const toOpenUri = vscode.Uri.parse(toOpen);
-        const doc = await vscode.workspace.openTextDocument(toOpenUri);
-        await vscode.window.showTextDocument(doc);
-    } else if (toReveal) {
-        const uri = client.protocol2CodeConverter.asUri(
-            toReveal.textDocument.uri,
-        );
-        const position = client.protocol2CodeConverter.asPosition(
-            toReveal.position,
-        );
-        const editor = vscode.window.activeTextEditor;
-        if (!editor || !editor.selection.isEmpty) {
-            return;
-        }
-
-        if (editor.document.uri !== uri) {
-            const doc = await vscode.workspace.openTextDocument(uri);
-            await vscode.window.showTextDocument(doc);
-        }
-        editor.selection = new vscode.Selection(position, position);
-        editor.revealRange(
-            new vscode.Range(position, position),
-            vscode.TextEditorRevealType.Default,
-        );
-    }
-}