diff --git a/editor/src/KeybindingManager.h b/editor/src/KeybindingManager.h index c677c44..0e5b917 100644 --- a/editor/src/KeybindingManager.h +++ b/editor/src/KeybindingManager.h @@ -19,11 +19,11 @@ enum KeyMod : int { WMOD_SUPER = 1 << 3 // Cmd on Mac, Win on Windows }; -struct KeyCombo { +struct LegacyKeyCombo { int key; // virtual key or character code (e.g. 'S', 'Z', 'F') int modifiers; // bitmask of KeyMod - bool operator==(const KeyCombo& other) const { + bool operator==(const LegacyKeyCombo& other) const { return key == other.key && modifiers == other.modifiers; } @@ -85,14 +85,14 @@ public: } // Look up the key combo for an action (returns empty combo if not bound) - KeyCombo getBinding(const std::string& action) const { + LegacyKeyCombo getBinding(const std::string& action) const { auto it = bindings_.find(action); if (it != bindings_.end()) return it->second; return {0, WMOD_NONE}; } // Look up the action for a key combo (returns "" if not bound) - std::string getAction(const KeyCombo& combo) const { + std::string getAction(const LegacyKeyCombo& combo) const { for (const auto& [action, binding] : bindings_) { if (binding == combo) return action; } @@ -100,7 +100,7 @@ public: } // Override a single binding - void setBinding(const std::string& action, KeyCombo combo) { + void setBinding(const std::string& action, LegacyKeyCombo combo) { bindings_[action] = combo; } @@ -272,5 +272,5 @@ private: } KeybindingProfile profile_; - std::map bindings_; + std::map bindings_; }; diff --git a/editor/src/ShortcutReference.h b/editor/src/ShortcutReference.h index 22ba484..079ceac 100644 --- a/editor/src/ShortcutReference.h +++ b/editor/src/ShortcutReference.h @@ -28,7 +28,7 @@ static void renderShortcutReference(EditorState& state, ShortcutReferenceState& std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char c) { return (char)std::tolower(c); }); if (!filterText.empty() && lower.find(filterText) == std::string::npos) continue; - KeyCombo combo = state.keys.getBinding(action); + LegacyKeyCombo combo = state.keys.getBinding(action); ImGui::Text("%s", action.c_str()); ImGui::SameLine(260.0f); ImGui::TextDisabled("%s", combo.toString().c_str()); diff --git a/editor/src/main.cpp b/editor/src/main.cpp index 016b38b..41220a4 100644 --- a/editor/src/main.cpp +++ b/editor/src/main.cpp @@ -317,6 +317,11 @@ int main(int, char**) { } else { state.ui.showFirstRunWizard = true; } + if (state.buffers.bufferCount() == 0) { + state.createBuffer(state.makeUntitledName(), "", "python", + BufferManager::BufferMode::Text); + state.ui.focusTarget = FocusRegion::Editor; + } state.lspTransport = std::make_shared(); state.lsp = std::make_shared(state.lspTransport); @@ -399,7 +404,7 @@ int main(int, char**) { } if (key != 0 && mods != WMOD_NONE) { - KeyCombo combo{key, mods}; + LegacyKeyCombo combo{key, mods}; std::string action = state.keys.getAction(combo); if (action == "edit.undo") state.doUndo(); else if (action == "edit.redo") state.doRedo(); diff --git a/editor/src/panels/MenuBarPanel.h b/editor/src/panels/MenuBarPanel.h index 53be333..647c6d3 100644 --- a/editor/src/panels/MenuBarPanel.h +++ b/editor/src/panels/MenuBarPanel.h @@ -97,6 +97,7 @@ static void renderMenuBar(EditorState& state) { ImGui::MenuItem("Dependencies", nullptr, &state.library.showDependencyPanel); ImGui::MenuItem("Libraries", nullptr, &state.library.showLibraryBrowserPanel); ImGui::MenuItem("Compose", nullptr, &state.library.showCompositionPanel); + ImGui::MenuItem("Memory Strategies", nullptr, &state.ui.showMemoryStrategies); ImGui::MenuItem("Emacs Packages", nullptr, &state.emacsState.showEmacsPackagesPanel); ImGui::MenuItem("Emacs Bridge", nullptr, &state.emacsState.showEmacsBridgePanel); ImGui::MenuItem("Settings", nullptr, &state.ui.showSettingsPanel); diff --git a/editor/src/panels/SidePanels.h b/editor/src/panels/SidePanels.h index 1ee55f8..811a537 100644 --- a/editor/src/panels/SidePanels.h +++ b/editor/src/panels/SidePanels.h @@ -249,11 +249,12 @@ static void renderMinibuffer(EditorState& state) { } static void renderMemoryStrategiesPanel(EditorState& state) { + if (!state.ui.showMemoryStrategies) return; if (state.ui.focusTarget == FocusRegion::Side) { ImGui::SetNextWindowFocus(); state.ui.focusTarget = FocusRegion::None; } - ImGui::Begin("Memory Strategies"); + ImGui::Begin("Memory Strategies", &state.ui.showMemoryStrategies); if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)) { state.ui.focusedRegion = FocusRegion::Side; } diff --git a/editor/src/state/UIFlags.h b/editor/src/state/UIFlags.h index 3269d57..1f36259 100644 --- a/editor/src/state/UIFlags.h +++ b/editor/src/state/UIFlags.h @@ -20,6 +20,7 @@ struct UIFlags { bool showFirstRunWizard = false; bool showShortcutReference = false; bool showHelpPanel = false; + bool showMemoryStrategies = false; bool showAnnotateWizard = false; bool showProjectWizard = false; bool showAgentWizard = false; diff --git a/editor/tests/step54_test.cpp b/editor/tests/step54_test.cpp index 9b0f486..5af3f4e 100644 --- a/editor/tests/step54_test.cpp +++ b/editor/tests/step54_test.cpp @@ -32,15 +32,15 @@ int main() { // --- Test 2: VSCode bindings are correct --- { KeybindingManager mgr; - KeyCombo save = mgr.getBinding("file.save"); + LegacyKeyCombo save = mgr.getBinding("file.save"); assert(save.key == 'S' && save.modifiers == WMOD_CTRL && "VSCode: file.save should be Ctrl+S"); - KeyCombo undo = mgr.getBinding("edit.undo"); + LegacyKeyCombo undo = mgr.getBinding("edit.undo"); assert(undo.key == 'Z' && undo.modifiers == WMOD_CTRL && "VSCode: edit.undo should be Ctrl+Z"); - KeyCombo redo = mgr.getBinding("edit.redo"); + LegacyKeyCombo redo = mgr.getBinding("edit.redo"); assert(redo.key == 'Y' && redo.modifiers == WMOD_CTRL && "VSCode: edit.redo should be Ctrl+Y"); @@ -54,12 +54,12 @@ int main() { mgr.setProfile(KeybindingProfile::JetBrains); assert(mgr.getProfile() == KeybindingProfile::JetBrains); - KeyCombo redo = mgr.getBinding("edit.redo"); + LegacyKeyCombo redo = mgr.getBinding("edit.redo"); 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"); + LegacyKeyCombo save = mgr.getBinding("file.save"); assert(save.key == 'S' && save.modifiers == WMOD_CTRL && "JetBrains: file.save should still be Ctrl+S"); @@ -74,7 +74,7 @@ int main() { assert(mgr.getProfile() == KeybindingProfile::Emacs); // Emacs uses Ctrl+Y for paste - KeyCombo paste = mgr.getBinding("edit.paste"); + LegacyKeyCombo paste = mgr.getBinding("edit.paste"); assert(paste.key == 'Y' && paste.modifiers == WMOD_CTRL && "Emacs: edit.paste should be Ctrl+Y"); @@ -85,11 +85,11 @@ int main() { // --- Test 5: Reverse lookup (combo -> action) --- { KeybindingManager mgr; // VSCode - KeyCombo ctrlS = {'S', WMOD_CTRL}; + LegacyKeyCombo ctrlS = {'S', WMOD_CTRL}; std::string action = mgr.getAction(ctrlS); assert(action == "file.save" && "Ctrl+S should map to file.save"); - KeyCombo unknown = {'Q', WMOD_CTRL | WMOD_ALT | WMOD_SHIFT}; + LegacyKeyCombo unknown = {'Q', WMOD_CTRL | WMOD_ALT | WMOD_SHIFT}; std::string none = mgr.getAction(unknown); assert(none.empty() && "Unknown combo should return empty string"); @@ -102,7 +102,7 @@ int main() { KeybindingManager mgr; mgr.setBinding("file.save", {'S', WMOD_CTRL | WMOD_ALT}); - KeyCombo save = mgr.getBinding("file.save"); + LegacyKeyCombo save = mgr.getBinding("file.save"); assert(save.key == 'S' && save.modifiers == (WMOD_CTRL | WMOD_ALT) && "Custom override should change binding"); @@ -121,7 +121,7 @@ int main() { KeybindingManager mgr; mgr.setProfile(profile); for (const auto& action : coreActions) { - KeyCombo combo = mgr.getBinding(action); + LegacyKeyCombo combo = mgr.getBinding(action); assert(combo.key != 0 && (std::string("Profile ") + KeybindingManager::profileName(profile) + @@ -149,15 +149,15 @@ int main() { ++passed; } - // --- Test 9: KeyCombo toString --- + // --- Test 9: LegacyKeyCombo toString --- { - KeyCombo ctrlS = {'S', WMOD_CTRL}; + LegacyKeyCombo ctrlS = {'S', WMOD_CTRL}; assert(ctrlS.toString() == "Ctrl+S" && "Ctrl+S toString"); - KeyCombo ctrlShiftZ = {'Z', WMOD_CTRL | WMOD_SHIFT}; + LegacyKeyCombo 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; + std::cout << "Test 9 PASS: LegacyKeyCombo toString" << std::endl; ++passed; } diff --git a/progress.md b/progress.md index 9e8f528..f0fef5d 100644 --- a/progress.md +++ b/progress.md @@ -5232,6 +5232,53 @@ visual workflow path. - `editor/src/MCPServer.h` (`1940` > `600`) - `editor/src/HeadlessAgentRPCHandler.h` (`2768` > `600`) +## Post-Sprint Stabilization: Build + Startup Usability + +### Hotfix A: Keybinding type collision blocking editor build +**Status:** PASS (build restored) + +Resolved a compile-breaking global type collision between legacy keybinding code +and the newer registry by namespacing the legacy combo type. + +**Files modified:** +- `editor/src/KeybindingManager.h` — renamed legacy `KeyCombo` to `LegacyKeyCombo` +- `editor/src/main.cpp` — updated shortcut dispatch type usage +- `editor/src/ShortcutReference.h` — updated shortcut panel type usage +- `editor/tests/step54_test.cpp` — updated test references + +**Verification run:** +- `cmake --build editor/build-native --target whetstone_editor` — PASS +- `step54_test` — PASS (10/10) regression coverage + +### Hotfix B: startup usability (editable buffer + dismissible side panel) +**Status:** PASS (build restored, UX defaults improved) + +Adjusted startup defaults so users can type immediately and hide optional side +panels cleanly. + +**Files modified:** +- `editor/src/state/UIFlags.h` — added `showMemoryStrategies` flag (default `false`) +- `editor/src/panels/SidePanels.h` — made Memory Strategies panel conditional and closable +- `editor/src/panels/MenuBarPanel.h` — added View menu toggle for Memory Strategies panel +- `editor/src/main.cpp` — auto-create untitled text buffer when startup/session has no buffers; set editor focus + +**Verification run:** +- `cmake --build editor/build-native --target whetstone_editor` — PASS +- `step54_test` — PASS (10/10) regression coverage +- `step437_test` — PASS (8/8) regression coverage + +**Build health check cadence (to run after each sprint step cluster):** +- `cmake --build editor/build-native --target whetstone_editor -j4` +- `./editor/build-native/step54_test` +- `./editor/build-native/step437_test` + +**Architecture gate check:** +- `editor/src/main.cpp` within main-file limit (`587` <= `1500`) +- `editor/src/KeybindingManager.h` within header-size limit (`276` <= `600`) +- `editor/src/panels/SidePanels.h` within header-size limit (`308` <= `600`) +- `editor/src/panels/MenuBarPanel.h` within header-size limit (`268` <= `600`) +- `editor/src/state/UIFlags.h` within header-size limit (`33` <= `600`) + # Roadmap Planning — Sprints 12-25+ ## Status: Planning Complete (Sprints 12-19 detailed, 20-25 in roadmap.md)