pub struct AppState {Show 32 fields
pub config: TrailConfig,
pub cwd: PathBuf,
pub launch_dir: PathBuf,
pub entries: Vec<Entry>,
pub selected: usize,
pub nav_scroll: Option<NavScroll>,
pub mode: Mode,
pub history: NavigationHistory,
pub filter: Option<FilterState>,
pub preview: PreviewSlot,
pub git: Option<GitDirState>,
pub status: StatusBarState,
pub show_hidden: bool,
pub sort: SortSettings,
pub dirty: bool,
pub selection_memory: HashMap<PathBuf, PathBuf>,
pub pending_delete: bool,
pub notice: Option<Notice>,
pub last_yank: Option<String>,
pub command_history: CommandHistory,
pub tab_state: TabState,
pub pending_nav_key: Option<char>,
pub pending_external: Option<Action>,
pub tab_manager: TabManager,
pub bookmark_store: Option<BookmarkStore>,
pub plugin_engine: Option<PluginEngine>,
pub recent_dirs: RecentDirs,
pub terminal: TerminalPanel,
pub transfers: Transfers,
pub marks: MarkSet,
pub settings: SessionSettings,
pub last_repeatable: Option<Repeatable>,
}Expand description
Central application state owned by the UI thread.
Every mutation must set dirty = true so the render loop knows to
redraw. Every render clears dirty.
Fields§
§config: TrailConfigRuntime configuration loaded from defaults plus any user TOML file.
cwd: PathBufCurrent working directory being displayed.
Always absolute, and always in the form crate::pathfmt::simplified
produces — on Windows that means no \\?\ prefix unless the path
genuinely needs one. Entry paths, the panel title, yanks and the
--cwd-file handoff are all derived from here, so normalizing this
field is what keeps the prefix out of all of them.
launch_dir: PathBufThe directory Trail was launched from — the shell’s working directory at startup, which is unaffected by navigation.
This is the base for yr (copy relative path): the point of a relative
path is that it can be pasted back into the shell that started Trail,
and that shell has not moved. Relative to cwd instead, every yank
would be the selection’s own file name, which is what yn yanks.
Canonicalized through crate::pathfmt::canonicalize, the same as
cwd and therefore as entry paths, so the two can be related
component-by-component. Both spellings have to match: relating a
\\?\C:\… base to a C:\… target would fail on the prefix component
and silently fall back to yanking the absolute path.
entries: Vec<Entry>Directory-first sorted listing of the current directory. Hidden entries are included but may be filtered from display.
selected: usizeIndex into entries of the currently highlighted item.
Where the navigation panel was scrolled to on the last frame.
Written by the renderer, which is the only thing that knows the pane
height, through crate::app::scroll::NavScroll::update. None until
the first frame.
mode: ModeCurrent interaction mode.
history: NavigationHistoryNavigation history for u/Ctrl-r back/forward.
filter: Option<FilterState>Active fuzzy-filter while in Search Mode; None otherwise.
preview: PreviewSlotCurrent preview pane content + generation counter.
git: Option<GitDirState>Git repository state for the current directory.
None before the git worker reports back or outside a git repo.
status: StatusBarStateCached status bar strings.
Whether hidden files are shown. Toggled by a keybinding (Phase 1).
sort: SortSettingsHow the active tab orders its listing.
A mirror of the active crate::app::tabs::TabState’s sort, kept
flat here for the same reason cwd and selected are: the listing code
reads it on every load_dir and should not have to go through the tab
manager to do so. save_to_active_tab and restore_from_active_tab
keep the two in step.
dirty: boolSet true on any state mutation; cleared after each render.
selection_memory: HashMap<PathBuf, PathBuf>The entry to re-select when returning to a directory visited before.
Key: the directory’s absolute path; value: the absolute path of the entry that was selected in it. A path, not an index: an index names whichever file happens to occupy that row now, so a directory whose contents changed while the user was away would come back with the selection on something else.
pending_delete: booltrue while awaiting the user’s confirmation of a dd delete.
The status bar renders a confirmation prompt while this is set.
Confirmed via Enter; cancelled via Esc.
notice: Option<Notice>The one message the status bar is currently showing, if any.
Set through AppState::notify and AppState::set_error rather than
directly, so that every message reaches the log as well as the screen.
Cleared by AppState::clear_notice on the next keystroke, which is
what makes it a flash rather than something that lingers over
directories it has nothing to do with.
last_yank: Option<String>The most-recently yanked string (set by clipboard operations).
The full text, not the summary the status bar flashes — observable in tests and the record of what the OS clipboard was handed.
command_history: CommandHistoryPersisted command history for Command Mode.
tab_state: TabStateTab-completion cycling state for Command Mode. Stored here so it survives across individual key dispatches within the same mode session.
Tracks the first key of multi-key Navigation Mode sequences:
y (for ya/yr/yn/yc) and d (for dd).
pending_external: Option<Action>A pending RunExternal action to be executed by the event loop.
Set by apply() when an editor-open or !<shell command> action is
requested. The event loop in main.rs drains this field after each
key dispatch, calling shell_exec::run_external and forcing a full
redraw. Using a state field rather than a channel keeps apply()
synchronous and testable without a running terminal.
tab_manager: TabManagerMulti-tab state manager.
The active tab’s cwd/entries/selected/history are kept in sync
with the flat AppState fields so all existing code continues to work
unchanged. On a tab switch the active state is written to the old tab
slot and read from the new one.
bookmark_store: Option<BookmarkStore>Persisted named-path bookmark registry.
None before startup initialization. Bookmark operations silently degrade when None (e.g. data directory unavailable).
plugin_engine: Option<PluginEngine>Phase 8 plugin engine for firing hooks on navigation.
recent_dirs: RecentDirsRecent directories tracker.
terminal: TerminalPanelThe terminal panel and its shells.
transfers: TransfersCopies and moves running in the background.
marks: MarkSetEntries marked for a paste, move, copy or delete. One set for every tab, so marks made in one can be pasted from another.
settings: SessionSettingsThe :set changes made this session, for :config write.
last_repeatable: Option<Repeatable>The last file operation, for @ to do again.
Implementations§
Source§impl AppState
impl AppState
Sourcepub fn new(start_path: PathBuf) -> Result<Self, StateError>
pub fn new(start_path: PathBuf) -> Result<Self, StateError>
Creates a new AppState rooted at start_path.
Loads the initial directory listing synchronously. Returns an error
if start_path cannot be read.
§Errors
Returns StateError::ReadDir if the initial directory listing fails.
Sourcepub fn with_config(
start_path: PathBuf,
config: TrailConfig,
) -> Result<Self, StateError>
pub fn with_config( start_path: PathBuf, config: TrailConfig, ) -> Result<Self, StateError>
Creates a new AppState rooted at start_path using config.
§Errors
Returns StateError::ReadDir if the initial directory listing fails.
Sourcepub fn apply_filter(&mut self, query: String)
pub fn apply_filter(&mut self, query: String)
Recomputes the fuzzy-filter against the current entries using
query, storing results sorted by descending score in
self.filter. Also auto-selects the top match (index 0).
Call this every time the query changes in Search Mode. The filter runs synchronously on the UI thread — the architecture doc designates fuzzy filtering as “fast enough not to need offloading.”
An empty query matches all entries (no score order; original listing order is preserved).
Sourcepub fn clear_filter(&mut self)
pub fn clear_filter(&mut self)
Drops the Search Mode filter, keeping the selection on the entry it was on.
While filtering, selected counts rows of the match list; without the
filter it counts rows of the full listing. Clearing the filter alone
would leave the cursor on whatever entry sits at that row, losing the
one the search found. Does not change mode. A no-op without a filter.
Sourcepub fn filtered_count(&self) -> usize
pub fn filtered_count(&self) -> usize
Returns the number of filtered-visible entries, or visible_count()
when no filter is active.
Sourcepub fn filtered_entries(&self) -> impl Iterator<Item = (usize, &Entry)>
pub fn filtered_entries(&self) -> impl Iterator<Item = (usize, &Entry)>
Returns an iterator over the entries visible given the current filter
and show_hidden flag.
When a filter is active, entries are yielded in match-score order.
When no filter is active, entries are yielded in listing order
(excluding hidden entries unless show_hidden is true).
Sourcepub fn selected_filtered_entry(&self) -> Option<&Entry>
pub fn selected_filtered_entry(&self) -> Option<&Entry>
Returns the currently selected Entry under the active filter,
or None if the visible (filtered) list is empty.
Sourcepub fn load_dir(&mut self, path: &Path) -> Result<(), StateError>
pub fn load_dir(&mut self, path: &Path) -> Result<(), StateError>
Reads and sorts the directory at path, replacing self.entries.
Sort order comes from self.sort, which is the active tab’s — see
crate::app::sort::sort_entries for the rules. Hidden entries are
always included in entries; visibility is controlled by show_hidden
at render time.
Also updates status and sets dirty.
§Errors
Returns StateError::ReadDir if the directory cannot be listed.
Sourcepub fn classify_entry(&mut self, path: &Path, is_text: bool)
pub fn classify_entry(&mut self, path: &Path, is_text: bool)
Records what a worker found out about whether path is text.
The classification is a fact about the file rather than about the current selection, so it is worth keeping even when the preview it arrived with is stale: it is what lets the next preview of the same entry go straight to the right provider instead of deferring to a worker again. Silently ignores a path that is not in the current listing.
Sourcepub fn visible_count(&self) -> usize
pub fn visible_count(&self) -> usize
Returns the number of entries that are visible given show_hidden.
Sourcepub fn visible_entries(&self) -> impl Iterator<Item = &Entry>
pub fn visible_entries(&self) -> impl Iterator<Item = &Entry>
Returns a slice of entries visible given the current show_hidden flag.
Returns an iterator rather than allocating a new Vec.
Sourcepub fn selected_entry(&self) -> Option<&Entry>
pub fn selected_entry(&self) -> Option<&Entry>
Returns the currently selected Entry, or None if the list is empty.
In Search Mode, delegates to selected_filtered_entry so the
selection is resolved against the match list rather than the raw
listing. Outside Search Mode the raw visible listing is used.
Sourcepub fn enter_dir(&mut self, path: PathBuf) -> Result<(), StateError>
pub fn enter_dir(&mut self, path: PathBuf) -> Result<(), StateError>
Navigates into the directory at path, pushing the current cwd onto
the history stack and loading the new listing.
Saves the current selection in selection_memory before navigating.
§Errors
Propagates any StateError from load_dir.
Sourcepub fn go_parent(&mut self) -> Result<(), StateError>
pub fn go_parent(&mut self) -> Result<(), StateError>
Navigates to the parent directory, if one exists.
Saves the current selection before navigating.
§Errors
Propagates any StateError from load_dir.
Sourcepub fn history_back(&mut self) -> Result<(), StateError>
pub fn history_back(&mut self) -> Result<(), StateError>
Sourcepub fn history_forward(&mut self) -> Result<(), StateError>
pub fn history_forward(&mut self) -> Result<(), StateError>
Sourcepub fn move_down(&mut self)
pub fn move_down(&mut self)
Moves the selection down by one within the visible (or filtered) list, clamping at the last entry.
Sets dirty = true if the selection changed.
Sourcepub fn move_up(&mut self)
pub fn move_up(&mut self)
Moves the selection up by one, clamping at zero.
Sets dirty = true if the selection changed.
Sourcepub fn jump_top(&mut self)
pub fn jump_top(&mut self)
Jumps the selection to the first visible entry.
Sets dirty = true if the selection changed.
Sourcepub fn jump_bottom(&mut self)
pub fn jump_bottom(&mut self)
Jumps the selection to the last visible (or filtered) entry.
Sets dirty = true if the selection changed.
Sourcepub fn scroll_preview_lines(&mut self, delta: isize)
pub fn scroll_preview_lines(&mut self, delta: isize)
Scrolls the preview pane by delta logical lines, positive for down.
Clamped to the loaded content: the first line never scrolls off the top
and the last line never scrolls off the bottom. A no-op — including for
dirty — when the content does not scroll (an image or a placeholder)
or is already at the requested edge.
Sourcepub fn scroll_preview_pages(&mut self, pages: isize)
pub fn scroll_preview_pages(&mut self, pages: isize)
Scrolls the preview pane by pages screenfuls, positive for down.
A page is the lines on screen less a two-line overlap, so consecutive pages share context. Lines are counted whole: a wrapped line takes all its rows, so a page of long lines moves fewer of them.
Sourcepub fn scroll_preview_to_edge(&mut self, to_end: bool)
pub fn scroll_preview_to_edge(&mut self, to_end: bool)
Jumps the preview pane to the end of the loaded content (to_end) or
back to its first line.
“End of the loaded content” is not necessarily the end of the file — see
PreviewSlot::truncated.
Toggles display of hidden files, keeping the selection on the same entry.
When a filter is active, re-applies it so hidden-file visibility is reflected correctly in the match list.
§Errors
Propagates any StateError from load_dir.
Sourcepub fn set_sort(&mut self, settings: SortSettings)
pub fn set_sort(&mut self, settings: SortSettings)
Re-orders the listing under settings, keeping the selection on the
same entry, and records the new order on the active tab.
Re-sorting is done in place rather than by re-listing the directory:
every sort key comes from data the entries already carry, so there is
nothing to re-read and no reason to pay for a read_dir.
Two things have to move with the order, and both are silent corruption if they do not:
- The filter’s match list holds indices into
entries(FilterState::matches), so after a re-sort every index names a different file. The filter is re-applied rather than re-indexed. - The selection is an index too, so it is resolved to a path first
and looked up again afterwards — the same rule as
toggle_hidden.
Sourcepub fn refresh(&mut self) -> Result<(), StateError>
pub fn refresh(&mut self) -> Result<(), StateError>
Reloads the current directory listing in place (e.g. after an external change or a self-initiated filesystem mutation).
Unlike enter_dir, this keeps the selection on the entry the user was on
so that R — or a filesystem-watch refresh — does not move the cursor.
Falls back to the same row when that entry is gone, which is what a
delete of the selected file wants.
§Errors
Propagates any StateError from load_dir.
Sourcepub fn notify(&mut self, text: impl Into<String>)
pub fn notify(&mut self, text: impl Into<String>)
Reports that something happened, in the status bar and in the log.
For outcomes worth seeing but not worth alarm: a yank, a bookmark, a
count of files moved. Logged at info, which the default subscriber
filter keeps, so the log file says what the user was told.
Replaces any notice already showing — the status bar holds one line, and the newest outcome is the relevant one.
Sourcepub fn set_error(&mut self, text: impl Into<String>)
pub fn set_error(&mut self, text: impl Into<String>)
Reports a failure, in the status bar and in the log.
Logged at warn rather than debug: anything the user is shown as an
error is by definition worth having in the log afterwards, and debug
is below the default filter, so those messages used to reach the screen
and nothing else.
Sourcepub fn clear_notice(&mut self) -> bool
pub fn clear_notice(&mut self) -> bool
Dismisses the current notice, if there is one.
Called on each keystroke from the event loop, before the keystroke’s own action runs — so a notice survives exactly until the user does the next thing, and an action is free to post a new one. Returns whether anything was actually dismissed, so the caller can avoid a needless redraw.
Sourcepub fn error_text(&self) -> Option<&str>
pub fn error_text(&self) -> Option<&str>
The text of the current notice when it is an error, else None.
For callers that care specifically about failure — chiefly tests asserting that an operation did or did not fail.
Sourcepub fn restore_from_active_tab(&mut self) -> Result<(), StateError>
pub fn restore_from_active_tab(&mut self) -> Result<(), StateError>
Restores the flat state from the active tab slot after switching.
§Errors
Returns StateError::ReadDir if the restored cwd can no longer be listed.
Sourcepub fn open_tab(&mut self, cwd: Option<PathBuf>) -> Result<(), StateError>
pub fn open_tab(&mut self, cwd: Option<PathBuf>) -> Result<(), StateError>
Opens a new tab rooted at cwd (or the current directory when None).
Saves the current tab’s state before switching.
§Errors
Returns StateError::ReadDir if the new tab’s directory cannot be listed.
Sourcepub fn close_tab(&mut self) -> Result<bool, StateError>
pub fn close_tab(&mut self) -> Result<bool, StateError>
Closes the active tab and restores the adjacent tab’s state.
Returns false when only one tab is open (close refused).
§Errors
Returns StateError::ReadDir if the revealed tab’s directory cannot be listed.
Sourcepub fn switch_tab_next(&mut self) -> Result<(), StateError>
pub fn switch_tab_next(&mut self) -> Result<(), StateError>
Switches to the next tab (wraps), restoring its state.
No-op when only one tab is open.
§Errors
Returns StateError::ReadDir if the target tab’s directory cannot be listed.
Sourcepub fn switch_tab_prev(&mut self) -> Result<(), StateError>
pub fn switch_tab_prev(&mut self) -> Result<(), StateError>
Switches to the previous tab (wraps), restoring its state.
No-op when only one tab is open.
§Errors
Returns StateError::ReadDir if the target tab’s directory cannot be listed.
Sourcepub fn bookmark_add(&mut self, name: String) -> Result<(), BookmarkError>
pub fn bookmark_add(&mut self, name: String) -> Result<(), BookmarkError>
Adds a bookmark named name pointing to the current directory.
No-op (logs at debug) when the bookmark store is not initialized.
§Errors
Returns BookmarkError if the store cannot be persisted.
Sourcepub fn bookmark_jump(&mut self, name: &str) -> Result<bool, StateError>
pub fn bookmark_jump(&mut self, name: &str) -> Result<bool, StateError>
Navigates to the bookmark named name.
Returns Ok(true) if the bookmark existed and navigation succeeded,
Ok(false) if no bookmark with that name exists.
§Errors
Returns StateError if the bookmarked directory cannot be listed.
Sourcepub fn return_from_jump(&mut self) -> Result<Option<usize>, StateError>
pub fn return_from_jump(&mut self) -> Result<Option<usize>, StateError>
Returns to the directory the newest jump left (U).
Walks past jumps whose directory has since disappeared, and returns
how many it skipped, so the caller can say so. Ok(None) means there
was no jump to return from. The return itself is an ordinary visit — u
comes back from it — but not a jump, so U again goes further back
rather than bouncing between two places.
§Errors
Returns StateError if the directory exists but cannot be listed.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for AppState
impl !Send for AppState
impl !Sync for AppState
impl !UnwindSafe for AppState
impl Freeze for AppState
impl Unpin for AppState
impl UnsafeUnpin for AppState
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
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> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
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