Skip to main content

AppState

Struct AppState 

Source
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: TrailConfig

Runtime configuration loaded from defaults plus any user TOML file.

§cwd: PathBuf

Current 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: PathBuf

The 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: usize

Index into entries of the currently highlighted item.

§nav_scroll: Option<NavScroll>

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: Mode

Current interaction mode.

§history: NavigationHistory

Navigation history for u/Ctrl-r back/forward.

§filter: Option<FilterState>

Active fuzzy-filter while in Search Mode; None otherwise.

§preview: PreviewSlot

Current 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: StatusBarState

Cached status bar strings.

§show_hidden: bool

Whether hidden files are shown. Toggled by a keybinding (Phase 1).

§sort: SortSettings

How 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: bool

Set 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: bool

true 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: CommandHistory

Persisted command history for Command Mode.

§tab_state: TabState

Tab-completion cycling state for Command Mode. Stored here so it survives across individual key dispatches within the same mode session.

§pending_nav_key: Option<char>

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: TabManager

Multi-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: RecentDirs

Recent directories tracker.

§terminal: TerminalPanel

The terminal panel and its shells.

§transfers: Transfers

Copies and moves running in the background.

§marks: MarkSet

Entries marked for a paste, move, copy or delete. One set for every tab, so marks made in one can be pasted from another.

§settings: SessionSettings

The :set changes made this session, for :config write.

§last_repeatable: Option<Repeatable>

The last file operation, for @ to do again.

Implementations§

Source§

impl AppState

Source

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.

Source

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.

Source

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).

Source

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.

Source

pub fn filtered_count(&self) -> usize

Returns the number of filtered-visible entries, or visible_count() when no filter is active.

Source

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).

Source

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.

Source

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.

Source

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.

Source

pub fn visible_count(&self) -> usize

Returns the number of entries that are visible given show_hidden.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn history_back(&mut self) -> Result<(), StateError>

Navigates backward in history (bound to u).

§Errors

Propagates any StateError from load_dir.

Source

pub fn history_forward(&mut self) -> Result<(), StateError>

Navigates forward in history (bound to Ctrl-r).

§Errors

Propagates any StateError from load_dir.

Source

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.

Source

pub fn move_up(&mut self)

Moves the selection up by one, clamping at zero.

Sets dirty = true if the selection changed.

Source

pub fn jump_top(&mut self)

Jumps the selection to the first visible entry.

Sets dirty = true if the selection changed.

Source

pub fn jump_bottom(&mut self)

Jumps the selection to the last visible (or filtered) entry.

Sets dirty = true if the selection changed.

Source

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.

Source

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.

Source

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.

Source

pub fn toggle_hidden(&mut self) -> Result<(), StateError>

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.

Source

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.
Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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§

Source§

impl Debug for AppState

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &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> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more