Filesystem candidate provider
The library's rev::file::completion module owns explicit directory observations
for path completion. It does not open editing buffers or create files.
| API | Contract |
|---|---|
Query::parse(base, home, draft) |
Split literal path text into an absolute directory and a component prefix without IO or environment access. |
Query::directory(), Query::prefix() |
Retain the requested directory component and exact UTF-8 filter text. |
Provider::observe(directory) |
Read one explicitly supplied absolute directory into a bounded, sorted snapshot. |
Provider::matching(prefix) |
Filter retained names by case-sensitive literal byte prefix, without filesystem access. |
Provider::refresh() |
Explicitly reread the same directory; replace the snapshot only on success. |
Provider::entries(), Provider::directory() |
Expose the retained entries and their directory identity without IO. |
Provider::name_bytes(), Provider::diagnostic() |
Report retained raw name bytes and any incomplete-list indication. |
Candidate::name(), Candidate::path() |
Expose the exact supported name and original opening path, independently of presentation. |
Candidate::label() |
Return a terminal-safe full label; display clipping must not change opening identity. |
Candidate::is_directory(), Candidate::is_symlink() |
Expose the entry's observed type without following child symlinks. |
Find-file navigation
Navigation::new(base, home) owns a single component snapshot, editable draft,
selection and scroll origin. update(draft, false) changes the filter and resets
selection only after an actual text change. A directory transition observes the
new component; cursor movement and redraw do not refresh it.
navigate(previous) moves a bounded selection without changing the draft.
complete() explicitly refreshes and returns the highlighted full name, including
the default first match of an ambiguous prefix. Selected raw identities survive
sorting shifts. A missing selected name or failed observation retains the previous
snapshot and reports an error; repeated Tab cannot substitute another row. A
successful refresh can retry the same identity after access or the name returns.
Directories retain a trailing separator. The prompt owner enforces the configured
scalar bound before installing text. Incomplete snapshots keep their diagnostic;
Tab fills an observed identity without claiming that the list is complete or the
match unique. Unsupported names never become replacement opening paths.
requested_rows(limit), reveal(rows), selected() and top() provide presentation
state for the common completion panel. Diagnostics reserve a visible row within
that limit; zero candidate rows retain selection and origin. The common display
owner clips labels independently of paths. typed_path() resolves the retained
literal draft against its explicit roots.
Native Return resolves the explicitly navigated candidate from its original path; without navigation it uses the literal draft, including new names. Acceptance checks only that requested identity, following symlinks there rather than during listing. The session prepares an accepted directory's bounded tree observation before closing the prompt and replacing its browsing context. An empty draft accepts the prompt base. Files pass to the existing canonical visit owner. Missing selected paths, unsupported encodings, denied access and file ingress errors retain the prompt and active buffer. Observation, completion and acceptance never publish saves or create filesystem entries.
Queries and identity
Relative text uses the explicit absolute base. An absolute draft supplies its own
directory. ./ and ../ retain OS path semantics, including parents reached
through symlinks. A trailing slash leaves an empty component prefix.
Only leading ~/ expands, using the caller's explicit absolute home directory.
Missing or relative home roots reject that expansion. Other tilde forms,
variables, glob characters, backticks and shell-looking text remain literal.
Spaces and Unicode retain their exact bytes. NUL and a relative base reject with
InvalidInput. Parsing does not require the requested directory to exist.
Candidate paths are retained independently of labels. Directory labels end in
/; the marker is not appended to the opening path. Control characters are
escaped in labels, while ordinary Unicode remains intact. The display owner can
clip these labels at whole-grapheme boundaries without modifying path identity.
Non-UTF-8 names remain visible with an unsupported non-UTF-8 filename indication.
Their name() is None, and path() returns InvalidData; no lossy replacement
path is offered. Raw bytes still participate in ordering and prefix filtering.
Observation and limits
Every observation processes at most 4096 entries and retains at most 512 KiB of candidate-name bytes. A name that cannot fit ends observation before its type or candidate is retained. Reaching either exact limit also marks the list incomplete without peeking at another entry. The diagnostic is:
Incomplete candidate list: directory observation limit reached
An incomplete snapshot contains the bounded portion returned by directory enumeration, sorted after observation. It does not claim to contain the first 4096 names of a fully sorted, unbounded directory listing.
Directories precede other entries; each group sorts by case-sensitive filename
bytes. Hidden names are included. Matching is a literal prefix operation;
minibuffer.match remains a command-candidate preference.
Only the current directory is enumerated. Child directories are not read, and directory, dangling and looping child symlinks remain leaves. An explicitly requested directory path can itself contain symlink components; their destinations are not resolved speculatively from listed children.
Filtering, label access and entry/type access use cached memory. Changes on disk become visible only through a new observation or explicit refresh. IO failures retain their error kind and requested-directory context. Failed refresh preserves the previous snapshot and its directory identity. There is no watcher or background traversal.