Wire up GUI: functional editor with VSCode Dark theme and docking layout

Rewrote main.cpp from Step 12 scaffold to full editor shell. Added tree-sitter
linking to whetstone_editor target. Fixed WMOD_ prefix to avoid Windows SDK
MOD_SHIFT/MOD_ALT macro conflicts. Editor now has editable text area, live AST
view, syntax-highlighted preview, generated code tab, find/replace, keybinding
profile selector, and status bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bill
2026-02-08 16:21:22 -07:00
parent 5190e12b89
commit 16cc60b36c
6 changed files with 863 additions and 593 deletions

View File

@@ -12,11 +12,11 @@
// Modifier flags (bitmask)
enum KeyMod : int {
MOD_NONE = 0,
MOD_CTRL = 1 << 0,
MOD_SHIFT = 1 << 1,
MOD_ALT = 1 << 2,
MOD_SUPER = 1 << 3 // Cmd on Mac, Win on Windows
WMOD_NONE = 0,
WMOD_CTRL = 1 << 0,
WMOD_SHIFT = 1 << 1,
WMOD_ALT = 1 << 2,
WMOD_SUPER = 1 << 3 // Cmd on Mac, Win on Windows
};
struct KeyCombo {
@@ -29,10 +29,10 @@ struct KeyCombo {
std::string toString() const {
std::string result;
if (modifiers & MOD_CTRL) result += "Ctrl+";
if (modifiers & MOD_SHIFT) result += "Shift+";
if (modifiers & MOD_ALT) result += "Alt+";
if (modifiers & MOD_SUPER) result += "Super+";
if (modifiers & WMOD_CTRL) result += "Ctrl+";
if (modifiers & WMOD_SHIFT) result += "Shift+";
if (modifiers & WMOD_ALT) result += "Alt+";
if (modifiers & WMOD_SUPER) result += "Super+";
if (key >= 'A' && key <= 'Z') {
result += (char)key;
} else if (key >= '0' && key <= '9') {
@@ -88,7 +88,7 @@ public:
KeyCombo getBinding(const std::string& action) const {
auto it = bindings_.find(action);
if (it != bindings_.end()) return it->second;
return {0, MOD_NONE};
return {0, WMOD_NONE};
}
// Look up the action for a key combo (returns "" if not bound)
@@ -127,148 +127,148 @@ private:
// --- VSCode profile (default) ---
void loadVSCode() {
// File operations
bind("file.save", 'S', MOD_CTRL);
bind("file.saveAs", 'S', MOD_CTRL | MOD_SHIFT);
bind("file.open", 'O', MOD_CTRL);
bind("file.new", 'N', MOD_CTRL);
bind("file.close", 'W', MOD_CTRL);
bind("file.save", 'S', WMOD_CTRL);
bind("file.saveAs", 'S', WMOD_CTRL | WMOD_SHIFT);
bind("file.open", 'O', WMOD_CTRL);
bind("file.new", 'N', WMOD_CTRL);
bind("file.close", 'W', WMOD_CTRL);
// Edit operations
bind("edit.undo", 'Z', MOD_CTRL);
bind("edit.redo", 'Y', MOD_CTRL);
bind("edit.cut", 'X', MOD_CTRL);
bind("edit.copy", 'C', MOD_CTRL);
bind("edit.paste", 'V', MOD_CTRL);
bind("edit.selectAll", 'A', MOD_CTRL);
bind("edit.delete", 127, MOD_NONE); // Delete key
bind("edit.duplicateLine", 'D', MOD_CTRL | MOD_SHIFT);
bind("edit.undo", 'Z', WMOD_CTRL);
bind("edit.redo", 'Y', WMOD_CTRL);
bind("edit.cut", 'X', WMOD_CTRL);
bind("edit.copy", 'C', WMOD_CTRL);
bind("edit.paste", 'V', WMOD_CTRL);
bind("edit.selectAll", 'A', WMOD_CTRL);
bind("edit.delete", 127, WMOD_NONE); // Delete key
bind("edit.duplicateLine", 'D', WMOD_CTRL | WMOD_SHIFT);
// Search
bind("search.find", 'F', MOD_CTRL);
bind("search.replace", 'H', MOD_CTRL);
bind("search.findNext", 'G', MOD_CTRL);
bind("search.findPrev", 'G', MOD_CTRL | MOD_SHIFT);
bind("search.findInFiles", 'F', MOD_CTRL | MOD_SHIFT);
bind("search.find", 'F', WMOD_CTRL);
bind("search.replace", 'H', WMOD_CTRL);
bind("search.findNext", 'G', WMOD_CTRL);
bind("search.findPrev", 'G', WMOD_CTRL | WMOD_SHIFT);
bind("search.findInFiles", 'F', WMOD_CTRL | WMOD_SHIFT);
// Navigation
bind("nav.goToLine", 'G', MOD_CTRL);
bind("nav.goToFile", 'P', MOD_CTRL);
bind("nav.goToSymbol", 'O', MOD_CTRL | MOD_SHIFT);
bind("nav.goToLine", 'G', WMOD_CTRL);
bind("nav.goToFile", 'P', WMOD_CTRL);
bind("nav.goToSymbol", 'O', WMOD_CTRL | WMOD_SHIFT);
// View
bind("view.toggleSidebar", 'B', MOD_CTRL);
bind("view.toggleTerminal", '`', MOD_CTRL);
bind("view.zoomIn", '=', MOD_CTRL);
bind("view.zoomOut", '-', MOD_CTRL);
bind("view.commandPalette", 'P', MOD_CTRL | MOD_SHIFT);
bind("view.toggleSidebar", 'B', WMOD_CTRL);
bind("view.toggleTerminal", '`', WMOD_CTRL);
bind("view.zoomIn", '=', WMOD_CTRL);
bind("view.zoomOut", '-', WMOD_CTRL);
bind("view.commandPalette", 'P', WMOD_CTRL | WMOD_SHIFT);
// Code
bind("code.comment", '/', MOD_CTRL);
bind("code.format", 'F', MOD_CTRL | MOD_SHIFT | MOD_ALT);
bind("code.goToDefinition", 0x0D, MOD_CTRL); // Ctrl+Enter or F12
bind("code.rename", 'R', MOD_CTRL | MOD_SHIFT);
bind("code.comment", '/', WMOD_CTRL);
bind("code.format", 'F', WMOD_CTRL | WMOD_SHIFT | WMOD_ALT);
bind("code.goToDefinition", 0x0D, WMOD_CTRL); // Ctrl+Enter or F12
bind("code.rename", 'R', WMOD_CTRL | WMOD_SHIFT);
// Build
bind("build.run", 'B', MOD_CTRL | MOD_SHIFT);
bind("build.build", 'B', MOD_CTRL);
bind("build.run", 'B', WMOD_CTRL | WMOD_SHIFT);
bind("build.build", 'B', WMOD_CTRL);
}
// --- JetBrains profile ---
void loadJetBrains() {
// File operations
bind("file.save", 'S', MOD_CTRL);
bind("file.saveAs", 'S', MOD_CTRL | MOD_SHIFT);
bind("file.open", 'O', MOD_CTRL);
bind("file.new", 'N', MOD_CTRL | MOD_ALT);
bind("file.close", 'W', MOD_CTRL);
bind("file.save", 'S', WMOD_CTRL);
bind("file.saveAs", 'S', WMOD_CTRL | WMOD_SHIFT);
bind("file.open", 'O', WMOD_CTRL);
bind("file.new", 'N', WMOD_CTRL | WMOD_ALT);
bind("file.close", 'W', WMOD_CTRL);
// Edit operations
bind("edit.undo", 'Z', MOD_CTRL);
bind("edit.redo", 'Z', MOD_CTRL | MOD_SHIFT);
bind("edit.cut", 'X', MOD_CTRL);
bind("edit.copy", 'C', MOD_CTRL);
bind("edit.paste", 'V', MOD_CTRL);
bind("edit.selectAll", 'A', MOD_CTRL);
bind("edit.delete", 127, MOD_NONE);
bind("edit.duplicateLine", 'D', MOD_CTRL);
bind("edit.undo", 'Z', WMOD_CTRL);
bind("edit.redo", 'Z', WMOD_CTRL | WMOD_SHIFT);
bind("edit.cut", 'X', WMOD_CTRL);
bind("edit.copy", 'C', WMOD_CTRL);
bind("edit.paste", 'V', WMOD_CTRL);
bind("edit.selectAll", 'A', WMOD_CTRL);
bind("edit.delete", 127, WMOD_NONE);
bind("edit.duplicateLine", 'D', WMOD_CTRL);
// Search
bind("search.find", 'F', MOD_CTRL);
bind("search.replace", 'R', MOD_CTRL);
bind("search.findNext", 'L', MOD_CTRL);
bind("search.findPrev", 'L', MOD_CTRL | MOD_SHIFT);
bind("search.findInFiles", 'F', MOD_CTRL | MOD_SHIFT);
bind("search.find", 'F', WMOD_CTRL);
bind("search.replace", 'R', WMOD_CTRL);
bind("search.findNext", 'L', WMOD_CTRL);
bind("search.findPrev", 'L', WMOD_CTRL | WMOD_SHIFT);
bind("search.findInFiles", 'F', WMOD_CTRL | WMOD_SHIFT);
// Navigation
bind("nav.goToLine", 'G', MOD_CTRL);
bind("nav.goToFile", 'N', MOD_CTRL | MOD_SHIFT);
bind("nav.goToSymbol", 'O', MOD_CTRL | MOD_ALT | MOD_SHIFT);
bind("nav.goToLine", 'G', WMOD_CTRL);
bind("nav.goToFile", 'N', WMOD_CTRL | WMOD_SHIFT);
bind("nav.goToSymbol", 'O', WMOD_CTRL | WMOD_ALT | WMOD_SHIFT);
// View
bind("view.toggleSidebar", '1', MOD_ALT);
bind("view.toggleTerminal", '4', MOD_ALT);
bind("view.zoomIn", '=', MOD_CTRL);
bind("view.zoomOut", '-', MOD_CTRL);
bind("view.commandPalette", 'A', MOD_CTRL | MOD_SHIFT);
bind("view.toggleSidebar", '1', WMOD_ALT);
bind("view.toggleTerminal", '4', WMOD_ALT);
bind("view.zoomIn", '=', WMOD_CTRL);
bind("view.zoomOut", '-', WMOD_CTRL);
bind("view.commandPalette", 'A', WMOD_CTRL | WMOD_SHIFT);
// Code
bind("code.comment", '/', MOD_CTRL);
bind("code.format", 'L', MOD_CTRL | MOD_ALT);
bind("code.goToDefinition", 'B', MOD_CTRL);
bind("code.rename", 'R', MOD_SHIFT | MOD_ALT);
bind("code.comment", '/', WMOD_CTRL);
bind("code.format", 'L', WMOD_CTRL | WMOD_ALT);
bind("code.goToDefinition", 'B', WMOD_CTRL);
bind("code.rename", 'R', WMOD_SHIFT | WMOD_ALT);
// Build
bind("build.run", 'R', MOD_CTRL | MOD_SHIFT);
bind("build.build", 'B', MOD_CTRL | MOD_SHIFT);
bind("build.run", 'R', WMOD_CTRL | WMOD_SHIFT);
bind("build.build", 'B', WMOD_CTRL | WMOD_SHIFT);
}
// --- Emacs profile ---
void loadEmacs() {
// File operations
bind("file.save", 'S', MOD_CTRL);
bind("file.saveAs", 'S', MOD_CTRL | MOD_SHIFT);
bind("file.open", 'O', MOD_CTRL);
bind("file.new", 'N', MOD_CTRL);
bind("file.close", 'W', MOD_CTRL);
bind("file.save", 'S', WMOD_CTRL);
bind("file.saveAs", 'S', WMOD_CTRL | WMOD_SHIFT);
bind("file.open", 'O', WMOD_CTRL);
bind("file.new", 'N', WMOD_CTRL);
bind("file.close", 'W', WMOD_CTRL);
// Edit operations
bind("edit.undo", 'Z', MOD_CTRL);
bind("edit.redo", 'Z', MOD_CTRL | MOD_SHIFT);
bind("edit.cut", 'W', MOD_CTRL);
bind("edit.copy", 'W', MOD_ALT);
bind("edit.paste", 'Y', MOD_CTRL);
bind("edit.selectAll", 'A', MOD_CTRL);
bind("edit.delete", 'D', MOD_CTRL);
bind("edit.duplicateLine", 'D', MOD_CTRL | MOD_SHIFT);
bind("edit.undo", 'Z', WMOD_CTRL);
bind("edit.redo", 'Z', WMOD_CTRL | WMOD_SHIFT);
bind("edit.cut", 'W', WMOD_CTRL);
bind("edit.copy", 'W', WMOD_ALT);
bind("edit.paste", 'Y', WMOD_CTRL);
bind("edit.selectAll", 'A', WMOD_CTRL);
bind("edit.delete", 'D', WMOD_CTRL);
bind("edit.duplicateLine", 'D', WMOD_CTRL | WMOD_SHIFT);
// Search
bind("search.find", 'S', MOD_CTRL);
bind("search.replace", 'R', MOD_ALT);
bind("search.findNext", 'S', MOD_CTRL);
bind("search.findPrev", 'R', MOD_CTRL);
bind("search.findInFiles", 'F', MOD_CTRL | MOD_SHIFT);
bind("search.find", 'S', WMOD_CTRL);
bind("search.replace", 'R', WMOD_ALT);
bind("search.findNext", 'S', WMOD_CTRL);
bind("search.findPrev", 'R', WMOD_CTRL);
bind("search.findInFiles", 'F', WMOD_CTRL | WMOD_SHIFT);
// Navigation
bind("nav.goToLine", 'G', MOD_ALT);
bind("nav.goToFile", 'F', MOD_CTRL);
bind("nav.goToSymbol", 'O', MOD_CTRL | MOD_SHIFT);
bind("nav.goToLine", 'G', WMOD_ALT);
bind("nav.goToFile", 'F', WMOD_CTRL);
bind("nav.goToSymbol", 'O', WMOD_CTRL | WMOD_SHIFT);
// View
bind("view.toggleSidebar", 'B', MOD_CTRL);
bind("view.toggleTerminal", '`', MOD_CTRL);
bind("view.zoomIn", '=', MOD_CTRL);
bind("view.zoomOut", '-', MOD_CTRL);
bind("view.commandPalette", 'X', MOD_ALT);
bind("view.toggleSidebar", 'B', WMOD_CTRL);
bind("view.toggleTerminal", '`', WMOD_CTRL);
bind("view.zoomIn", '=', WMOD_CTRL);
bind("view.zoomOut", '-', WMOD_CTRL);
bind("view.commandPalette", 'X', WMOD_ALT);
// Code
bind("code.comment", ';', MOD_ALT);
bind("code.format", 'F', MOD_CTRL | MOD_ALT);
bind("code.goToDefinition", '.', MOD_ALT);
bind("code.rename", 'R', MOD_CTRL | MOD_SHIFT);
bind("code.comment", ';', WMOD_ALT);
bind("code.format", 'F', WMOD_CTRL | WMOD_ALT);
bind("code.goToDefinition", '.', WMOD_ALT);
bind("code.rename", 'R', WMOD_CTRL | WMOD_SHIFT);
// Build
bind("build.run", 'C', MOD_CTRL | MOD_SHIFT);
bind("build.build", 'B', MOD_CTRL | MOD_SHIFT);
bind("build.run", 'C', WMOD_CTRL | WMOD_SHIFT);
bind("build.build", 'B', WMOD_CTRL | WMOD_SHIFT);
}
KeybindingProfile profile_;