Skip to main content

MarkerKind

Enum MarkerKind 

Source
pub enum MarkerKind {
    Plain,
    PromptStart,
    CommandStart,
    OutputStart,
    CommandFinished(Option<i32>),
}
Expand description

What a marker means (#158). A plain add_marker decoration carries no semantics (MarkerKind::Plain); OSC 133 shell-integration marks carry the command-boundary role (prompt/command/output start, or command finished with its optional exit code). The engine only parses and anchors these — the success/failure colour, earcon and prompt-to-prompt navigation are consumer policy (ADR-0017), driven off the kind + exit the wire (#159) carries.

Deliberately exhaustive (#843), and the first draft of that sweep got this one wrong — the compiler caught it. The reasoning that failed: OSC 133 has more subcommands than the four modelled, and MarkerKind::Plain is already the shape an unrecognised mark takes, so a consumer meeting a new member has somewhere to put it. True, and not the whole question.

This enum rides the wire, so a new member is not a consumer’s problem first — it is an encoder’s. justerm-wasm-decode maps every member onto a numeric wire triple, and marking this non-exhaustive forces a _ arm there, which converts a future compile error into a silently wrong wire value. That is the exact trade FrameKind is left exhaustive for, one type over in this same file: a new member here moves WIRE_VERSION (ADR-0008), and a wire bump is a louder gate than semver, so the attribute would soften the quieter signal while removing the loud one.

The rule, stated by mechanism rather than by symptom, because the first phrasing — “a wire-carried enum stays exhaustive” — misclassified at both ends. It over-captured DecodeError, which ADR-0008 makes a wire contract by name yet which crosses the boundary through Debug (total, no arms) and is therefore free to take the attribute; and it under-captured crate::CursorShape, which is not obviously “wire-carried” from its own module and is mapped exactly like this one. The mechanism:

An enum whose members are mapped onto wire values by a match outside this crate stays exhaustive.

Measured over justerm-wasm-decode/src — the published encoder, and the only place the boundary bites — that is four: crate::CursorShape (lib.rs:198), FrameKind (:192), this one (:233), and crate::UnderlineStyle, which joined when #831 gave the style a name on the published surface. Every other public enum has zero such sites, so no other call turns on this rule.

Do not read that count from here. It was “exactly three” until #831 and this paragraph is prose, checked by nothing — the executable roster is justerm-wasm-decode/tests/wire_enum_stays_exhaustive.rs, which derives the set from core’s own sources and is what noticed that cell.rs was outside its scan.

Nothing but cargo test --workspace would have said so: #[non_exhaustive] binds only across a crate boundary, so the defect compiles fine inside justerm-core and a bare cargo test never sees it. That is the load-bearing half of the --workspace release.md insists on.

But do not mistake that gate for a detector of this rule. It fired here by the accident that this enum’s wire mapping lives one crate over. Color is wire-carried too (encode_color, below) and its only exhaustive match is inside this crate, where the attribute does nothing — so marking Color would leave the workspace green and put the attribute on a wire-carried enum unnoticed. The rule is currently held by this paragraph and by nothing executable.

Why the direction is asymmetric at all, which is the fact the whole sweep turns on and is easy to state backwards: an exhaustive enum does not force a consumer to handle a new member — they may write _ whenever they like. It preserves their option to be forced. #[non_exhaustive] removes that option, and on stable Rust it is irreversible: measured on this repo’s pinned 1.96.0, #![deny(non_exhaustive_omitted_patterns)] is an unknown lint, so a consumer cannot opt back in. One direction is a default the consumer can change; the other is a decision taken on their behalf for good.

And #843 runs on two axes, not one. The first draft wrote down only the first, which left five calls looking arbitrary until a refuting pass named the gap. They answer different questions and neither substitutes for the other:

  • Openness — can this set actually grow? This decides whether the attribute is warranted. Putting it on a closed set states something false in the type; crate::Side will not gain a third member, and saying it might is worse than saying nothing.
  • Direction — does a consumer ever receive one? This decides the cost, not the need. Where nothing public hands the enum outward, there is no match to preserve and the attribute costs a consumer nothing — so a genuine doubt about openness resolves toward marking. Where the enum comes outward, the option being removed is real and closure has to be shown.

Read together they explain the whole roster: crate::Key is inward and open, so it is marked; crate::SelectionType is inward and closed by convergence, so it is not; crate::Color comes outward and is closed, so it is not twice over.

Variants§

§

Plain

A add_marker decoration anchor (#118) — no OSC-133 semantics.

§

PromptStart

OSC 133;A — the shell prompt begins here.

§

CommandStart

OSC 133;B — the typed command begins here (the prompt ended).

§

OutputStart

OSC 133;C — the command was submitted; its output begins here.

§

CommandFinished(Option<i32>)

OSC 133;D[;exit] — the command finished, with its exit code if reported (absent, empty or non-numeric → None).

Trait Implementations§

Source§

impl Clone for MarkerKind

Source§

fn clone(&self) -> MarkerKind

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for MarkerKind

Source§

impl Debug for MarkerKind

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Eq for MarkerKind

Source§

impl PartialEq for MarkerKind

Source§

fn eq(&self, other: &MarkerKind) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for MarkerKind

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<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.