pub struct FormState {Show 20 fields
pub title: String,
pub status: String,
pub priority: String,
pub labels: String,
pub assignee: String,
pub estimate: String,
pub cycles: String,
pub milestones: String,
pub reviewer: String,
pub start_date: String,
pub due_date: String,
pub parent: String,
pub target: NewIssueTarget,
pub template: String,
pub template_scope: Option<String>,
pub body: String,
pub projects: String,
pub epics: String,
pub focus: FormFocus,
pub cursor: usize,
}Fields§
§title: String§status: String§priority: String§labels: String§assignee: String§estimate: String§cycles: String§milestones: String§reviewer: String§start_date: String§due_date: String§parent: StringThe chosen parent’s number, as a string (WP06 / T026).
A String for the same reason assignee is one: the form’s fields are
uniformly text, and each is parsed and validated at submit rather than at
Empty means no parent, which carries the same meaning as an
empty --parent "" on the CLI.
target: NewIssueTargetThe entry target of the F4 New Issue mode. Choosing a side writes the
matching status into Self::status, which is what submit reads.
template: StringThe selected template’s identity, or empty for none.
A stable template ID ([issue_templates.<id>]) when
Self::template_scope is set, otherwise the legacy
[templates.<name>] record’s name. A label only: the fields it filled are
held separately, so clearing the selection keeps what was typed.
The stable-ID case is identity, not a display label (C-002): a rename in
tix.toml changes the label the row shows through
Self::display_value, never this value — so a submit resolves against
the same template after the rename.
template_scope: Option<String>The explicit scope of the selected stable template, when one is selected.
Some("repository")/Some("board:<name>")/Some("team:<label>") marks
the selection as a stable-ID template and makes the scope visible
(FR-005): Self::display_value renders it beside the ID. None means
no stable template is selected — either none at all, or a legacy
[templates.<name>] pre-fill. The scope is the template’s own declared
scope, split out here so it travels with the selection and is what the
shared resolver is asked for.
body: StringThe issue body (Markdown). Submitted verbatim; rendered with newlines escaped so the row stays one line.
projects: StringThe issue’s project associations (WP06 T029), as the comma-joined
spelling of the resolved project ids — the same shape labels, cycles
and milestones use, and the shape the submit path parses.
A set of ids, not a display string: the picker offers
crate::projects::list_projects’ ids, Self::from_issue pre-selects the
issue’s stored associations so an edit cannot silently drop the ones the user
did not touch, and the service validates them at submit. The form itself
never constructs or validates a project.
epics: StringThe issue’s epic references (WP06 T031), as the comma-joined spelling of
the resolved epic ids — the same shape projects, labels, cycles and
milestones use, and the shape the submit path parses.
A set of ids, not a display string: the picker offers
crate::epics::list_epics’ ids, Self::from_issue pre-selects the
issue’s stored references so an edit or clone cannot silently drop the ones
the user did not touch, and the service validates them at submit. The form
itself never constructs or validates an epic.
focus: FormFocus§cursor: usizeThe insertion point in the focused field, in characters (not bytes, so a multi-byte value is never split). Always clamped to the field’s value when used; every writer that replaces a value wholesale resets it to the end.
Implementations§
Source§impl FormState
impl FormState
pub fn new(default_status: &str) -> Self
pub fn with_default_assignee( default_status: &str, default_assignee: &str, ) -> Self
Sourcepub fn apply_template(&mut self, name: &str, template: &IssueTemplate)
pub fn apply_template(&mut self, name: &str, template: &IssueTemplate)
Pre-fill the rows a template sets, leaving rows it omits untouched.
Untouched rather than cleared is the whole point: a template is applied
to a form the user may already have typed into, and a template that named
only labels must not silently erase their title. Vector fields follow the
same rule as the submit path — they are the comma-joined spelling of the
list they would create.
Sourcepub fn apply_stable_template(
&mut self,
id: &str,
scope: &str,
template: &Template,
)
pub fn apply_stable_template( &mut self, id: &str, scope: &str, template: &Template, )
Pre-fill the rows a stable-ID template sets, and record its ID + scope.
The sibling of Self::apply_template for [issue_templates.<id>]
records (WP05/T024), and deliberately the same shape: only rows the
template actually sets are written, so applying a labels-only template
cannot erase a title the user already typed.
The values come from the template’s defaults and its prompt defaults,
in the same precedence the shared resolver merges them (contracts/ resolver.md): a prompt’s default wins over the block default for the same
key, because user input would. This is seeding only — required prompts with
no value are left empty and reported by the resolver at submit, not
pre-filled with a placeholder.
template.extensions (unknown metadata) is not read: it is preserved
data, never interpreted as a form field (C-006). List-valued defaults are
joined with the same comma rule the submit path parses, and rows this form
does not have (files, related_issues, type) are applied by the
resolver from the defaults at submit instead — the form neither invents a
row for them nor silently drops them.
Sourcepub fn from_issue(issue: &Issue) -> Self
pub fn from_issue(issue: &Issue) -> Self
This form with every field prefilled from an existing issue — the TUI’s “clone issue” action (tix #1484).
Exactly the fields the form has are carried over, which is exactly the
fields creation takes: number, created, commit and History are not
creation inputs, so they are not carried. The title is copied verbatim
rather than suffixed with “copy”: the user asked for the source’s data, a
title is not an identity (numbers are), and inventing a naming convention
here would put a string in the user’s issue that no command in this tool
produces.
Multivalued fields are filled in the same comma-separated form the submit
path parses (labels, cycles, milestones), so a clone submitted
unchanged round-trips the source’s values exactly.
Sourcepub fn value_of(&self, focus: FormFocus) -> &str
pub fn value_of(&self, focus: FormFocus) -> &str
This form’s value for focus, regardless of which field is focused.
focused_value is value_of(self.focus). The indirection exists so the
renderer can walk FormFocus::RING and read each field in turn, which is
what lets one list drive both the labels and the focus index.
Sourcepub fn display_value(&self, focus: FormFocus) -> Cow<'_, str>
pub fn display_value(&self, focus: FormFocus) -> Cow<'_, str>
The text actually drawn for focus.
Identical to Self::value_of everywhere but two rows. The body’s
newlines are escaped (\n) so a multi-line Markdown body occupies one row
and the row arithmetic the caret depends on stays true; the submitted value
keeps the real newlines. The Template row appends the selected template’s
explicit scope (id [scope]) so the scope is visible before submit
(FR-005); the stored Self::template stays the bare ID, which is what
selection and resolution read.
Sourcepub fn focused_display_value(&self) -> Cow<'_, str>
pub fn focused_display_value(&self) -> Cow<'_, str>
Self::display_value for the focused row.
pub fn focused_value(&self) -> &str
Sourcepub fn focused_value_mut(&mut self) -> Option<&mut String>
pub fn focused_value_mut(&mut self) -> Option<&mut String>
The focused field’s editable buffer, or None when the field has none.
Option rather than a panic for the control rows: Target is an enum
with no buffer of its own, and the alternative — a &mut String arm that
panics — would make a guard in insert_char the only thing standing
between a mis-set focus and an abort. A None makes the callers handle it.
Sourcepub fn cursor_to_end(&mut self)
pub fn cursor_to_end(&mut self)
Put the insertion point after the focused field’s last character.
Sourcepub fn cursor_to_start(&mut self)
pub fn cursor_to_start(&mut self)
Put the insertion point before the focused field’s first character.
Sourcepub fn move_cursor_left(&mut self)
pub fn move_cursor_left(&mut self)
Move the insertion point one character left (no-op at the start).
Sourcepub fn move_cursor_right(&mut self)
pub fn move_cursor_right(&mut self)
Move the insertion point one character right (no-op at the end).
Sourcepub fn move_cursor_word_left(&mut self)
pub fn move_cursor_word_left(&mut self)
Move the insertion point to the start of the previous word.
Skips the run of non-word characters before the caret first, then the
word itself, which is the readline/Emacs rule Ctrl-Left follows.
Sourcepub fn move_cursor_word_right(&mut self)
pub fn move_cursor_word_right(&mut self)
Move the insertion point to the end of the next word.
Sourcepub fn delete_char(&mut self)
pub fn delete_char(&mut self)
Delete the character before the insertion point (Backspace).
Sourcepub fn delete_forward_char(&mut self)
pub fn delete_forward_char(&mut self)
Delete the character at the insertion point (Delete).
Sourcepub fn delete_to_end(&mut self)
pub fn delete_to_end(&mut self)
Delete from the insertion point to the end of the value (Ctrl-K).
Sourcepub fn delete_to_start(&mut self)
pub fn delete_to_start(&mut self)
Delete from the start of the value to the insertion point (Ctrl-U).
Sourcepub fn delete_word_backward(&mut self)
pub fn delete_word_backward(&mut self)
Delete the word before the insertion point (Ctrl-W, Alt-Backspace).
pub fn insert_char(&mut self, c: char)
Sourcepub fn is_date_focus(&self) -> bool
pub fn is_date_focus(&self) -> bool
Whether the focused field is a picker-only date field.
Sourcepub fn focused_date_is_complete(&self) -> bool
pub fn focused_date_is_complete(&self) -> bool
Whether the focused date field already holds a complete, valid date.
Sourcepub fn set_focused_date(&mut self, value: &str)
pub fn set_focused_date(&mut self, value: &str)
Overwrite the focused date field (no-op when it isn’t a date field).
pub fn move_focus_next(&mut self)
pub fn move_focus_prev(&mut self)
Trait Implementations§
Auto Trait Implementations§
impl Freeze for FormState
impl RefUnwindSafe for FormState
impl Send for FormState
impl Sync for FormState
impl Unpin for FormState
impl UnsafeUnpin for FormState
impl UnwindSafe for FormState
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<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