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:
@@ -236,7 +236,7 @@ code and will fail to link until their implementations exist.
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
- **Editor** (`whetstone_editor.exe`): ImGui-based GUI. Renders AST as structured editor panels with file tree, toolbar, projection toggles. Currently a Step 12 scaffold — functional but minimal.
|
||||
- **Editor** (`whetstone_editor.exe`): ImGui-based GUI with VSCode Dark theme. Docking layout: Explorer (left), Editor with tabs (center), Panel with Output/AST/Highlighted/Generated tabs (bottom), blue status bar. Editable text via InputTextMultiline backed by TextEditor + TextASTSync. Syntax-highlighted preview, live AST view, generated code preview. Configurable keybinding profiles (VSCode/JetBrains/Emacs). Find/Replace dialog. File open/save with language auto-detection.
|
||||
- **Orchestrator** (`orchestrator.exe`): Standalone JSON-RPC server. Manages AST state, undo/redo journal, file I/O, Emacs daemon integration, agent API.
|
||||
- **Communication**: Editor ↔ Orchestrator via JSON-RPC over stdin/stdout pipes. When launched standalone (no pipe), the editor runs in disconnected mode.
|
||||
- **Generators**: AST → Python, C++, Elisp text output. C++ generator handles canonical memory annotations.
|
||||
@@ -248,10 +248,10 @@ code and will fail to link until their implementations exist.
|
||||
|
||||
Phase 3c (Classical Editing Mode) is complete. All backend components exist:
|
||||
text editing, AST sync, syntax highlighting, and configurable keybindings.
|
||||
GUI is fully wired — editor is functional and can be launched.
|
||||
Next logical work:
|
||||
- **Phase 3d** (Steps 55–58): Emacs integration completion (splash screen, mode-specific behavior)
|
||||
- **Phase 3e** (Steps 59–63): WebSocket agent API (Step 60 already done, remaining: WebSocket endpoint, agent protocol)
|
||||
- **GUI wiring**: Connect TextEditor, SyntaxHighlighter, KeybindingManager into main.cpp ImGui shell
|
||||
|
||||
---
|
||||
|
||||
@@ -273,3 +273,4 @@ Next logical work:
|
||||
| 2026-02-08 | Claude Opus 4.6 | Phase 3b: Real tree-sitter integration (Steps 45–49). Replaced Parser.h stubs with real tree-sitter C bindings. Python/C++/Elisp CST-to-AST conversion, memory pattern detection, error recovery. 34/34 tests pass. |
|
||||
| 2026-02-08 | Claude Opus 4.6 | Phase 3c: Steps 50–53. TextASTSync (bidirectional text↔AST sync with debounce) and TextEditor (edit ops, undo/redo with AST tracking, find/replace, selection). 19/19 tests pass. Fixed step53 find-position bug (was off-by-one). |
|
||||
| 2026-02-08 | Claude Opus 4.6 | Phase 3c complete: Steps 52+54. SyntaxHighlighter (tree-sitter CST→color spans for Python/C++/Elisp). KeybindingManager (VSCode/JetBrains/Emacs profiles, default VSCode). 37/37 total Phase 3c tests pass. Design pivot: editor targets VSCode/JetBrains look, not Emacs. |
|
||||
| 2026-02-08 | Claude Opus 4.6 | GUI wiring: Rewrote main.cpp from Step 12 scaffold to functional editor. VSCode Dark theme, docking layout, editable text with TextEditor/TextASTSync, syntax-highlighted preview, live AST view, generated code tab, find/replace, keybinding profile selector, status bar. Fixed WMOD_ prefix (Windows MOD_SHIFT/MOD_ALT macro conflicts). whetstone_editor.exe builds and links. |
|
||||
|
||||
@@ -346,7 +346,11 @@ target_link_libraries(whetstone_editor PRIVATE
|
||||
OpenGL::GL
|
||||
glad::glad
|
||||
imgui::imgui
|
||||
nlohmann_json::nlohmann_json)
|
||||
nlohmann_json::nlohmann_json
|
||||
unofficial::tree-sitter::tree-sitter
|
||||
tree_sitter_python
|
||||
tree_sitter_cpp
|
||||
tree_sitter_elisp)
|
||||
|
||||
add_executable(orchestrator src/orchestrator_main.cpp)
|
||||
target_include_directories(orchestrator PRIVATE src)
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <tree_sitter/api.h>
|
||||
|
||||
|
||||
1208
editor/src/main.cpp
1208
editor/src/main.cpp
File diff suppressed because it is too large
Load Diff
@@ -33,15 +33,15 @@ int main() {
|
||||
{
|
||||
KeybindingManager mgr;
|
||||
KeyCombo save = mgr.getBinding("file.save");
|
||||
assert(save.key == 'S' && save.modifiers == MOD_CTRL &&
|
||||
assert(save.key == 'S' && save.modifiers == WMOD_CTRL &&
|
||||
"VSCode: file.save should be Ctrl+S");
|
||||
|
||||
KeyCombo undo = mgr.getBinding("edit.undo");
|
||||
assert(undo.key == 'Z' && undo.modifiers == MOD_CTRL &&
|
||||
assert(undo.key == 'Z' && undo.modifiers == WMOD_CTRL &&
|
||||
"VSCode: edit.undo should be Ctrl+Z");
|
||||
|
||||
KeyCombo redo = mgr.getBinding("edit.redo");
|
||||
assert(redo.key == 'Y' && redo.modifiers == MOD_CTRL &&
|
||||
assert(redo.key == 'Y' && redo.modifiers == WMOD_CTRL &&
|
||||
"VSCode: edit.redo should be Ctrl+Y");
|
||||
|
||||
std::cout << "Test 2 PASS: VSCode bindings correct" << std::endl;
|
||||
@@ -55,12 +55,12 @@ int main() {
|
||||
assert(mgr.getProfile() == KeybindingProfile::JetBrains);
|
||||
|
||||
KeyCombo redo = mgr.getBinding("edit.redo");
|
||||
assert(redo.key == 'Z' && redo.modifiers == (MOD_CTRL | MOD_SHIFT) &&
|
||||
assert(redo.key == 'Z' && redo.modifiers == (WMOD_CTRL | WMOD_SHIFT) &&
|
||||
"JetBrains: edit.redo should be Ctrl+Shift+Z");
|
||||
|
||||
// But save is still Ctrl+S
|
||||
KeyCombo save = mgr.getBinding("file.save");
|
||||
assert(save.key == 'S' && save.modifiers == MOD_CTRL &&
|
||||
assert(save.key == 'S' && save.modifiers == WMOD_CTRL &&
|
||||
"JetBrains: file.save should still be Ctrl+S");
|
||||
|
||||
std::cout << "Test 3 PASS: JetBrains profile has different redo" << std::endl;
|
||||
@@ -75,7 +75,7 @@ int main() {
|
||||
|
||||
// Emacs uses Ctrl+Y for paste
|
||||
KeyCombo paste = mgr.getBinding("edit.paste");
|
||||
assert(paste.key == 'Y' && paste.modifiers == MOD_CTRL &&
|
||||
assert(paste.key == 'Y' && paste.modifiers == WMOD_CTRL &&
|
||||
"Emacs: edit.paste should be Ctrl+Y");
|
||||
|
||||
std::cout << "Test 4 PASS: Emacs profile loads with correct bindings" << std::endl;
|
||||
@@ -85,11 +85,11 @@ int main() {
|
||||
// --- Test 5: Reverse lookup (combo -> action) ---
|
||||
{
|
||||
KeybindingManager mgr; // VSCode
|
||||
KeyCombo ctrlS = {'S', MOD_CTRL};
|
||||
KeyCombo ctrlS = {'S', WMOD_CTRL};
|
||||
std::string action = mgr.getAction(ctrlS);
|
||||
assert(action == "file.save" && "Ctrl+S should map to file.save");
|
||||
|
||||
KeyCombo unknown = {'Q', MOD_CTRL | MOD_ALT | MOD_SHIFT};
|
||||
KeyCombo unknown = {'Q', WMOD_CTRL | WMOD_ALT | WMOD_SHIFT};
|
||||
std::string none = mgr.getAction(unknown);
|
||||
assert(none.empty() && "Unknown combo should return empty string");
|
||||
|
||||
@@ -100,10 +100,10 @@ int main() {
|
||||
// --- Test 6: Custom binding override ---
|
||||
{
|
||||
KeybindingManager mgr;
|
||||
mgr.setBinding("file.save", {'S', MOD_CTRL | MOD_ALT});
|
||||
mgr.setBinding("file.save", {'S', WMOD_CTRL | WMOD_ALT});
|
||||
|
||||
KeyCombo save = mgr.getBinding("file.save");
|
||||
assert(save.key == 'S' && save.modifiers == (MOD_CTRL | MOD_ALT) &&
|
||||
assert(save.key == 'S' && save.modifiers == (WMOD_CTRL | WMOD_ALT) &&
|
||||
"Custom override should change binding");
|
||||
|
||||
std::cout << "Test 6 PASS: Custom binding override" << std::endl;
|
||||
@@ -151,10 +151,10 @@ int main() {
|
||||
|
||||
// --- Test 9: KeyCombo toString ---
|
||||
{
|
||||
KeyCombo ctrlS = {'S', MOD_CTRL};
|
||||
KeyCombo ctrlS = {'S', WMOD_CTRL};
|
||||
assert(ctrlS.toString() == "Ctrl+S" && "Ctrl+S toString");
|
||||
|
||||
KeyCombo ctrlShiftZ = {'Z', MOD_CTRL | MOD_SHIFT};
|
||||
KeyCombo ctrlShiftZ = {'Z', WMOD_CTRL | WMOD_SHIFT};
|
||||
assert(ctrlShiftZ.toString() == "Ctrl+Shift+Z" && "Ctrl+Shift+Z toString");
|
||||
|
||||
std::cout << "Test 9 PASS: KeyCombo toString" << std::endl;
|
||||
|
||||
Reference in New Issue
Block a user