pub enum FilterField {
Show 13 variants
Assignee,
Label,
Status,
Priority,
Cycle,
Milestone,
Reviewer,
StartDate,
DueDate,
Parent,
Category,
Project,
Epic,
}Expand description
A selectable structured-filter criterion.
FilterField::ALL is the single ordered field list the filter modal
renders its rows from (risk: field/modal drift) and StructuredFilter
evaluates over — adding a criterion (FR-011) is one more Option<String>
field on StructuredFilter plus one variant / match arm here.
Variants§
Assignee
Label
Status
Priority
Cycle
Milestone
Reviewer
StartDate
DueDate
Parent
An issue’s direct parent, by selector (WP06 T024).
Category
An issue’s resolved workflow category, by category key (WP08 T034).
Derived, not stored. Unlike the nine above, this criterion matches
nothing an issue’s file contains: there is no category frontmatter key
(research R2), and the value comes from the issue’s status resolved
through the board’s category_map. See FilterField::key for what
that means for diagnostics.
Project
An issue’s project membership, by resolved project id (WP06 T026).
A membership criterion, not a text one. project:<id> asks whether the
issue’s association list — Issue::projects, read through the shared
crate::projects::ProjectNode::project_ids accessor that
ProjectIndex::build itself reads — contains the referenced project. It is
deliberately not a substring test on the rendered frontmatter: that
would call an issue whose body mentions an id a member, and would match
project:p-1 against an issue associated with p-12.
An issue in two projects matches project:A and project:B
(recorded in contracts/cli-surface.md §3); an unassociated issue matches
no project criterion, and an id no association carries matches nothing.
Epic
An issue’s epic membership, by resolved epic id (WP06 T028).
A membership criterion, not a text one, and the exact analogue of
FilterField::Project for the epic registry. epic:<id> asks whether the
issue’s reference list — Issue::epics, read through the shared
crate::epics::EpicNode::epic_ids accessor that
crate::epics::EpicIndex::build itself reads — contains the referenced
epic. It is deliberately not a substring test on the rendered
frontmatter: that would call an issue whose body mentions an id a member, and
would match epic:e-1 against an issue referencing e-12.
An issue in two epics matches epic:A and epic:B (recorded in
contracts/cli-surface.md §3); an unreferenced issue matches no epic
criterion, and an id no reference carries matches nothing.
The token is the singular epic: while Self::key is the plural
epics the model serializes — the same split FilterField::Project
records, and for the same reason.
Implementations§
Source§impl FilterField
impl FilterField
Sourcepub const ALL: [FilterField; 13]
pub const ALL: [FilterField; 13]
The criteria in modal row order (research D-05).
Parent is appended rather than interleaved: a row’s position is a
user’s muscle memory and a TUI test’s golden index, and moving eight
existing rows to make room for a ninth helps nobody (T024 step 2).
Category is appended after Parent, for the same reason T024 step 2
gave: a row’s position is a user’s muscle memory and the TUI’s golden
index, and it is also the position a user reaches last. A category is the
one criterion a user cannot reach from the file itself, so it is the one
they will look up last.
Project is appended after Category for the same reason T024 step 2
gave: a row’s position is a user’s muscle memory and the TUI’s golden index.
Appending is also what keeps next()/prev() wrapping correct without
touching a single existing index — the arithmetic is a modulus of the
extended length, and the wrapping test asserts both ends.
Epic is appended after Project (WP06 T028) for exactly the same
reason: a row’s position is a user’s muscle memory and the TUI’s golden
index, and appending keeps next()/prev() correct as a modulus of the
extended length without moving a single existing row.
pub fn label(self) -> &'static str
Sourcepub fn key(self) -> &'static str
pub fn key(self) -> &'static str
The serialized frontmatter key each criterion matches against
(Issue::to_file_contents emits these). Used by diagnostics.
For FilterField::Category this is the token name, not a frontmatter
key, because there is no category key: the criterion is derived from the
issue’s status through the board’s category_map (research R2). T034
step 4 asked what to report here and warned that leaving a nonexistent key
in the diagnostics would be a quiet lie, so the honest spelling is
category — which is exactly what the user types, and what the grammar
parses — plus FilterField::is_derived for any surface that has to
explain the criterion rather than merely echo it.
The distinction is not cosmetic. key() feeds two things that read very
differently: a hint bar, where category:completed is exactly right, and
an error, where “no issue has category:completed” would send a user
looking for a field that does not exist. [is_derived] is what keeps the
second from happening.
Sourcepub fn is_derived(self) -> bool
pub fn is_derived(self) -> bool
Whether this criterion is derived from other data rather than read off a frontmatter field (WP08 T034 step 4).
Category is the only one. It is derived from status through the board’s
category_map, so a diagnostic that names it as a field points at a field
that does not exist. Any surface printing why a criterion matched, or why
it found nothing, must say so through this.
Sourcepub fn describe(self) -> String
pub fn describe(self) -> String
The criterion as a user should read it in an explanation: category on its
own, or category (derived from status) where the extra clause matters.
Split from [key] so a caller has to choose. A hint bar that appends
“(derived from status)” on every keystroke is noise, and an error that
omits it sends the user hunting for a field; this hands each surface the
short form and lets the ones that explain pick the long one.
Sourcepub fn row(self) -> usize
pub fn row(self) -> usize
Row index of this criterion in FilterField::ALL.
pub fn next(self) -> Self
pub fn prev(self) -> Self
Sourcepub fn value(self, filter: &StructuredFilter) -> Option<&str>
pub fn value(self, filter: &StructuredFilter) -> Option<&str>
The criterion value when set and non-empty. An empty string is treated as “no criterion” everywhere (canonical invariant), so the filter modal can edit a slot without a live-match surprise.
Sourcepub fn value_mut(self, filter: &mut StructuredFilter) -> &mut String
pub fn value_mut(self, filter: &mut StructuredFilter) -> &mut String
Mutable access to the criterion buffer, materializing an empty one
when the criterion is unset (the filter modal types into it and
StructuredFilter::normalize promotes empty back to None).
Sourcepub fn unset(self, filter: &mut StructuredFilter)
pub fn unset(self, filter: &mut StructuredFilter)
Clear the criterion back to None.
Sourcepub fn is_reference(self) -> bool
pub fn is_reference(self) -> bool
Whether this criterion is a parent reference rather than a text field.
The distinction drives two things: the free-typing path is bypassed in
favour of the issue picker (WP06 T026), and evaluate compares exactly
rather than by substring, because a number must not match a longer number
that merely contains it.
Sourcepub fn token(self) -> &'static str
pub fn token(self) -> &'static str
The criterion’s query token, as the grammar parses it and the hint bar should echo it.
For every criterion but FilterField::Project and
FilterField::Epic this is Self::key — the two spellings coincide
(status:, labels:, parent: the token and the frontmatter key alike).
Those two are the places they differ, and deliberately: the token is the
singular project:/epic: the parser accepts and the modal’s help
advertises, while the key is the plural projects/epics WP03’s model
serializes. A hint bar echoing projects:p-1 would advertise a token
query_matches does not parse, which is a key that looks usable and does
nothing — the exact failure key()’s own doc warns about for diagnosis.
Sourcepub fn is_project(self) -> bool
pub fn is_project(self) -> bool
Whether this criterion is a project membership test rather than a text field (WP06 T026).
Kept separate from Self::is_reference even though both compare exactly:
a parent is a number on the issue’s own frontmatter and can be rewritten
into the query, while a project is a membership the file’s bytes answer
only indirectly (the association list is a YAML block, not a scalar), so the
criterion travels in the StructuredFilter and is judged by
StructuredFilter::project_matches. The surfaces use this predicate to
route the row to the project picker rather than the issue picker.
Sourcepub fn is_epic(self) -> bool
pub fn is_epic(self) -> bool
Whether this criterion is an epic membership test rather than a text field (WP06 T028).
The exact analogue of Self::is_project: a reference list is a YAML block
the rendered bytes answer only indirectly, so the criterion travels in the
StructuredFilter and is judged by StructuredFilter::epic_matches. Kept
a separate predicate from is_project because the two name different
registries and different pickers — collapsing them would make the surfaces
offer a project picker for an epic row.
Trait Implementations§
Source§impl Clone for FilterField
impl Clone for FilterField
impl Copy for FilterField
Source§impl Debug for FilterField
impl Debug for FilterField
impl Eq for FilterField
Source§impl PartialEq for FilterField
impl PartialEq for FilterField
impl StructuralPartialEq for FilterField
Auto Trait Implementations§
impl Freeze for FilterField
impl RefUnwindSafe for FilterField
impl Send for FilterField
impl Sync for FilterField
impl Unpin for FilterField
impl UnsafeUnpin for FilterField
impl UnwindSafe for FilterField
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.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