pub struct DirPickSource {
pub spec: PickerSourceSpec,
}Expand description
PC.9: dir-pick — FilePickSource’s directory peer. Browse to a
directory and supply its path as a value.
§Incremental, not a walk
The candidates are the children of the directory the query names, filtered
by the basename it ends with — gen:directories’ model, which is what
emacs’s read-directory-name does. It shares the implementation with that
generator (lattice_completion::builtins::generators::path_entries)
rather than copying it, so <Tab> on the : line and this picker cannot
disagree about what listing a path means.
walk_files_for_picker with directories instead of files was the obvious
alternative and is the wrong one here: it has no depth cap and a flat
FILE_PICKER_MAX_ENTRIES ceiling, so pointed anywhere near a home
directory it stops somewhere arbitrary and the directory you wanted may
simply not be in the list. Incremental has no ceiling, reaches any depth,
and opens in one read_dir.
§It starts at HOME, where file-pick starts at the workspace root
Not an inconsistency. Picking a file is nearly always picking one in the project you are in, so the workspace root is the useful default. Picking a directory is nearly always about going somewhere you are not — the motivating case is choosing a project you have never opened — and rooting that at the project you are already in would make the common case start in the one place it does not want.
An explicit start argument still wins, and :picker dir-pick . is the
spelling for “here”.
§Tilde survives into the rows on purpose
A row’s text keeps whatever spelling the query used (~/src/…), because
that is what the user is reading and typing against, and descending
re-lists from it unchanged. The value handed back on accept is the
expanded absolute path off CandidateData::File, because a consumer
resolving it has no obligation to know about ~.
Fields§
§spec: PickerSourceSpecImplementations§
Source§impl DirPickSource
impl DirPickSource
pub fn new() -> DirPickSource
Trait Implementations§
Source§impl Default for DirPickSource
impl Default for DirPickSource
Source§fn default() -> DirPickSource
fn default() -> DirPickSource
Source§impl PickerSourceGenerator for DirPickSource
impl PickerSourceGenerator for DirPickSource
Source§fn on_query_changed(
&self,
_ctx: &PickerContext<'_>,
query: &str,
) -> Option<Result<PickerInitResult, String>>
fn on_query_changed( &self, _ctx: &PickerContext<'_>, query: &str, ) -> Option<Result<PickerInitResult, String>>
Re-list on every keystroke. An unreadable query yields an EMPTY list, not an error: half a typed path names nothing yet, and that is the state the user is in for most of the keystrokes — erroring on it would mean the picker spends its life reporting failure.
Source§fn descend(
&self,
_ctx: &PickerContext<'_>,
candidate: &RawCandidate,
) -> Option<String>
fn descend( &self, _ctx: &PickerContext<'_>, candidate: &RawCandidate, ) -> Option<String>
<C-l>: the selected row’s own text becomes the query, so the next
listing is of its children. It already ends in / — path_entries
puts one on every directory — which is exactly the prefix that lists a
directory’s contents rather than its siblings.
PP.3: <CR> on ../ GOES UP. It does not choose the parent.
PP.1 shipped the other reading — ../ is an ordinary row, so <CR>
supplies its path like every other row does — and it was wrong in the
way that only shows up in use. ../ reads as a verb, every file
browser there is (netrw, oil, ranger, lf, telescope-file-browser)
treats <CR> on .. as “go up”, and the UX-convention rule says
muscle memory wins on a surface like this one.
What it looked like in practice: <CR> on ../ at ~/ supplied
/Users, which the project flow then refused — an error message where
the user had asked to go up a level.
Only this row. Every other row in this picker is a directory you might
be choosing, and <CR> still chooses it.
Source§fn ascend(&self, query: &str) -> Option<String>
fn ascend(&self, query: &str) -> Option<String>
<C-w>: drop the last path component.
parent_of does the work, shared with the ../
row so the key and the row cannot land in different places. / stays
a fixed point — parent_of answers None there, and this returns the
query unchanged so the host recognises it and spends no re-query.
Source§fn initial_query(&self, args: &[String]) -> Option<String>
fn initial_query(&self, args: &[String]) -> Option<String>
PP.1: open on the start directory rather than on an empty query.
The query IS the directory being listed here, so an empty one leaves the prompt unable to say where you are — every row carries a path and the one line meant to orient you carries nothing. It also left ascend with no last component to drop, so the first press did nothing and the second worked.
The trailing / is what makes it a LISTING rather than a filter:
path_entries("~/src") lists ~’s children whose names start with
src, where path_entries("~/src/") lists what is inside. Seeding
the un-slashed form is the bug this normalisation exists to prevent,
and :picker dir-pick /tmp walked straight into it.
Source§fn spec(&self) -> &PickerSourceSpec
fn spec(&self) -> &PickerSourceSpec
:describe-picker /
:picker <Tab> listings without cloning.Source§fn init(
&self,
_ctx: &PickerContext<'_>,
args: &[String],
) -> Result<PickerInitResult, String>
fn init( &self, _ctx: &PickerContext<'_>, args: &[String], ) -> Result<PickerInitResult, String>
ctx, clone into async captures if
necessary, return the appropriate PickerInitResult
variant. Synchronous errors (no active buffer when
one was required, args validation failure) return
Err; the host echoes the error and leaves the
picker closed. Read moreSource§fn accept(
&self,
_ctx: &PickerContext<'_>,
routing: &RoutingPayload,
) -> Result<PickerAcceptOutcome, String>
fn accept( &self, _ctx: &PickerContext<'_>, routing: &RoutingPayload, ) -> Result<PickerAcceptOutcome, String>
PickerAcceptOutcome the host applies. The
generator owns the mapping from its emitted
routing-payload variant(s) to outcome(s); mismatch
returns Err, which the host echoes.Source§fn accept_async(
&self,
_ctx: &PickerContext<'_>,
_routing: &RoutingPayload,
) -> Option<Pin<Box<dyn Future<Output = Result<PickerAcceptOutcome, String>> + Send>>>
fn accept_async( &self, _ctx: &PickerContext<'_>, _routing: &RoutingPayload, ) -> Option<Pin<Box<dyn Future<Output = Result<PickerAcceptOutcome, String>> + Send>>>
None means “this source resolves accept
synchronously” — every native source takes this path and is unchanged. Read moreSource§fn preview(
&self,
_ctx: &PickerContext<'_>,
_routing: &RoutingPayload,
) -> Option<PickerPreviewOutcome>
fn preview( &self, _ctx: &PickerContext<'_>, _routing: &RoutingPayload, ) -> Option<PickerPreviewOutcome>
Source§fn preview_debounce(&self) -> Option<Duration>
fn preview_debounce(&self) -> Option<Duration>
Auto Trait Implementations§
impl Freeze for DirPickSource
impl RefUnwindSafe for DirPickSource
impl Send for DirPickSource
impl Sync for DirPickSource
impl Unpin for DirPickSource
impl UnsafeUnpin for DirPickSource
impl UnwindSafe for DirPickSource
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
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§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.§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.§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.§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.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> 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