pub struct SidebarState {
pub open: bool,
pub position: SidebarPosition,
pub orientation: SidebarOrientation,
pub focused: bool,
pub scroll: u16,
pub max_scroll: u16,
pub cache: Option<((PathBuf, SidebarMode), SidebarSections)>,
pub mode: SidebarMode,
}Expand description
Pure sidebar state. Use Self::new (or the Default impl below)
to get the initial state that matches the previous App::new_at
behaviour (open + unfocused + zero scroll + cold cache) — the
#[derive(Default)] Copilot would normally synthesise here would
set open = false, which contradicts both the doc above and
new(). The hand-written Default keeps the contract single-sourced.
Fields§
§open: booltrue when the sidebar is visible. On a narrow terminal the
renderer no longer hides it (pre-#188 behaviour) but stacks it
under the table instead — see Self::resolve_layout. Closing
the panel (open = false) is the only way to reclaim the full
width for the table.
position: SidebarPositionWhich side the sidebar sits on in the side-by-side layout
(issue #188). Seeded from [tui] sidebar_position at App
construction, toggled live by Self::toggle_position (H).
Ignored by the stacked layout (sidebar always at the bottom).
orientation: SidebarOrientationHow the sidebar is arranged relative to the table (issue #188).
Defaults to SidebarOrientation::Auto (width-driven); cycled
by Self::cycle_orientation (V). Runtime-only — not persisted
to .gwm.toml, unlike position.
focused: booltrue when keyboard navigation (j / k) targets the sidebar
(scrolling Recent Commits) instead of the worktree list.
Invariant: focused is false whenever open is false.
scroll: u16First-visible line index of the Recent Commits section. Bumped
by Self::scroll_down / Self::scroll_up; reset to 0 by
Self::on_navigation.
max_scroll: u16Upper bound for scroll, republished by the renderer every
frame against the actual rendered Recent Commits height. Used
by Self::scroll_down to clamp so the panel content can never
be pushed entirely off-screen.
cache: Option<((PathBuf, SidebarMode), SidebarSections)>Cached pre-rendered sections keyed by the selected worktree’s
path and the active mode (issue #34). None = cold cache
(the renderer will rebuild and store). Invalidated on selection
change (Self::on_navigation), worktree list mutation
(App::refresh calls Self::invalidate), filter narrowing
(App::filter_push_char / filter_pop_char), and mode toggle
(Self::cycle_mode). Two-tuple key so a re-toggle re-shells
git stash list / git log rather than serving stale content
for the other mode.
mode: SidebarModeActive preview mode. Defaults to SidebarMode::Commits so the
pre-#34 sidebar behaviour is unchanged until the user presses
s. Toggled by Self::cycle_mode.
Implementations§
Source§impl SidebarState
impl SidebarState
pub fn new() -> Self
Sourcepub fn resolve_layout(&self, width: u16) -> ResolvedSidebarLayout
pub fn resolve_layout(&self, width: u16) -> ResolvedSidebarLayout
Resolve the concrete layout for a frame of width columns from
the current visibility, orientation, and position. Pure and
ratatui-free so the width contract is unit-testable:
- closed →
ResolvedSidebarLayout::Hidden; Auto→ side-by-side atwidth >= SIDEBAR_MIN_WIDTH, else stacked;SideBySide/Stacked→ that layout regardless of width.
In a side-by-side result sidebar_left mirrors Self::position.
Sourcepub fn cycle_orientation(&mut self)
pub fn cycle_orientation(&mut self)
Cycle the orientation Auto → SideBySide → Stacked → Auto
(issue #188, V). The cache survives — orientation changes the
frame geometry, not the previewed git content.
Sourcepub fn toggle_position(&mut self)
pub fn toggle_position(&mut self)
Flip the side-by-side position left ↔ right (issue #188, H).
The cache survives for the same reason as Self::cycle_orientation.
Sourcepub fn cycle_mode(&mut self)
pub fn cycle_mode(&mut self)
Cycle the preview mode (issue #34). Pre-#34 the sidebar only
ever showed git log + git status; now s flips between
Commits and Stashes. The scroll offset resets to 0 because
the new content has its own length and the previous offset
becomes meaningless. The cache is invalidated because the key
(path + mode) changes — the new mode re-shells the right git
command on the next frame.
Navigation-driven reset: drop the scroll back to the top AND
invalidate the cache so the new selection’s preview renders fresh.
Paired with App::refresh_link() inside App::on_navigation to
collapse the pre-extraction sidebar_scroll = 0; invalidate_sidebar_cache(); refresh_link(); triple that the
App body repeated 4+ times across next / prev / first /
last.
Deliberately does NOT touch open, focused, or max_scroll:
navigation moves selection within the existing layout; visibility
is a separate concern owned by the toggle methods, and
max_scroll is owned by the renderer (a stale value resets
itself on the next frame anyway).
Sourcepub fn invalidate(&mut self)
pub fn invalidate(&mut self)
Standalone cache flush. Used outside the navigation path —
App::refresh after the worktrees list mutates, and the filter
push_char / pop_char wrappers that re-narrow the visible set
without moving the cursor. Scroll state survives so a user
scrolled halfway through the preview keeps their viewport.
Sourcepub fn scroll_down(&mut self)
pub fn scroll_down(&mut self)
Scroll the Recent Commits viewport down by one line, clamped at
max_scroll. The clamp is the load-bearing invariant — without
it, j on a focused sidebar would walk the content entirely off
the bottom of the panel.
Sourcepub fn scroll_up(&mut self)
pub fn scroll_up(&mut self)
Scroll the Recent Commits viewport up by one line, saturating at
0. Matches k-on-sidebar; safe to call from scroll == 0.
Sourcepub fn toggle_open(&mut self)
pub fn toggle_open(&mut self)
Flip open. When closing, also drops focused — a hidden
sidebar can never hold the navigation focus, so the worktree
list takes back j / k automatically. Status-bar copy is the
App orchestrator’s concern.
Sourcepub fn toggle_focus(&mut self)
pub fn toggle_focus(&mut self)
Flip focused. No-op when the sidebar is closed — focus cannot
move to a hidden panel. Matches the Tab keybinding semantics.
Sourcepub fn focus_table(&mut self)
pub fn focus_table(&mut self)
Direct-focus the worktree table (issue #217, 1). Releases the
sidebar’s navigation focus so j / k walk the worktree list. The
sidebar stays open — 1 is about where the cursor is, not
visibility (that’s v / Self::toggle_open).
Sourcepub fn focus_panel(&mut self)
pub fn focus_panel(&mut self)
Direct-focus the status (sidebar) pane (issue #217, 2). Opens the
sidebar if it was closed and moves the navigation focus onto it, so a
single keystroke both reveals and targets the pane.
Trait Implementations§
Source§impl Debug for SidebarState
impl Debug for SidebarState
Auto Trait Implementations§
impl Freeze for SidebarState
impl RefUnwindSafe for SidebarState
impl Send for SidebarState
impl Sync for SidebarState
impl Unpin for SidebarState
impl UnsafeUnpin for SidebarState
impl UnwindSafe for SidebarState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more