Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions PROJECT_STATE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# VimCode Project State

**Last updated:** May 8, 2026 (Session 359 — **Source Control panel → SidebarSystem** complete (#321/#339/#340). Three-issue migration mirroring the Extensions sidebar pattern. Unified `dispatch_sc_sidebar_key_unified()` eliminates all per-backend key mapping. `sc_set_focus()` + `sc_button_hit_test()` deduplicate focus sync and button click math. Section badges via quadraui#103 (`set_section_badge`/`set_section_visible`). Net ~340 lines removed across the migration.)
**Last updated:** May 10, 2026 (Session 360 — **Search panel → SidebarSystem** (#323/#333/#334, PR #342). 2-section SidebarSystem (Form + Tree) via quadraui#105 `SectionKind::Form`. Unified `dispatch_search_sidebar_key_unified()` for all 3 backends. 6 quadraui issues filed and resolved (#105/#107/#109/#110/#112/#116). `search_set_focus()` + `search_switch_to_results()` deduplicate 6 activation sites. Net -120 lines.)

## Active milestone: Cross-Platform UI Crate

Expand All @@ -18,23 +18,21 @@
| [#315](https://github.com/JDonaghy/vimcode/issues/315) | GTK MSV scrollbar drag-to-scroll | Polish |
| [#294](https://github.com/JDonaghy/vimcode/issues/294) | quadraui MSV horizontal axis rasterisers | Infrastructure |
| [#312](https://github.com/JDonaghy/vimcode/issues/312) | Ctrl-Shift-F visual selection prepopulate | Feature |
| [#333](https://github.com/JDonaghy/vimcode/issues/333) | TUI: remove duplicate search panel focus state | Cleanup |
| [#334](https://github.com/JDonaghy/vimcode/issues/334) | Unify search panel results-mode behavior | Polish |
| [#331](https://github.com/JDonaghy/vimcode/issues/331) | GTK debug toolbar → StatusBarInteraction | Cleanup (blocked on GTK UiEvent migration) |

**Shipped this session (359):**
- **#321 SC sidebar: engine + render layer** (Path A) — Added `sc_sidebar_system: Rc<RefCell<SidebarSystem>>` with 4 sections (Staged/Changes/Worktrees/Log), WholePanel scroll, Selection nav, collapsible. `populate_sc_sidebar_system(engine, theme)` builds TreeRows with git status colors + section badges. `dispatch_sc_sidebar_key_unified()` + `ScKeyResult` provides single entry point for both backends. `dispatch_sc_sidebar_event()` + `dispatch_sc_action_key()` + `sc_activate_row()` for domain actions. `handle_sc_sidebar_ui_event()` for mouse/scroll. 8 new tests.
- **#339 SC sidebar: TUI → SidebarSystem** (Path A) — Replaced TreeView section rendering with `SidebarSystem.render()`, 80-line manual key mapping with `dispatch_sc_sidebar_key_unified()`, flat-index scroll/click with `handle_sc_sidebar_ui_event()`. Domain actions read selection from SidebarSystem. Fixed Shift+key with Kitty keyboard enhancement. Net -40 lines TUI.
- **#340 SC sidebar: GTK → SidebarSystem + dedup** (PR #341) — GTK section rendering, key dispatch (both `Msg::KeyPress` and `Msg::ScKey`), and 60-line click accumulator walk all replaced with SidebarSystem. `wire_da_events` wired for scroll/scrollbar drag. GDK `question`/`slash` key name mapping fixed. `Engine::sc_set_focus(bool)` deduplicates 10+ manual dual-set sites. `Engine::sc_button_hit_test()` shares button layout math. `sc_open_selected_async` gated behind `#[cfg(feature = "win-gui")]`. `sc_stage_all` error now surfaced in status bar. Net -200 lines GTK.
- **quadraui issues filed + resolved:** #103 (section visibility + header badges).
**Shipped this session (360):**
- **#323 Search panel → SidebarSystem** (PR #342) — 2-section SidebarSystem (Form + Tree) via quadraui#105 `SectionKind::Form`. `populate_search_sidebar_system()` builds Form (query/replace/toggles/buttons/status) + TreeRows (file-grouped results with collapse). Unified `dispatch_search_sidebar_key_unified()` for TUI/GTK/Win-GUI. `search_set_focus()` + `search_switch_to_results()` deduplicate 6 activation sites. Removed `project_search_selected`, `search_file_expanded`, `search_panel_msv_layout`, `build_search_panel_msv()`. Toggles auto-rerun search. GTK: `alt` on `Msg::KeyPress`, `search_has_focus` routing, `wire_da_events`, `ISO_Left_Tab` → `BackTab`. 4 new tests.
- **#333 TUI duplicate search focus** — `search_input_mode`, `replace_input_focused`, `search_scroll_top` removed from TuiSidebar. Engine `search_panel_form_focus` is single source of truth.
- **#334 Cross-backend search behavior** — Printable char in results mode re-enters form input on all backends.
- **quadraui issues filed + resolved:** #105 (Form sections in SidebarSystem), #107 (Form click event semantics), #109 (GTK empty TextInput cursor), #110 (tree header click precision), #112 (ToggleGroup/ButtonRow per-item click), #116 (Form hit region drift).

---

**Previous sessions (358 and earlier):** in SESSION_HISTORY.md.
**Previous sessions (359 and earlier):** in SESSION_HISTORY.md.

Vimcode at 1954 lib tests passing. All on develop — no active branches.
Vimcode at 1957 lib tests passing. PR #342 open on `issue-323-search-sidebar-system`.

> Sessions 359 and earlier in **SESSION_HISTORY.md**.
> Sessions 360 and earlier in **SESSION_HISTORY.md**.

> Feature documentation lives in **README.md**.
> Per-session implementation notes through Session 348 are in **SESSION_HISTORY.md**.
Expand Down Expand Up @@ -109,7 +107,7 @@ cell coalescence) remain but are tracked separately.
| Terminal toolbar (find bar + tab strip) | `StatusBar` / `TabBar` | ✅ | ✅ | #305, `08dd916`. Adapter `render::build_terminal_toolbar`. Click via `Engine::resolve_terminal_toolbar_click`. Tab strip uses `compact: true`. |
| Menu bar labels | `MenuSystem` | ✅ | ✅ | #319. `quadraui::MenuSystem` owns all state + rendering. `MenuOverlay` helper for GTK overlay DA. |
| Command center (nav arrows + search box) | `CommandCenter` | ✅ | ✅ | #310, `b5fdd7d`. Adapter `render::build_command_center_view`. Click via `CommandCenterLayout::hit_test`. |
| Search panel (chrome + results) | `MSV` + `Form` + `TreeView` | ✅ | ✅ | #302, `de625bb`. Adapter `render::build_search_panel_msv`. Form: query/replace TextInput + ToggleGroup + ButtonRow. Tree: file-grouped results. Click via `backend.form_layout`/`backend.tree_layout`. Replace All has confirmation dialog. |
| Search panel (chrome + results) | `SidebarSystem` (Form + Tree) | ✅ | ✅ | #323/#333/#334. `populate_search_sidebar_system` + `SidebarSystem.render()`. Unified dispatch via `dispatch_search_sidebar_key_unified`. Form: query/replace TextInput + ToggleGroup + ButtonRow. Tree: file-grouped results with collapse. |

**Cross-backend logic-sharing** (where one implementation drives both backends):

Expand All @@ -120,7 +118,7 @@ cell coalescence) remain but are tracked separately.
- All `*_to_form` / `*_to_tree_view` / `lsp_status_for_buffer` adapters in `render.rs` and `core/engine/`.
- `quadraui::MenuSystem` — menu bar + dropdown lifecycle (open/close, keyboard nav, hover-to-switch, modal stack). Both backends call `render()` and `handle()` with zero per-backend menu logic. GTK uses `MenuOverlay` helper for the titlebar DA overlay wiring.
- `quadraui::TreeController` — explorer file tree: selection, scroll, keyboard nav, inline editing (rename + new-file/folder). Both backends call `render()` for drawing and `_via` methods for keyboard editing. All domain logic in `engine/explorer_ops.rs`.
- `quadraui::SidebarSystem` — extensions sidebar (#336/#337/#338) and source control panel (#321/#339/#340): section selection, scroll, keyboard nav, mouse handling, collapse, badges, visibility. Both backends call `populate_*()` + `render()` and `dispatch_*_key_unified()`. Zero per-backend nav/click code.
- `quadraui::SidebarSystem` — extensions sidebar (#336/#337/#338), source control panel (#321/#339/#340), and search panel (#323/#333/#334): section selection, scroll, keyboard nav, mouse handling, collapse, badges, visibility. Search panel uses `SectionKind::Form` for the chrome section (quadraui#105). Both backends call `populate_*()` + `render()` and `dispatch_*_key_unified()`. Zero per-backend nav/click code.
- `quadraui::StatusBarInteraction` — debug toolbar hover/press state. TUI uses it via UiEvent intercept; GTK still manual (#331).

**North-star ("developer doesn't need to know the backend") status after B.5:**
Expand All @@ -136,4 +134,4 @@ cell coalescence) remain but are tracked separately.

## Recent Work

> Sessions 351 and earlier in **SESSION_HISTORY.md**.
> Sessions 360 and earlier in **SESSION_HISTORY.md**.
7 changes: 6 additions & 1 deletion SESSION_HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# VimCode Session History

Detailed per-session implementation notes archived from PROJECT_STATE.md.
All sessions through 359 archived here.
All sessions through 360 archived here.

---
**Session 360 (May 9–10) — Search panel → SidebarSystem (#323/#333/#334, PR #342):**

Migrated search panel from hand-rolled MSV to 2-section `SidebarSystem` (Form + Tree), following the SC sidebar pattern from Session 359. Filed and resolved 6 quadraui prerequisite issues: #105 (Form section support in SidebarSystem), #107 (Form click event semantics), #109 (GTK empty TextInput cursor), #110 (tree header click precision), #112 (ToggleGroup/ButtonRow per-item click), #116 (Form hit region drift from rendered positions). **#323** (core migration): Added `search_sidebar_system: Rc<RefCell<SidebarSystem>>` with 2 sections (`SidebarSectionDef::form("chrome", "SEARCH")` + `SidebarSectionDef::new("results", "RESULTS")`), `search_sidebar_body_rect: Cell<Rect>`, `search_collapsed_files: RefCell<HashSet<usize>>`. `populate_search_sidebar_system(engine, root)` in render.rs builds Form (query/replace TextInputs, ToggleGroup, ButtonRow, status) for section 0 and TreeRows (file-grouped results with expand/collapse) for section 1. Unified `dispatch_search_sidebar_key_unified(key, ctrl, alt, unicode) -> SearchKeyResult` — single entry point for all 3 backends. `dispatch_search_sidebar_event()` handles `RowActivated`/`RowSelected`/`FormEvent` (FocusChanged/ToggleChanged/ButtonClicked). `handle_search_sidebar_ui_event()` for mouse/scroll. `search_selected_result_idx()` derives flat index from SidebarSystem selection. `search_set_focus(bool)` deduplicates 6 activation sites across TUI/GTK/Win-GUI. `search_switch_to_results()` deduplicates poll_project_search result-mode switch. Removed engine fields: `project_search_selected`, `search_file_expanded`, `search_panel_msv_layout`. Removed `build_search_panel_msv()` + `result_idx_to_tree_path()` from render.rs. Toggles auto-rerun search when results exist. 4 new tests. **#333** (TUI duplicate focus): Removed `TuiSidebar::search_input_mode`, `replace_input_focused`, `search_scroll_top` — engine's `search_panel_form_focus` is single source of truth. **#334** (cross-backend behavior): Printable char in results mode re-enters form input on all backends via unified dispatch. **GTK fixes**: Added `alt: bool` to `Msg::KeyPress` (all 7 senders updated). Added `search_has_focus` routing in `handle_key_press` (was missing — keys only came through DA's EventControllerKey without ctrl/alt). `wire_da_events` replaces manual GestureClick for scroll/drag/click. `ISO_Left_Tab` → `BackTab` mapping. `search_has_focus = true` in `SwitchPanel`/`ToggleFocusSearch` (was missing). `ClipboardPasteToInput` handles search panel paste. `poll_project_search` switches to results mode. **TUI fixes**: `set_backend_info` for search sidebar. Scroll wheel + drag + mouseup routed through SidebarSystem. **Win-GUI**: Migrated to unified dispatch. Net -120 lines across 12 files.

---
**Session 359 (May 8) — Source Control panel → SidebarSystem (#321/#339/#340):**
Expand Down
30 changes: 19 additions & 11 deletions src/core/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2434,8 +2434,6 @@ pub struct Engine {
pub project_search_query: String,
/// Results from the last `run_project_search` call.
pub project_search_results: Vec<ProjectMatch>,
/// Index of the currently highlighted result (0-based).
pub project_search_selected: usize,
/// Search mode toggles (case-sensitive, whole word, regex).
pub project_search_options: SearchOptions,
/// Receiver for async search results (set while a search thread is running).
Expand All @@ -2454,12 +2452,9 @@ pub struct Engine {
pub project_replace_running: bool,
/// Search-specific status message ("N matches in M files").
pub project_search_status: String,
/// Per-file collapse state in search results. Indexed by file group order.
pub search_file_expanded: Vec<bool>,
/// Cached MSV layout from the last search panel paint. Written at paint time.
pub search_panel_msv_layout: std::cell::RefCell<Option<quadraui::MultiSectionViewLayout>>,
/// File indices that are collapsed in search results (toggled by clicking headers).
pub search_collapsed_files: std::cell::RefCell<std::collections::HashSet<usize>>,
/// Which form field in the search panel has focus (widget ID string).
/// Written at paint time from TUI sidebar state.
pub search_panel_form_focus: std::cell::RefCell<Option<String>>,
/// Cursor position (char offset) in the search query input.
pub search_query_caret: std::cell::Cell<usize>,
Expand Down Expand Up @@ -2560,6 +2555,11 @@ pub struct Engine {
pub explorer_has_focus: bool,
/// Whether the Search sidebar panel has keyboard focus.
pub search_has_focus: bool,
/// quadraui SidebarSystem — owns Search panel (2 sections: Form chrome +
/// Tree results) selection, scroll, keyboard nav, and mouse handling.
/// Both TUI and GTK call `render()` and `handle()`.
pub search_sidebar_system: std::rc::Rc<std::cell::RefCell<quadraui::SidebarSystem>>,
pub search_sidebar_body_rect: std::cell::Cell<quadraui::Rect>,

// --- Source Control panel ---
/// Cached file statuses from the last `sc_refresh()` call.
Expand Down Expand Up @@ -3404,16 +3404,14 @@ impl Engine {
completion_display_only: false,
project_search_query: String::new(),
project_search_results: Vec::new(),
project_search_selected: 0,
project_search_options: SearchOptions::default(),
project_search_receiver: None,
project_search_running: false,
project_replace_text: String::new(),
project_replace_receiver: None,
project_replace_running: false,
project_search_status: String::new(),
search_file_expanded: Vec::new(),
search_panel_msv_layout: std::cell::RefCell::new(None),
search_collapsed_files: std::cell::RefCell::new(std::collections::HashSet::new()),
search_panel_form_focus: std::cell::RefCell::new(Some("search:query".to_string())),
search_query_caret: std::cell::Cell::new(0),
replace_text_caret: std::cell::Cell::new(0),
Expand Down Expand Up @@ -3466,6 +3464,16 @@ impl Engine {
base_settings: None,
explorer_has_focus: false,
search_has_focus: false,
search_sidebar_system: {
let mut s = quadraui::SidebarSystem::new(vec![
quadraui::SidebarSectionDef::form("chrome", "SEARCH"),
quadraui::SidebarSectionDef::new("results", "RESULTS"),
]);
s.set_navigation_mode(quadraui::NavigationMode::Selection);
s.set_allow_collapse(false);
std::rc::Rc::new(std::cell::RefCell::new(s))
},
search_sidebar_body_rect: std::cell::Cell::new(quadraui::Rect::new(0.0, 0.0, 0.0, 0.0)),
sc_file_statuses: Vec::new(),
sc_worktrees: Vec::new(),
sc_selected: 0,
Expand Down Expand Up @@ -4513,7 +4521,7 @@ mod panels;
mod picker;
mod plugins;
mod search;
pub use search::{find_word_boundaries, SearchInputAction};
pub use search::{find_word_boundaries, SearchKeyResult};
mod source_control;
pub use source_control::ScKeyResult;
mod spell_ops;
Expand Down
Loading