From a8c7b2adfcdd324aadfd0da9a2be448c7dd3d8a3 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 9 Feb 2026 11:46:57 -0700 Subject: [PATCH] Step 107a: add text mode toggle --- PROGRESS.md | 5 ++++- editor/CMakeLists.txt | 4 ++++ editor/src/BufferManager.h | 24 ++++++++++++++++++++++-- editor/src/main.cpp | 24 +++++++++++++++++++++++- editor/tests/step107a_test.cpp | 28 ++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 editor/tests/step107a_test.cpp diff --git a/PROGRESS.md b/PROGRESS.md index 68c6f14..66c07e5 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -207,8 +207,9 @@ All 38 steps implemented and passing. Each step has a corresponding test (`step1 - [x] Step 104: **IMPLEMENTED** — Cross-language projection button with read-only projected tabs and annotation summary (2/2 tests pass) - [x] Step 105: **IMPLEMENTED** — Optimization controls panel with constraint-aware buttons and summaries (2/2 tests pass) - [x] Step 106: **IMPLEMENTED** — Transform history panel with undo controls and provenance coloring (1/1 tests pass) -- [ ] Step 107a–107c: **PLANNED** — Text-Editor Mode toggle, UI behavior by mode, and per-buffer persistence (not started) - [x] Step 107: **IMPLEMENTED** — Before/after diff view with preview and accept/reject (1/1 tests pass) +- [x] Step 107a: **IMPLEMENTED** — Text-Editor Mode toggle and per-buffer mode tracking (2/2 tests pass) +- [ ] Step 107b–107c: **PLANNED** — Mode-specific UI behavior and per-buffer persistence (not started) --- @@ -296,6 +297,7 @@ vcpkg's imgui 1.91.9 removed the `sdl2-binding` feature (only `sdl3-binding` exi **Step 105:** Compile and pass (2/2) **Step 106:** Compile and pass (1/1) **Step 107:** Compile and pass (1/1) +**Step 107a:** Compile and pass (2/2) --- @@ -413,3 +415,4 @@ Sprint 4 in progress. Step 76 (LayoutManager) done. Next: Step 77 (custom code e | 2026-02-09 | Codex | Step 106: Transform history panel with undo controls and provenance coloring. 1/1 tests pass. | | 2026-02-09 | Codex | Planned Step 107a–107c: add Text-Editor Mode toggle, mode-specific UI behavior, and per-buffer persistence. | | 2026-02-09 | Codex | Step 107: Before/after diff view with preview and accept/reject. 1/1 tests pass. | +| 2026-02-09 | Codex | Step 107a: Text-Editor Mode toggle and per-buffer mode tracking. 2/2 tests pass. | diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 1ce9e05..ded374a 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -578,6 +578,10 @@ add_executable(step107_test tests/step107_test.cpp) target_include_directories(step107_test PRIVATE src) target_link_libraries(step107_test PRIVATE nlohmann_json::nlohmann_json) +add_executable(step107a_test tests/step107a_test.cpp) +target_include_directories(step107a_test PRIVATE src) +target_link_libraries(step107a_test PRIVATE nlohmann_json::nlohmann_json) + find_package(SDL2 CONFIG REQUIRED) find_package(OpenGL REQUIRED) find_package(glad CONFIG REQUIRED) diff --git a/editor/src/BufferManager.h b/editor/src/BufferManager.h index 2a5ee1d..da9ffb3 100644 --- a/editor/src/BufferManager.h +++ b/editor/src/BufferManager.h @@ -11,20 +11,27 @@ class BufferManager { public: + enum class BufferMode { + Structured, + Text + }; + struct BufferInfo { std::string path; std::string content; std::string language; bool modified = false; + BufferMode mode = BufferMode::Structured; }; BufferManager() = default; // Open a file into a buffer (makes it active) bool openBuffer(const std::string& path, const std::string& content, - const std::string& language) { + const std::string& language, + BufferMode mode = BufferMode::Structured) { if (hasBuffer(path)) return false; // already open - BufferInfo info{path, content, language, false}; + BufferInfo info{path, content, language, false, mode}; buffers_[path] = info; activeBuffer_ = path; return true; @@ -70,6 +77,19 @@ public: } } + void setBufferMode(const std::string& path, BufferMode mode) { + auto it = buffers_.find(path); + if (it != buffers_.end()) { + it->second.mode = mode; + } + } + + BufferMode getBufferMode(const std::string& path) const { + auto it = buffers_.find(path); + if (it != buffers_.end()) return it->second.mode; + return BufferMode::Structured; + } + // Get list of all open buffer paths std::vector getOpenBuffers() const { std::vector result; diff --git a/editor/src/main.cpp b/editor/src/main.cpp index c1e3bd8..226f742 100644 --- a/editor/src/main.cpp +++ b/editor/src/main.cpp @@ -17,6 +17,7 @@ #include "TextASTSync.h" #include "SyntaxHighlighter.h" #include "KeybindingManager.h" +#include "BufferManager.h" #include "CodeEditorWidget.h" #include "EditorMode.h" #include "FileDialog.h" @@ -70,6 +71,7 @@ struct BufferState { std::string generatedLanguage = "python"; std::string path = "(untitled)"; bool readOnly = false; + BufferManager::BufferMode mode = BufferManager::BufferMode::Structured; bool modified = false; int cursorLine = 1; int cursorCol = 1; @@ -251,7 +253,8 @@ struct EditorState { state->generatedHighlightsDirty = true; state->modified = false; state->lspVersion = 1; - buffers.openBuffer(path, content, language); + buffers.openBuffer(path, content, language, BufferManager::BufferMode::Structured); + state->mode = BufferManager::BufferMode::Structured; activeBuffer = state.get(); bufferStates[path] = std::move(state); if (path.rfind("(untitled", 0) != 0) watcher.watch(path); @@ -1328,6 +1331,15 @@ int main(int, char**) { ImGui::MenuItem("Show Minimap", nullptr, &state.showMinimap); ImGui::MenuItem("Show Annotations", nullptr, &state.showAnnotations); ImGui::MenuItem("LSP Servers...", nullptr, &state.showLspSettings); + if (state.active()) { + bool textMode = state.active()->mode == BufferManager::BufferMode::Text; + if (ImGui::MenuItem("Text-Editor Mode", nullptr, textMode)) { + state.active()->mode = textMode ? + BufferManager::BufferMode::Structured : + BufferManager::BufferMode::Text; + state.buffers.setBufferMode(state.active()->path, state.active()->mode); + } + } if (ImGui::BeginMenu("Layout")) { if (ImGui::MenuItem("VSCode", nullptr, state.layoutPreset == LayoutPreset::VSCode)) state.layoutPreset = LayoutPreset::VSCode; @@ -2575,6 +2587,16 @@ int main(int, char**) { ImGui::Text("-"); ImGui::SameLine(0, 30); + // Mode + if (state.active()) { + const char* modeLabel = + state.active()->mode == BufferManager::BufferMode::Text ? "Text" : "Structured"; + ImGui::Text("Mode: %s", modeLabel); + } else { + ImGui::Text("Mode: -"); + } + ImGui::SameLine(0, 30); + // Keybinding profile ImGui::Text("Keys: %s", KeybindingManager::profileName(state.keys.getProfile())); ImGui::SameLine(0, 30); diff --git a/editor/tests/step107a_test.cpp b/editor/tests/step107a_test.cpp new file mode 100644 index 0000000..0d2f12d --- /dev/null +++ b/editor/tests/step107a_test.cpp @@ -0,0 +1,28 @@ +// Step 107a TDD Test: Text editor mode toggle persistence in BufferManager +// +// Tests: +// 1. Default mode is Structured +// 2. setBufferMode updates mode + +#include +#include +#include "BufferManager.h" + +int main() { + int passed = 0; + int failed = 0; + + BufferManager bm; + bm.openBuffer("file1", "", "python"); + assert(bm.getBufferMode("file1") == BufferManager::BufferMode::Structured); + std::cout << "Test 1 PASS: default mode structured" << std::endl; + ++passed; + + bm.setBufferMode("file1", BufferManager::BufferMode::Text); + assert(bm.getBufferMode("file1") == BufferManager::BufferMode::Text); + std::cout << "Test 2 PASS: mode updated" << std::endl; + ++passed; + + std::cout << "\n=== Step 107a Results: " << passed << " passed, " << failed << " failed ===" << std::endl; + return failed > 0 ? 1 : 0; +}