Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
// Step 54 TDD Test: Configurable keybinding profiles
|
|
|
|
|
//
|
|
|
|
|
// Verifies that KeybindingManager:
|
|
|
|
|
// 1. Defaults to VSCode profile
|
|
|
|
|
// 2. Can switch between profiles (VSCode, JetBrains, Emacs)
|
|
|
|
|
// 3. Different profiles have different bindings for the same actions
|
|
|
|
|
// 4. Reverse lookup (key combo -> action) works
|
|
|
|
|
// 5. Custom binding overrides work
|
|
|
|
|
// 6. All profiles define core actions
|
|
|
|
|
// 7. Profile names round-trip correctly
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include "KeybindingManager.h"
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
int passed = 0;
|
|
|
|
|
int failed = 0;
|
|
|
|
|
|
|
|
|
|
// --- Test 1: Default profile is VSCode ---
|
|
|
|
|
{
|
|
|
|
|
KeybindingManager mgr;
|
|
|
|
|
assert(mgr.getProfile() == KeybindingProfile::VSCode &&
|
|
|
|
|
"Default profile should be VSCode");
|
|
|
|
|
|
|
|
|
|
std::cout << "Test 1 PASS: Default profile is VSCode" << std::endl;
|
|
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Test 2: VSCode bindings are correct ---
|
|
|
|
|
{
|
|
|
|
|
KeybindingManager mgr;
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo save = mgr.getBinding("file.save");
|
2026-02-08 16:21:22 -07:00
|
|
|
assert(save.key == 'S' && save.modifiers == WMOD_CTRL &&
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
"VSCode: file.save should be Ctrl+S");
|
|
|
|
|
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo undo = mgr.getBinding("edit.undo");
|
2026-02-08 16:21:22 -07:00
|
|
|
assert(undo.key == 'Z' && undo.modifiers == WMOD_CTRL &&
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
"VSCode: edit.undo should be Ctrl+Z");
|
|
|
|
|
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo redo = mgr.getBinding("edit.redo");
|
2026-02-08 16:21:22 -07:00
|
|
|
assert(redo.key == 'Y' && redo.modifiers == WMOD_CTRL &&
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
"VSCode: edit.redo should be Ctrl+Y");
|
|
|
|
|
|
|
|
|
|
std::cout << "Test 2 PASS: VSCode bindings correct" << std::endl;
|
|
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Test 3: JetBrains has different redo ---
|
|
|
|
|
{
|
|
|
|
|
KeybindingManager mgr;
|
|
|
|
|
mgr.setProfile(KeybindingProfile::JetBrains);
|
|
|
|
|
assert(mgr.getProfile() == KeybindingProfile::JetBrains);
|
|
|
|
|
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo redo = mgr.getBinding("edit.redo");
|
2026-02-08 16:21:22 -07:00
|
|
|
assert(redo.key == 'Z' && redo.modifiers == (WMOD_CTRL | WMOD_SHIFT) &&
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
"JetBrains: edit.redo should be Ctrl+Shift+Z");
|
|
|
|
|
|
|
|
|
|
// But save is still Ctrl+S
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo save = mgr.getBinding("file.save");
|
2026-02-08 16:21:22 -07:00
|
|
|
assert(save.key == 'S' && save.modifiers == WMOD_CTRL &&
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
"JetBrains: file.save should still be Ctrl+S");
|
|
|
|
|
|
|
|
|
|
std::cout << "Test 3 PASS: JetBrains profile has different redo" << std::endl;
|
|
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Test 4: Emacs profile loads ---
|
|
|
|
|
{
|
|
|
|
|
KeybindingManager mgr;
|
|
|
|
|
mgr.setProfile(KeybindingProfile::Emacs);
|
|
|
|
|
assert(mgr.getProfile() == KeybindingProfile::Emacs);
|
|
|
|
|
|
|
|
|
|
// Emacs uses Ctrl+Y for paste
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo paste = mgr.getBinding("edit.paste");
|
2026-02-08 16:21:22 -07:00
|
|
|
assert(paste.key == 'Y' && paste.modifiers == WMOD_CTRL &&
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
"Emacs: edit.paste should be Ctrl+Y");
|
|
|
|
|
|
|
|
|
|
std::cout << "Test 4 PASS: Emacs profile loads with correct bindings" << std::endl;
|
|
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Test 5: Reverse lookup (combo -> action) ---
|
|
|
|
|
{
|
|
|
|
|
KeybindingManager mgr; // VSCode
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo ctrlS = {'S', WMOD_CTRL};
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
std::string action = mgr.getAction(ctrlS);
|
|
|
|
|
assert(action == "file.save" && "Ctrl+S should map to file.save");
|
|
|
|
|
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo unknown = {'Q', WMOD_CTRL | WMOD_ALT | WMOD_SHIFT};
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
std::string none = mgr.getAction(unknown);
|
|
|
|
|
assert(none.empty() && "Unknown combo should return empty string");
|
|
|
|
|
|
|
|
|
|
std::cout << "Test 5 PASS: Reverse lookup works" << std::endl;
|
|
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Test 6: Custom binding override ---
|
|
|
|
|
{
|
|
|
|
|
KeybindingManager mgr;
|
2026-02-08 16:21:22 -07:00
|
|
|
mgr.setBinding("file.save", {'S', WMOD_CTRL | WMOD_ALT});
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo save = mgr.getBinding("file.save");
|
2026-02-08 16:21:22 -07:00
|
|
|
assert(save.key == 'S' && save.modifiers == (WMOD_CTRL | WMOD_ALT) &&
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
"Custom override should change binding");
|
|
|
|
|
|
|
|
|
|
std::cout << "Test 6 PASS: Custom binding override" << std::endl;
|
|
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Test 7: All profiles define core actions ---
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string> coreActions = {
|
|
|
|
|
"file.save", "edit.undo", "edit.redo", "edit.copy", "edit.paste",
|
|
|
|
|
"search.find", "code.comment"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (auto profile : KeybindingManager::availableProfiles()) {
|
|
|
|
|
KeybindingManager mgr;
|
|
|
|
|
mgr.setProfile(profile);
|
|
|
|
|
for (const auto& action : coreActions) {
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo combo = mgr.getBinding(action);
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
assert(combo.key != 0 &&
|
|
|
|
|
(std::string("Profile ") +
|
|
|
|
|
KeybindingManager::profileName(profile) +
|
|
|
|
|
" missing action: " + action).c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::cout << "Test 7 PASS: All profiles define core actions" << std::endl;
|
|
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Test 8: Profile name round-trip ---
|
|
|
|
|
{
|
|
|
|
|
for (auto profile : KeybindingManager::availableProfiles()) {
|
|
|
|
|
const char* name = KeybindingManager::profileName(profile);
|
|
|
|
|
KeybindingProfile roundTripped = KeybindingManager::profileFromName(name);
|
|
|
|
|
assert(roundTripped == profile && "Profile name should round-trip");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unknown name defaults to VSCode
|
|
|
|
|
KeybindingProfile def = KeybindingManager::profileFromName("unknown");
|
|
|
|
|
assert(def == KeybindingProfile::VSCode && "Unknown profile should default to VSCode");
|
|
|
|
|
|
|
|
|
|
std::cout << "Test 8 PASS: Profile name round-trip" << std::endl;
|
|
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-16 17:46:05 -07:00
|
|
|
// --- Test 9: LegacyKeyCombo toString ---
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
{
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo ctrlS = {'S', WMOD_CTRL};
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
assert(ctrlS.toString() == "Ctrl+S" && "Ctrl+S toString");
|
|
|
|
|
|
2026-02-16 17:46:05 -07:00
|
|
|
LegacyKeyCombo ctrlShiftZ = {'Z', WMOD_CTRL | WMOD_SHIFT};
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
assert(ctrlShiftZ.toString() == "Ctrl+Shift+Z" && "Ctrl+Shift+Z toString");
|
|
|
|
|
|
2026-02-16 17:46:05 -07:00
|
|
|
std::cout << "Test 9 PASS: LegacyKeyCombo toString" << std::endl;
|
Phase 3c complete: syntax highlighting and configurable keybindings (Steps 52, 54)
Step 52: SyntaxHighlighter walks tree-sitter CST to produce colored
token spans (keyword, string, comment, number, function, parameter,
type, operator, etc.) for Python, C++, and Elisp.
Step 54: KeybindingManager with swappable profiles — VSCode (default),
JetBrains, and Emacs. Each profile maps 25+ actions (file, edit,
search, nav, view, code, build) to key combos. Supports custom
overrides and reverse lookup.
Design direction: editor targets VSCode/JetBrains look-and-feel.
Keybinding profile selectable at startup. VSCode is default.
Phase 3c totals: 37/37 tests pass across 5 steps (50-54).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:12:10 -07:00
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Test 10: listActions returns all bound actions ---
|
|
|
|
|
{
|
|
|
|
|
KeybindingManager mgr;
|
|
|
|
|
auto actions = mgr.listActions();
|
|
|
|
|
assert(actions.size() > 20 && "VSCode profile should have 20+ actions");
|
|
|
|
|
|
|
|
|
|
// Check a few exist
|
|
|
|
|
assert(std::find(actions.begin(), actions.end(), "file.save") != actions.end());
|
|
|
|
|
assert(std::find(actions.begin(), actions.end(), "edit.undo") != actions.end());
|
|
|
|
|
assert(std::find(actions.begin(), actions.end(), "search.find") != actions.end());
|
|
|
|
|
|
|
|
|
|
std::cout << "Test 10 PASS: listActions returns all bound actions" << std::endl;
|
|
|
|
|
++passed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Summary ---
|
|
|
|
|
std::cout << "\n=== Step 54 Results: " << passed << " passed, " << failed << " failed ===" << std::endl;
|
|
|
|
|
return failed > 0 ? 1 : 0;
|
|
|
|
|
}
|