Skip to main content

Document

Struct Document 

Source
pub struct Document { /* private fields */ }
Available on crate feature std only.
Expand description

A YAML document with byte-faithful source preservation, typed data access, and path-targeted edits.

Document carries three coordinated views of the same input: an immutable green tree that reproduces the source byte-for-byte, a typed Value for data access, and an internal span tree that maps any Value-shaped path back to a byte range. Edits flow through Document::replace_span (the primitive) and Document::set (the path-shaped wrapper); untouched bytes — indentation, comments, blank lines, sibling entries — are preserved verbatim.

Every path-taking method reads the grammar described in crate::path: server.port, items[0].name, and, for a key the grammar would otherwise read as structure, a bracket-quoted segment such as labels["app.kubernetes.io/name"].

§Examples

Read-only round-trip:

use noyalib::cst::parse_document;

let src = "name: noyalib  # the project\nversion: 0.0.1\n";
let doc = parse_document(src).unwrap();
assert_eq!(doc.to_string(), src);

Path-targeted edit:

use noyalib::cst::parse_document;

let mut doc = parse_document("name: foo\nversion: 0.0.1\n").unwrap();
doc.set("version", "0.0.2").unwrap();
assert_eq!(doc.to_string(), "name: foo\nversion: 0.0.2\n");

Implementations§

Source§

impl Document

Source

pub fn anchors(&self) -> Vec<AnchorInfo>

Every &name declaration in this document, in source order.

§Examples
use noyalib::cst::parse_document;

let doc = parse_document(
    "defaults: &cfg\n  port: 8080\nserver:\n  <<: *cfg\n",
).unwrap();
let anchors = doc.anchors();
assert_eq!(anchors.len(), 1);
assert_eq!(anchors[0].name, "cfg");
Source

pub fn aliases(&self) -> Vec<AliasInfo>

Every *name reference in this document, in source order.

§Examples
use noyalib::cst::parse_document;

let doc = parse_document("a: &x 1\nb: *x\nc: *x\n").unwrap();
let aliases = doc.aliases();
assert_eq!(aliases.len(), 2);
Source

pub fn aliases_of(&self, name: &str) -> Vec<AliasInfo>

Aliases whose name matches name, in source order.

§Examples
use noyalib::cst::parse_document;

let doc = parse_document("a: &x 1\nb: &y 2\nc: *x\nd: *y\n").unwrap();
let xs = doc.aliases_of("x");
assert_eq!(xs.len(), 1);
assert_eq!(xs[0].name, "x");
Source

pub fn materialise_alias_at(&mut self, position: usize) -> Result<()>

Replace the *name alias whose mark begins at byte position with the source text of the matching &name’s scalar value.

After the splice, the alias’s site holds an independent copy of the anchored scalar — subsequent edits to the anchored value do not propagate to it.

§Errors
  • position does not start an *name token.
  • The named anchor is not declared earlier in source order.
  • The anchored value is not a scalar (multi-line block collections require manual handling — read the anchor’s span via Self::anchors and splice with Self::replace_span).
  • The same parse-after-edit errors as Self::replace_span.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("a: &x 7\nb: *x\n").unwrap();
let alias = doc.aliases()[0].clone();
doc.materialise_alias_at(alias.mark_span.0).unwrap();
assert!(!doc.to_string().contains("*x"));
assert!(doc.to_string().contains("b: 7"));
Source

pub fn materialise_aliases_of(&mut self, name: &str) -> Result<usize>

Materialise every alias whose name matches name. Returns the count of aliases replaced.

Aliases are processed in reverse source order so each splice’s offsets stay valid for later (earlier in source) aliases.

§Errors

As Self::materialise_alias_at. The first failing alias aborts the batch — already-materialised aliases stay materialised, the rest are unchanged.

§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("a: &x 7\nb: *x\nc: *x\n").unwrap();
let n = doc.materialise_aliases_of("x").unwrap();
assert_eq!(n, 2);
assert!(!doc.to_string().contains('*'));
Source

pub fn rename_anchor(&mut self, old: &str, new: &str) -> Result<usize>

Rename every &old anchor declaration and every *old alias reference to new in one atomic pass. Returns the total number of touched sites (anchors + aliases).

Splices run in reverse source order so each successive splice’s offsets stay valid for earlier sites. The whole rename is byte-faithful outside the touched marks — comments, blank lines, and sibling formatting survive verbatim.

§Errors
  • new is empty or contains characters that would not be accepted as a YAML anchor name (any of the flow indicators ,[]{} or whitespace per YAML 1.2 §6.9.2).
  • old does not match any anchor or alias in the document (so the call is a no-op the user probably did not intend) — surfaced as an error rather than a silent zero-count.
  • new already names a different anchor in the document (unless new == old): merging the two would make every *new alias resolve to the last declaration, silently changing the document’s meaning, so the rename is refused.
  • The same parse-after-edit errors as crate::cst::Document::replace_span. The rename is a single atomic splice over the whole document, so it is all-or-nothing: on any error the document is left byte-for-byte unchanged.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document(
    "defaults: &cfg\n  port: 8080\nservice:\n  <<: *cfg\nbackup: *cfg\n",
).unwrap();

// Rename `cfg` → `defaults`. The single `&cfg` declaration
// and both `*cfg` references are updated in one call.
let n = doc.rename_anchor("cfg", "defaults").unwrap();
assert_eq!(n, 3); // 1 anchor + 2 aliases
let out = doc.to_string();
assert!(!out.contains("&cfg"));
assert!(!out.contains("*cfg"));
assert!(out.contains("&defaults"));
assert!(out.contains("*defaults"));
Source§

impl Document

Source

pub fn comments_at(&self, path: &str) -> CommentBundle

Comments decorating the node at path, classified by position.

Returns an empty CommentBundle when path does not resolve. Path syntax matches Document::span_atfoo.bar, items[0], items[0].name. Wildcard / recursive-descent segments are not supported (a non-singular span has no canonical “above” line).

§Examples
use noyalib::cst::parse_document;

let src = "# A multi-line\n# leading block\nport: 8080  # inline\n";
let doc = parse_document(src).unwrap();

let b = doc.comments_at("port");
assert_eq!(b.before.len(), 2);
assert_eq!(b.inline.as_ref().unwrap().text, " inline");
Source

pub fn set_inline_comment(&mut self, path: &str, text: &str) -> Result<()>

Set (or replace) the inline comment on the single-line node at path — the #-introduced comment that follows the value on the same line.

text is the comment body without the leading #; it renders as # <text> (a single space after #, or a bare # when text is empty). If the node already has an inline comment, its body is replaced in place, keeping the existing separating whitespace; otherwise # <text> is appended after the value.

Guarded like the other mutators: the edit must re-parse and leave the document’s typed value unchanged (a comment carries no data), or it is rolled back.

§Errors
  • path does not resolve to a node.
  • The node spans multiple lines — it has no inline comment of its own; comment its entries instead.
  • text contains a newline (a comment is a single line).
  • The splice would not re-parse or would change data (roll back).
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("port: 8080\n").unwrap();
doc.set_inline_comment("port", "the listen port").unwrap();
assert_eq!(doc.source(), "port: 8080  # the listen port\n");
doc.set_inline_comment("port", "changed").unwrap();
assert_eq!(doc.source(), "port: 8080  # changed\n");
Source

pub fn remove_inline_comment(&mut self, path: &str) -> Result<()>

Remove the inline comment on the node at path, if any, taking the separating whitespace with it so no trailing space is left. A no-op returning Ok(()) when the node has no inline comment (or the path does not resolve).

Guarded and rolled back exactly like set_inline_comment.

§Errors
  • The removal would not re-parse or would change data (rolls back). A missing comment or path is a no-op, not an error.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("port: 8080  # noise\n").unwrap();
doc.remove_inline_comment("port").unwrap();
assert_eq!(doc.source(), "port: 8080\n");
Source

pub fn set_leading_comment(&mut self, path: &str, text: &str) -> Result<()>

Set (or replace) the leading comment block above the single-line mapping entry at path — the run of comment lines that comments_at(path).before reports.

text becomes one comment line per \n-separated segment, each rendered at the key’s indentation as # <segment> (a bare # for an empty segment). An existing leading block is replaced in place; otherwise the block is inserted immediately above the entry’s line.

Scope: block mapping keys on a single line (where the key token, and therefore the entry’s own line and indent, are unambiguous). Multi-line / nested entries and sequence items are a follow-up — comments_at does not attribute a leading block to them unambiguously. Guarded like the other mutators: the edit must re-parse and leave the typed value unchanged, or it rolls back.

§Errors
  • path does not address a single-line block-mapping key.
  • The splice would not re-parse or would change data (roll back).
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("port: 8080\n").unwrap();
doc.set_leading_comment("port", "the listen port").unwrap();
assert_eq!(doc.source(), "# the listen port\nport: 8080\n");
doc.set_leading_comment("port", "line one\nline two").unwrap();
assert_eq!(doc.source(), "# line one\n# line two\nport: 8080\n");
Source

pub fn remove_leading_comment(&mut self, path: &str) -> Result<()>

Remove the leading comment block above the mapping entry at path, if any. A no-op returning Ok(()) when there is none (or the path does not address a single-line mapping key).

Guarded and rolled back exactly like set_leading_comment.

§Errors
  • The removal would not re-parse or would change data (rolls back).
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("# noise\n# more\nport: 8080\n").unwrap();
doc.remove_leading_comment("port").unwrap();
assert_eq!(doc.source(), "port: 8080\n");
Source§

impl Document

Source

pub fn set_comment( &mut self, path: &str, position: CommentPosition, text: &str, ) -> Result<()>

Set the comment at path in the given position.

Replaces an existing comment, or writes a new one when there is none. text is the comment body without the leading #; a single leading space is added when text does not already begin with whitespace, so set_comment(p, Inline, "note") yields # note.

For CommentPosition::Before, a text containing newlines becomes one # line per line, each at the node’s own indentation.

The edit goes through Document::replace_span, so it inherits the same guard: an edit that would make the document re-parse differently is rejected rather than written.

§Errors
  • path does not resolve to a node.
  • The resulting document would not re-parse to the same value.
§Examples
use noyalib::cst::{parse_document, CommentPosition};

let mut doc = parse_document("port: 8080\n").unwrap();
doc.set_comment("port", CommentPosition::Inline, "listen port").unwrap();
assert_eq!(doc.source(), "port: 8080  # listen port\n");
Source

pub fn remove_comment( &mut self, path: &str, position: CommentPosition, ) -> Result<()>

Remove the comment at path in the given position.

A no-op when there is no comment there. For CommentPosition::Inline the whitespace separating the comment from the node’s content goes with it, so no trailing spaces are left behind. For CommentPosition::Before the whole run of comment lines is removed.

§Errors

As Document::set_comment.

§Examples
use noyalib::cst::{parse_document, CommentPosition};

let mut doc = parse_document("port: 8080  # note\n").unwrap();
doc.remove_comment("port", CommentPosition::Inline).unwrap();
assert_eq!(doc.source(), "port: 8080\n");
Source§

impl Document

Source

pub fn syntax(&self) -> &GreenNode

Borrow the root GreenNode.

§Examples
use noyalib::cst::{parse_document, SyntaxKind};

let doc = parse_document("foo: 1\n").unwrap();
assert_eq!(doc.syntax().kind(), SyntaxKind::Document);
Source

pub fn as_value(&self) -> Ref<'_, Value>

Borrow the typed Value view of the document.

On the first call after an edit (or a fresh parse), this triggers a one-shot parse of the current source into the internal Value / SpanTree cache. Subsequent calls on the same document are O(1) until the next edit invalidates the cache. Code that batches many edits without reading the typed view in between never pays the typed-tree cost.

§Examples
use noyalib::cst::parse_document;

let doc = parse_document("name: noyalib\n").unwrap();
assert_eq!(doc.as_value()["name"].as_str(), Some("noyalib"));
Source

pub fn source(&self) -> &str

The original source bytes for this document. After an edit reflects the current source.

§Examples
use noyalib::cst::parse_document;

let src = "key: 1\n";
let doc = parse_document(src).unwrap();
assert_eq!(doc.source(), src);
Source

pub fn span_at(&self, path: &str) -> Option<(usize, usize)>

Resolve a path to the byte range of the value at that path, if any.

Path syntax matches the rest of the crate (foo.bar, items[0], items[0].name). Wildcard / recursive-descent segments are not supported here — they have no single span.

A duplicated mapping key resolves to its last occurrence, the same occurrence the typed view keeps (as_value loads with the default DuplicateKeyPolicy::Last, the YAML 1.2 behaviour) — the returned span always denotes the node that as_value selects for the path.

§Examples
use noyalib::cst::parse_document;

let doc = parse_document("name: noyalib\nversion: 0.0.1\n").unwrap();
let (s, e) = doc.span_at("version").unwrap();
assert_eq!(&doc.source()[s..e], "0.0.1");

A duplicate key resolves to the occurrence the typed view keeps:

use noyalib::cst::parse_document;

let doc = parse_document("k: one\nk: two\n").unwrap();
let (s, e) = doc.span_at("k").unwrap();
assert_eq!(&doc.source()[s..e], "two");
assert_eq!(doc.get("k"), Some("two"));
Source

pub fn key_span(&self, path: &str) -> Option<(usize, usize)>

Return the byte span of a mapping entry’s key token, the read-only companion to span_at (which returns the value span). source()[start..end] is the key exactly as written — quotes included for a quoted key.

This exposes, read-only, the same key site rename_key rewrites; it is the span tooling needs to report duplicate keys with positions or to drive a “rename key” code action without walking the green tree by hand.

Returns None when the path does not resolve to a block-mapping entry with a simple scalar key — a sequence index, an alias (*name) site (which owns no key bytes of its own), a key produced by a << merge, or a path that does not resolve at all.

use noyalib::cst::parse_document;

let doc = parse_document("name: foo\n\"quoted key\": 1\n").unwrap();
let (s, e) = doc.key_span("name").unwrap();
assert_eq!(&doc.source()[s..e], "name");
let (s, e) = doc.key_span("quoted key").unwrap();
assert_eq!(&doc.source()[s..e], "\"quoted key\"");
assert_eq!(doc.key_span("missing"), None);
Source

pub fn validate(&self) -> Result<()>

Verify that the current source re-parses cleanly.

Document::set (and the rest of the path-shaped edit API) uses a localised-repair fast path that gates each splice on the fragment’s own scanner-level validation but commits optimistically: a structurally invalid splice across the whole document — for example, a value like [ that opens a flow collection never closed at end-of-input — passes the fragment check and only surfaces when the typed view is next read. as_value, span_at, get, and any path-shaped API panic on first access in that state.

validate is the non-panicking eager check: call it after an edit (or before handing the document to a downstream consumer) to surface any document-level parse error as a regular Result. On success, the typed cache is populated as a side-effect so a subsequent as_value call is free.

§Errors

Returns the underlying parse error if the source no longer parses as a single YAML document.

§Examples

Eagerly validate after an edit that may not be safe:

use noyalib::cst::parse_document;

let mut doc = parse_document("name: foo\n").unwrap();
// `[` opens a flow seq that is never closed — the local
// repair commits optimistically, but the document is now
// structurally broken. `validate` surfaces that as an
// error rather than waiting for the next typed-view read.
doc.set("name", "[").unwrap();
assert!(doc.validate().is_err());

Validate a freshly-parsed document — always succeeds:

use noyalib::cst::parse_document;

let doc = parse_document("name: foo\n").unwrap();
assert!(doc.validate().is_ok());
Source

pub fn get(&self, path: &str) -> Option<&str>

Return the source slice of the value at path.

§Examples
use noyalib::cst::parse_document;

let doc = parse_document("items:\n  - one\n  - two\n").unwrap();
assert_eq!(doc.get("items[1]"), Some("two"));
Source

pub fn replace_span( &mut self, start: usize, end: usize, replacement: &str, ) -> Result<()>

Replace the bytes in start..end with replacement and re-parse. The caller is responsible for replacement being a syntactically valid fragment in that position; if the spliced source fails to parse, the original document is left unchanged and the parse error is returned.

§Errors
  • Error::Parse if the resulting source is not valid YAML.
  • Error::Parse if start..end is out of bounds or not a character boundary.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("a: 1\n").unwrap();
let (s, e) = doc.span_at("a").unwrap();
doc.replace_span(s, e, "42").unwrap();
assert_eq!(doc.to_string(), "a: 42\n");
Source

pub fn last_repair_scope(&self) -> Option<RepairScope>

Last successful repair scope, if any. Useful for tests and instrumentation; returns None for a freshly-parsed document or when the most recent edit fell back to a full re-parse.

Source

pub fn set(&mut self, path: &str, fragment: &str) -> Result<()>

Replace the value at path with fragment.

fragment is spliced verbatim into the source — the caller supplies the YAML representation. This deliberately matches no scalar style automatically; choose double-quoted, plain, or block style to suit.

§Prefer Document::set_value for values

Verbatim means the fragment is YAML, not text. set(p, "true") writes the boolean, set(p, "") writes null, and set(p, "v # x") writes v with a comment after it. If you have a value rather than a spelling, set_value renders it — quoting, escaping and choosing a block style as needed — so it reads back as exactly what you passed in.

§The fragment cannot reach outside path

A fragment containing a newline could previously give the document new entries:

set("a", "v\nc: 3")  on  "a: 1\nb: 2\n"   ->   a: v
                                                 c: 3
                                                 b: 2

The re-parse guard could not catch that, because the result is valid YAML. An oracle now checks that restoring the original value at path reproduces the original document; if the fragment changed anything elsewhere, the edit is refused and the document is left untouched. Restructuring the target itself — scalar to mapping, say — remains allowed.

§Errors
  • Error::Parse(...) with “path not found” if path does not resolve in the current document.
  • The same errors as Document::replace_span otherwise.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("name: foo\nversion: 0.0.1\n").unwrap();
doc.set("version", "0.0.2").unwrap();
assert_eq!(doc.to_string(), "name: foo\nversion: 0.0.2\n");
Source

pub fn set_value(&mut self, path: &str, value: &Value) -> Result<()>

Replace the value at path with a typed Value, formatting the YAML fragment to match the existing scalar style at the target site.

Style matching:

  • PlainScalar — emit plain when safe, double-quoted otherwise.
  • SingleQuotedScalar — wrap in '…' (only string values).
  • DoubleQuotedScalar — wrap in "…" with standard escapes (only string values).
  • LiteralScalar / FoldedScalar — a single-line replacement is emitted plain (or quoted when unsafe); a multi-line one is re-emitted as a literal block when representable, and refused otherwise. Folded style is not yet reproduced — a changed value at a > site comes back | or plain.

Setting a value equal to the one already loaded is a no-op: the source is left byte-identical, so the author’s spelling (1.10, 0x1F, ~, an implicit null, a >- folded scalar) survives a save that does not change the value. Equality is Value’s own, so whether 1.0 over a loaded 1 is a no-op follows Number’s PartialEq for the active features.

Non-string values (numbers, booleans, null) are emitted plain regardless of the existing style — quoting them would change the parsed type round-trip.

Inside a […] / {…} flow collection the same styles apply, except that a plain spelling is also refused when the string contains , [ ] { or } (structural anywhere in flow context), and a multi-line string is double-quoted with \n escapes, because block scalars do not exist in flow context:

use noyalib::cst::parse_document;
use noyalib::Value;

let mut doc = parse_document("m: {a: 1, b: 2}\n").unwrap();
doc.set_value("m.a", &Value::String("x, y".into())).unwrap();
assert_eq!(doc.to_string(), "m: {a: \"x, y\", b: 2}\n");
doc.set_value("m.b", &Value::String("two\nlines".into())).unwrap();
assert_eq!(doc.to_string(), "m: {a: \"x, y\", b: \"two\\nlines\"}\n");
§Filling in an implicit null

An absent block-mapping value (a:) or empty sequence item (- ) has no bytes to replace, so the value is inserted after the : / - instead — before any comment on the line, and with no style to inherit, so the neighbour rule above decides the spelling on its own. span_at still reports None there: the node has nothing to read, which is a separate question from where a write goes.

§A trailing comment beside a new block literal

A multi-line string is written as a literal block scalar, which runs to the end of its last content line. A comment that trailed the old one-line value (title: Hello # note) therefore moves to the block scalar’s header line, where YAML permits one:

use noyalib::cst::parse_document;
use noyalib::Value;

let mut doc = parse_document("title: Hello # note\n").unwrap();
doc.set_value("title", &Value::String("multi\nline".into())).unwrap();
assert_eq!(doc.to_string(), "title: |- # note\n  multi\n  line\n");
assert_eq!(doc.as_value()["title"].as_str(), Some("multi\nline"));
§Collections (#328)

A Value::Sequence / Value::Mapping replaces an existing collection node in that node’s own style — flow stays flow (tags: [a, b] set to [a, c] emits tags: [a, c]), block stays block at the old value’s column. The splice is verified to load back as the document with exactly this path replaced, or it is rolled back. Replacing a scalar with a collection is still refused: a value that must move onto its own lines is a layout decision set expresses with a fragment.

use noyalib::cst::parse_document;
use noyalib::{Value, from_str};

let mut doc = parse_document("tags: [a, b]\nname: x\n").unwrap();
let tags: Value = from_str("[a, c]").unwrap();
doc.set_value("tags", &tags).unwrap();
assert_eq!(doc.to_string(), "tags: [a, c]\nname: x\n");
§Anchored nodes (#338)

A write into a value that *name alias sites share lands at every one of them, so it is refused — the same policy rename_key, remove and the inserters follow. Call materialise_aliases_of first to give each site its own copy. Setting a value equal to the current one stays a no-op wherever it points.

§Errors
  • Path not found.
  • The target sits inside an anchored value with live alias references.
  • Target is a block scalar being replaced by a multi-line string it cannot represent.
  • Caller passed a Sequence / Mapping and the target is a scalar (use set with a pre-formatted fragment to grow a scalar into a collection).
  • The same errors as Document::replace_span otherwise.
§Examples
use noyalib::cst::parse_document;
use noyalib::Value;

let mut doc = parse_document("name: noyalib\nversion: 0.0.1\n").unwrap();
doc.set_value("version", &Value::String("0.0.2".into())).unwrap();
assert_eq!(doc.to_string(), "name: noyalib\nversion: 0.0.2\n");

// An equal value does not touch the bytes.
let mut doc = parse_document("ratio: 1.10\n").unwrap();
doc.set_value("ratio", &Value::from(1.1_f64)).unwrap();
assert_eq!(doc.to_string(), "ratio: 1.10\n");
Source

pub fn set_path(&mut self, path: &str, value: &Value) -> Result<()>

Like set_value, but creates every missing mapping level along path on the way (#327, ADR-0009).

A frontmatter writer setting menu.visible must not care whether menu: exists yet — the writer it replaces creates it. set_path resolves the deepest existing ancestor and:

  • whole path exists — behaves exactly like set_value (upsert, equal-value no-op, scalar-only replacement);
  • a block-mapping ancestor exists — inserts the remaining chain through insert_entry_value, which owns the indentation, quoting, and the typed-oracle guard;
  • the document is empty (nothing but comments, blank lines, or a bare ---) — appends the rendered chain after the existing bytes, so a comment header survives its document’s first key.

The style machinery is the same one every *_value mutator uses: quoting stays with Emit, new levels indent at the document’s indent_unit, and the edit is verified to change exactly the addressed path before it is kept.

§Errors
  • An existing path segment resolves to a scalar (title.x where title is a string) or to a null value other than the empty document root; the source is left byte-identical.
  • A missing segment is a sequence index — set_path creates mappings, never sequence items.
  • The nearest existing ancestor is a flow collection or an empty {} — the flow inserters are tracked by #338; the refusal is clean.
  • The same errors as set_value / insert_entry_value otherwise.
§Examples
use noyalib::cst::parse_document;
use noyalib::Value;

// Creates the missing `menu:` level.
let mut doc = parse_document("title: x\n").unwrap();
doc.set_path("menu.visible", &Value::Bool(true)).unwrap();
assert_eq!(doc.to_string(), "title: x\nmenu:\n  visible: true\n");

// An empty document receives its first key.
let mut doc = parse_document("").unwrap();
doc.set_path("menu.visible", &Value::Bool(true)).unwrap();
assert_eq!(doc.to_string(), "menu:\n  visible: true\n");

// An existing leaf is an ordinary upsert.
let mut doc = parse_document("menu:\n  visible: false\n").unwrap();
doc.set_path("menu.visible", &Value::Bool(true)).unwrap();
assert_eq!(doc.to_string(), "menu:\n  visible: true\n");
Source

pub fn remove(&mut self, path: &str) -> Result<()>

Remove the value at path along with its surrounding entry (key + colon for mappings, - indicator for sequences). Trailing whitespace and the line break are removed too so the surrounding entries close up with no orphan blank line.

§What counts as part of the entry

An entry owns the trivia a reader would say belongs to it, so a removal leaves no orphan and steals nothing from its neighbours:

  • Head comment. A contiguous run of full-line comments directly above the entry, at its own indentation, is removed with it. Left behind, such a comment does not merely litter — it silently becomes documentation for the next entry. A blank line detaches the run, so a document header set off by one survives the removal of the first entry.
  • Kept blank lines. A keep-chomped (|+ / >+) block scalar’s trailing blank lines are content, not separation, and go with the entry rather than being stranded after it.
  • Trailing comments stay. A comment after the entry’s last content line lies outside its value span (see Document::span_at) and conventionally documents whatever comes next, so it is left in place. A comment interleaved inside a multi-line value is inside the span and goes with the entry.
use noyalib::cst::parse_document;

// The comment documenting `database` goes with it …
let mut doc = parse_document("# connection settings\ndatabase:\n  host: x\ncache: 1\n").unwrap();
doc.remove("database").unwrap();
assert_eq!(doc.to_string(), "cache: 1\n");

// … but one that documents the following entry does not.
let mut doc = parse_document("outer:\n  a: 1\n  # note for next\nnext: 2\n").unwrap();
doc.remove("outer").unwrap();
assert_eq!(doc.to_string(), "  # note for next\nnext: 2\n");

Coverage (issue #221 sub-ask 4 is complete as of v0.0.23):

  • Multi-line values and nested block collections are removed — the whole entry, from its key / - indicator through the last line the value owns.
  • Flow-collection members are removed ({x: 1, y: 2}{y: 2}, [1, 2, 3][1, 3]). The member’s own span goes, plus exactly one separator: the comma after it, or — for the last member — the comma before it. A separator sitting on another line is not matched, so a multi-line flow collection refuses rather than splicing something it cannot see.
  • The last entry of a collection empties that collection rather than deleting its bytes: a:\n x: 1 becomes a:\n {}, and a sole sequence item leaves []. Deleting the bytes would leave a dangling a:, which re-parses as null — a type change rather than a removal. The document’s trailing newline survives.

Every path except the single-line block fast path is guarded by an eager re-parse and a typed-value oracle (the document minus exactly this one path); a splice that would change anything else rolls back and the document is left untouched. The fast path is kept only where the entry demonstrably owns its whole line, because the oracle’s expectation is wrong for a duplicated key.

§Errors
  • Path not found.
  • The entry sits inside an anchored value with live alias references — removing it here would remove it at every *name site too (#338); call materialise_aliases_of first.
  • A flow separator that cannot be located on the member’s line.
  • The same parse-after-edit errors as Document::replace_span; on failure the document is left unchanged.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("a: 1\nb: 2\nc: 3\n").unwrap();
doc.remove("b").unwrap();
assert_eq!(doc.to_string(), "a: 1\nc: 3\n");
Source

pub fn rename_key(&mut self, path: &str, new_key: &str) -> Result<()>

Rename the key of the mapping entry at path to new_key, leaving every other byte — the :, the value, whitespace, comments, and sibling entries — untouched.

path addresses the entry the same way Document::set and Document::remove address it: the path points at the entry’s value; the operation rewrites that entry’s key token.

new_key’s spelling is style-matched to the key it replaces: a plain key stays plain when new_key’s plain spelling re-parses to exactly that string, a single-quoted key stays single-quoted, a double-quoted key stays double-quoted. Quoting is forced only when the plain spelling would not re-parse to new_key (a: b, -flag, 8080, true) — a plain site then falls back to double quotes.

Renaming a key to its current spelling is a no-op — Ok(()) with no bytes modified. “Current spelling” is decided on the decoded key, so a plain true: renamed to "true" stays plain rather than being requoted. The guarantee applies to every path that resolves to a mapping entry; paths that fail to resolve at all (alias-addressed content, keys produced by a << merge) report their resolution error instead.

After the splice the document must re-parse cleanly and its typed value must equal the old value with exactly that one key renamed — same entry position, same value. If either check fails, the document is rolled back to its previous state and an error is returned.

Restrictions in this phase:

  • Both block-mapping and flow-mapping entries rename (#338); in flow context a new key whose plain spelling would read as flow structure (, [ ] { }) is double-quoted.
  • The entry’s key must be a simple scalar token (plain, single-quoted, or double-quoted). Alias keys (*name :) are rejected. Explicit complex keys (? [a, b]) are not addressable by the path syntax in the first place — their stringified form contains bracket segments, which the path parser reads as sequence indices — so they cannot be renamed; the surrounding mapping’s other entries rename normally.
§Errors
  • Path not found, or it does not address a mapping entry (e.g. it ends in a sequence index).
  • path contains a bracket segment that is neither a non-negative integer nor a quoted key (servers[web]) — the shared path parser drops such a segment, which would rename the parent key, so rename_key refuses it outright. A key the grammar would misread is addressed as servers["web"].
  • new_key is <<: the loader treats a << key as a merge directive whatever its quote style, so the rename cannot round-trip.
  • new_key contains a non-printable character (any control character other than tab, U+007F, or a U+0080..=U+009F C1 control) — YAML’s printable set excludes them and no scalar style can spell them here.
  • Restrictions above.
  • The containing mapping already has a different entry whose key equals new_key — the rename would create a duplicate and silently change data. Reported separately when that sibling comes from a << merge rather than from the mapping’s own source entries.
  • The addressed key has no entry of its own because a << merge key produced it — the key lives in the merged mapping, so that is where it must be renamed.
  • The path is reached through an alias (*name): the bytes at that site belong to the anchor, so the anchor’s own entry must be renamed instead.
  • The entry lies inside an anchored value that has alias references — the rename would propagate to every *name site. Call Document::materialise_aliases_of first.
  • The re-parse / integrity guard above; the document is left unchanged.
  • The document no longer parses (an earlier edit left it in the optimistically-committed broken state — see Document::validate).
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("name: foo  # the project\nversion: 0.0.1\n").unwrap();
doc.rename_key("name", "title").unwrap();
assert_eq!(doc.to_string(), "title: foo  # the project\nversion: 0.0.1\n");

A new key that is not plain-safe is quoted automatically:

use noyalib::cst::parse_document;

let mut doc = parse_document("name: foo\n").unwrap();
doc.rename_key("name", "a: b").unwrap();
assert_eq!(doc.to_string(), "\"a: b\": foo\n");
assert_eq!(doc.as_value()["a: b"].as_str(), Some("foo"));
Source

pub fn swap_items(&mut self, path: &str, i: usize, j: usize) -> Result<()>

Swap two items of the block sequence at path, exchanging each item’s whole entry — its own lines, its head-comment run included. Every other item, and the surrounding structure, stay byte-identical.

An item owns the same range here that remove deletes — owned_entry_range computes both. That is deliberate: the two have to agree about who a comment belongs to, or the same bytes are the entry’s property under one call and the slot’s under the other. A reorder that moved only value bytes would leave each comment annotating whichever item landed beneath it, silently and at Ok.

A flow sequence has no per-item lines to exchange, so its members keep the narrower value-span swap.

Guarded like the other mutators: after the two splices the document must re-parse and its typed value must equal the original with exactly items i and j exchanged, or the edit is rolled back and the document is left untouched.

Swapping an index with itself, or two items whose values are already equal, is a no-op that returns Ok(()).

§Errors
  • path does not resolve to a sequence.
  • i or j is out of bounds for that sequence.
  • The bytes of an item could not be located.
  • The splice would not re-parse, or fails the integrity check above (both roll back).
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("- a\n- b\n- c\n").unwrap();
doc.swap_items("", 0, 2).unwrap();
assert_eq!(doc.source(), "- c\n- b\n- a\n");

A comment travels with the item it documents:

use noyalib::cst::parse_document;

let mut doc = parse_document("# about one\n- one\n# about two\n- two\n").unwrap();
doc.swap_items("", 0, 1).unwrap();
assert_eq!(doc.source(), "# about two\n- two\n# about one\n- one\n");
Source

pub fn move_item(&mut self, path: &str, from: usize, to: usize) -> Result<()>

Move the item at from to index to in the block sequence at path, shifting the items in between by one. The move is applied as a run of adjacent swap_items steps, so it inherits that method’s guarantees — each item’s whole entry moves, its comments with it, structure is preserved, and each step is guarded — and the whole move is atomic: if any step is refused, the document is rolled back to its state before the call.

Moving an index to itself is a no-op that returns Ok(()).

§Errors
  • path does not resolve to a sequence.
  • from or to is out of bounds for that sequence.
  • Any underlying swap is refused; the document is left unchanged.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("- a\n- b\n- c\n- d\n").unwrap();
doc.move_item("", 0, 2).unwrap();
assert_eq!(doc.source(), "- b\n- c\n- a\n- d\n");
Source

pub fn push_back(&mut self, path: &str, fragment: &str) -> Result<()>

Append a new item to the block sequence at path.

fragment is the YAML representation of the value — the - indicator and the surrounding indentation are synthesized from the existing items so the new line matches the file’s shape. Block sequences only in this phase; flow sequences ([…]) and empty sequences are rejected.

§Errors
  • path does not resolve to a sequence.
  • The sequence is a flow collection ([…]).
  • The sequence has no existing items to anchor indentation on.
  • The fragment changed the document beyond the single item asked for — reaching outside the sequence ("v\nqq: 7") or smuggling extra items into it ("v\n - w"); the document is left unchanged.
  • The same parse-after-edit errors as Document::replace_span.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("items:\n  - one\n  - two\n").unwrap();
doc.push_back("items", "three").unwrap();
assert_eq!(doc.to_string(), "items:\n  - one\n  - two\n  - three\n");
Source

pub fn indent_unit(&self) -> usize

Detect the indentation unit (in spaces) used by this document.

Walks the source line-by-line, looks for any pair of consecutive non-empty/non-comment lines where the second is more deeply indented than the first, and returns the smallest such delta — that is the file’s “indent step”, typically 2 or 4 spaces. A document with no nested structure (or only top-level keys) has no detectable step; the default 2 is returned in that case.

Used internally by the crate::cst::Entry insertion paths to keep the inserted YAML’s inner indentation consistent with what the rest of the file already uses (2-space file → 2-space inserts; 4-space file → 4-space inserts). Exposed publicly so callers building their own emission paths can match the same convention.

§Examples
use noyalib::cst::parse_document;

let two_space = parse_document(
    "metadata:\n  labels:\n    app: noyalib\n",
).unwrap();
assert_eq!(two_space.indent_unit(), 2);

let four_space = parse_document(
    "metadata:\n    labels:\n        app: noyalib\n",
).unwrap();
assert_eq!(four_space.indent_unit(), 4);

// No nested structure — defaults to 2.
let flat = parse_document("a: 1\nb: 2\n").unwrap();
assert_eq!(flat.indent_unit(), 2);
Source

pub fn dominant_quote_style(&self) -> ScalarStyle

Inspect the document and return the dominant scalar quote style — Plain, SingleQuoted, or DoubleQuoted. Used by the crate::cst::Entry insert helpers to make new scalars adopt the file’s existing convention rather than the serializer’s hard-coded default.

The detection scans every plain / single-quoted / double-quoted scalar leaf in the green tree, picks the majority, and breaks ties in favour of the simpler form (Plain > SingleQuoted > DoubleQuoted). Empty documents and documents with no string-shaped scalars default to Plain.

§Examples
use noyalib::cst::parse_document;
use noyalib::ScalarStyle;

let single = parse_document("a: 'one'\nb: 'two'\n").unwrap();
assert_eq!(single.dominant_quote_style(), ScalarStyle::SingleQuoted);

let double = parse_document("a: \"one\"\nb: \"two\"\n").unwrap();
assert_eq!(double.dominant_quote_style(), ScalarStyle::DoubleQuoted);

let plain = parse_document("a: one\nb: two\n").unwrap();
assert_eq!(plain.dominant_quote_style(), ScalarStyle::Plain);
Source

pub fn dominant_flow_style(&self) -> FlowStyle

Inspect the document and return the dominant collection style — FlowStyle::Block or FlowStyle::Auto (equivalent to “flow”). Used by Entry::insert_value to decide whether a typed mapping / sequence emission should use block or flow form.

The detection counts top-level BlockMapping / BlockSequence vs FlowMapping / FlowSequence leaves and picks the majority. Empty / scalar-only documents default to Block.

§Examples
use noyalib::cst::parse_document;
use noyalib::FlowStyle;

let block = parse_document("a:\n  - 1\n  - 2\n").unwrap();
assert_eq!(block.dominant_flow_style(), FlowStyle::Block);

let flow = parse_document("a: [1, 2, 3]\nb: [4, 5]\n").unwrap();
assert_eq!(flow.dominant_flow_style(), FlowStyle::Auto);
Source

pub fn insert_entry( &mut self, mapping_path: &str, key: &str, fragment: &str, ) -> Result<()>

Insert a new key: fragment entry into the block mapping at mapping_path. The mapping-side analogue of Document::push_back.

Behaves like set when the key already exists (the value is replaced losslessly). When the key is new, a sibling line is spliced after the last existing entry, with the indent matched to the last entry’s key column so the file stays canonical. Block mappings only in this phase; flow mappings ({…}) and empty mappings are rejected.

Only the fragment is verbatim YAML. The key is a name: a spelling whose plain form would not re-parse to it (a: b, [x], a leading - ) is quoted automatically, exactly as Document::rename_key documents for its new key, and the existing-key check reads the mapping’s own entries — a key holding . or [ (app.io/name, ubiquitous in Kubernetes labels) inserts as that literal key rather than resolving through the path syntax.

§The fragment cannot reach outside the entry

After the splice, the document’s shape outside mapping_path must be unchanged and the mapping must have gained exactly the one entry asked for — a fragment or key that smuggles sibling entries (a line break the splice never intended, v\rc: 3) is refused and the document left untouched, the same oracle Document::set and Document::push_back apply.

§Errors
  • mapping_path does not resolve to a mapping.
  • The mapping is empty (no anchor for indentation; use set with a fragment instead).
  • key is << (the loader reads any << key as a merge directive, whatever its quote style) or carries a non-printable character.
  • key already exists but contains . or [, which the path syntax cannot address to replace its value — remove the entry and insert it afresh, or splice it with set.
  • The fragment added or removed entries beyond the one asked for (the integrity oracle above); the document is left unchanged.
  • The same parse-after-edit errors as Document::replace_span.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document(
    "metadata:\n  labels:\n    app: noyalib\n",
).unwrap();
doc.insert_entry("metadata.labels", "env", "prod").unwrap();
let out = doc.to_string();
assert!(out.contains("app: noyalib"));
assert!(out.contains("env: prod"));
Source

pub fn insert_after(&mut self, item_path: &str, fragment: &str) -> Result<()>

Insert a new sequence item immediately after the item at item_path (e.g. "items[1]").

fragment is the YAML representation of the value; the - indicator and indentation are derived from the item at item_path.

§Errors
  • item_path does not end in an index.
  • The path does not resolve to a sequence item in a block sequence.
  • The fragment changed the document beyond the single item asked for — the same containment oracle Document::push_back documents; the document is left unchanged.
  • The same parse-after-edit errors as Document::replace_span.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("items:\n  - one\n  - three\n").unwrap();
doc.insert_after("items[0]", "two").unwrap();
assert_eq!(
    doc.to_string(),
    "items:\n  - one\n  - two\n  - three\n",
);
Source

pub fn insert_entry_value<E: Emit + ?Sized>( &mut self, mapping_path: &str, key: &str, value: &E, ) -> Result<()>

Insert key: value into the block mapping at mapping_path, formatting both halves so they re-parse to exactly the key and value given.

The typed counterpart of Document::insert_entry, which splices its &str arguments verbatim: insert_entry(m, "k", "a: b") grows a nested mapping, where insert_entry_value(m, "k", "a: b") inserts the string "a: b". Quoting follows the file’s dominant scalar style except where that style would misrepresent the data, in which case quoting is forced (see Emit).

When key already exists its value is replaced in place; otherwise a sibling line is appended after the mapping’s last entry, indented to match.

After the splice the document must re-parse and its typed value must equal the pre-edit value with exactly this one entry set, or the edit is rolled back — the guard the verbatim path cannot offer, since a fragment that restructures the document is still valid YAML.

An existing key is an upsert: its value is rewritten in place, including when that value is an implicit null (a:), which is an entry the mapping already has rather than one to append. A key it only inherits through a << merge has no entry here at all, so an explicit one is created to override it.

A new key into a flow mapping — {a: 1}, {}, or a whole document spelled as one — splices , key: value before the closing brace (#338); only single-line flow mappings accept inserts.

§Errors
  • mapping_path does not resolve to a mapping, or an empty block-context mapping leaves no entry to anchor indentation on (use Document::set with a fragment).
  • The flow mapping at mapping_path spans more than one line.
  • key is << (the loader reads any << key as a merge directive, whatever its quote style) or carries a non-printable character.
  • The value has no auto-formatted spelling (see Emit::emit).
  • The splice would not re-parse, or fails the integrity check above; the document is left unchanged.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("labels:\n  app: noyalib\n").unwrap();
doc.insert_entry_value("labels", "version", "8080").unwrap();
// Quoted: the plain spelling would load as a number.
assert_eq!(
    doc.to_string(),
    "labels:\n  app: noyalib\n  version: \"8080\"\n",
);
Source

pub fn push_back_value<E: Emit + ?Sized>( &mut self, path: &str, value: &E, ) -> Result<()>

Append value to the block sequence at path, formatted so it re-parses to exactly that value.

The typed counterpart of Document::push_back, which splices its &str verbatim: push_back("items", "- x") grows a nested sequence, where push_back_value("items", "- x") appends the string "- x". Guarded by the same re-parse plus typed-value oracle as Document::insert_entry_value.

A flow sequence takes , value before its closing bracket instead of a new - line, and [] receives its first member (#338); only single-line flow collections accept inserts.

§Errors
  • path does not resolve to a sequence, or an empty block sequence leaves no item to anchor indentation on.
  • The flow sequence at path spans more than one line.
  • The value has no auto-formatted spelling (see Emit::emit).
  • The splice would not re-parse, or fails the integrity check; the document is left unchanged.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("items:\n  - one\n").unwrap();
doc.push_back_value("items", "two: 2").unwrap();
assert_eq!(doc.to_string(), "items:\n  - one\n  - \"two: 2\"\n");
Source

pub fn insert_after_value<E: Emit + ?Sized>( &mut self, item_path: &str, value: &E, ) -> Result<()>

Insert value immediately after the sequence item at item_path (e.g. "items[1]"), formatted so it re-parses to exactly that value.

The typed counterpart of Document::insert_after, guarded by the same re-parse plus typed-value oracle as Document::insert_entry_value.

Inside a single-line flow sequence the new member follows the addressed item’s own span: [a, b] after item 0 becomes [a, v, b] (#338).

§Errors
  • item_path does not end in an index, or does not resolve to a sequence item.
  • The flow sequence spans more than one line.
  • The value has no auto-formatted spelling (see Emit::emit).
  • The splice would not re-parse, or fails the integrity check; the document is left unchanged.
§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document("items:\n  - one\n  - three\n").unwrap();
doc.insert_after_value("items[0]", "two").unwrap();
assert_eq!(doc.to_string(), "items:\n  - one\n  - two\n  - three\n");
Source§

impl Document

Source

pub fn entry<'a>(&'a mut self, path: &str) -> Entry<'a>

Return a path-shaped mutable handle to the node at path.

The handle is the “pro” mutation interface — chainable, composable, ergonomic for nested edits — that complements the functional Document::set / Document::remove / Document::push_back / Document::insert_after methods (all of which remain available for direct one-shot operations).

entry itself is infallible — the path is recorded but not resolved at this point. Operations on the returned entry surface path-resolution and splice-failure errors via their own Result.

§Examples
use noyalib::cst::parse_document;

let mut doc = parse_document(
    "metadata:\n  labels:\n    app: noyalib\n",
).unwrap();
doc.entry("metadata.labels").insert("env", "prod").unwrap();

let out = doc.to_string();
assert!(out.contains("app: noyalib"));
assert!(out.contains("env: prod"));

Trait Implementations§

Source§

impl Clone for Document

Source§

fn clone(&self) -> Self

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 Debug for Document

Source§

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

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

impl Display for Document

Source§

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

Re-emit the document. For any input that parses successfully, the result equals the original bytes verbatim. Display drives Document::to_string() via the standard ToString blanket impl.

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

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> Fmt for T
where T: Display,

Source§

fn fg<C>(self, color: C) -> Foreground<Self>
where C: Into<Option<Color>>, Self: Display,

Give this value the specified foreground colour.
Source§

fn bg<C>(self, color: C) -> Background<Self>
where C: Into<Option<Color>>, Self: Display,

Give this value the specified background colour.
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> MaybeSendSync for T

Source§

impl<D> OwoColorize for D

Source§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where C: Color,

Set the foreground color generically Read more
Source§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where C: Color,

Set the background color generically. Read more
Source§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
Source§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
Source§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
Source§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
Source§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
Source§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
Source§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
Source§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
Source§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
Source§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
Source§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
Source§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
Source§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
Source§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
Source§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
Source§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
Source§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
Source§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
Source§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
Source§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
Source§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
Source§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
Source§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
Source§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
Source§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
Source§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
Source§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
Source§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
Source§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
Source§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
Source§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
Source§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
Source§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
Source§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
Source§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
Source§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
Source§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
Source§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
Source§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
Source§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
Source§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
Source§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text underlined
Make the text blink
Make the text blink (but fast!)
Source§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
Source§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
Source§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
Source§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at compile-time. If the color is constant, use either OwoColorize::fg or a color-specific method, such as OwoColorize::green, Read more
Source§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at compile-time. If the color is constant, use either OwoColorize::bg or a color-specific method, such as OwoColorize::on_yellow, Read more
Source§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
Source§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
Source§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
Source§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
Source§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
Source§

impl<T> Paint for T
where T: ?Sized,

Source§

fn fg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the foreground set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like red() and green(), which have the same functionality but are pithier.

§Example

Set foreground color to white using fg():

use yansi::{Paint, Color};

painted.fg(Color::White);

Set foreground color to white using white().

use yansi::Paint;

painted.white();
Source§

fn primary(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Primary].

§Example
println!("{}", value.primary());
Source§

fn fixed(&self, color: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Fixed].

§Example
println!("{}", value.fixed(color));
Source§

fn rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Rgb].

§Example
println!("{}", value.rgb(r, g, b));
Source§

fn black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Black].

§Example
println!("{}", value.black());
Source§

fn red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Red].

§Example
println!("{}", value.red());
Source§

fn green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Green].

§Example
println!("{}", value.green());
Source§

fn yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Yellow].

§Example
println!("{}", value.yellow());
Source§

fn blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Blue].

§Example
println!("{}", value.blue());
Source§

fn magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Magenta].

§Example
println!("{}", value.magenta());
Source§

fn cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Cyan].

§Example
println!("{}", value.cyan());
Source§

fn white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: White].

§Example
println!("{}", value.white());
Source§

fn bright_black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlack].

§Example
println!("{}", value.bright_black());
Source§

fn bright_red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightRed].

§Example
println!("{}", value.bright_red());
Source§

fn bright_green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightGreen].

§Example
println!("{}", value.bright_green());
Source§

fn bright_yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightYellow].

§Example
println!("{}", value.bright_yellow());
Source§

fn bright_blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlue].

§Example
println!("{}", value.bright_blue());
Source§

fn bright_magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.bright_magenta());
Source§

fn bright_cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightCyan].

§Example
println!("{}", value.bright_cyan());
Source§

fn bright_white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightWhite].

§Example
println!("{}", value.bright_white());
Source§

fn bg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the background set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like on_red() and on_green(), which have the same functionality but are pithier.

§Example

Set background color to red using fg():

use yansi::{Paint, Color};

painted.bg(Color::Red);

Set background color to red using on_red().

use yansi::Paint;

painted.on_red();
Source§

fn on_primary(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Primary].

§Example
println!("{}", value.on_primary());
Source§

fn on_fixed(&self, color: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Fixed].

§Example
println!("{}", value.on_fixed(color));
Source§

fn on_rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Rgb].

§Example
println!("{}", value.on_rgb(r, g, b));
Source§

fn on_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Black].

§Example
println!("{}", value.on_black());
Source§

fn on_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Red].

§Example
println!("{}", value.on_red());
Source§

fn on_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Green].

§Example
println!("{}", value.on_green());
Source§

fn on_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Yellow].

§Example
println!("{}", value.on_yellow());
Source§

fn on_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Blue].

§Example
println!("{}", value.on_blue());
Source§

fn on_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Magenta].

§Example
println!("{}", value.on_magenta());
Source§

fn on_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Cyan].

§Example
println!("{}", value.on_cyan());
Source§

fn on_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: White].

§Example
println!("{}", value.on_white());
Source§

fn on_bright_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlack].

§Example
println!("{}", value.on_bright_black());
Source§

fn on_bright_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightRed].

§Example
println!("{}", value.on_bright_red());
Source§

fn on_bright_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightGreen].

§Example
println!("{}", value.on_bright_green());
Source§

fn on_bright_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightYellow].

§Example
println!("{}", value.on_bright_yellow());
Source§

fn on_bright_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlue].

§Example
println!("{}", value.on_bright_blue());
Source§

fn on_bright_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.on_bright_magenta());
Source§

fn on_bright_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightCyan].

§Example
println!("{}", value.on_bright_cyan());
Source§

fn on_bright_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightWhite].

§Example
println!("{}", value.on_bright_white());
Source§

fn attr(&self, value: Attribute) -> Painted<&T>

Enables the styling Attribute value.

This method should be used rarely. Instead, prefer to use attribute-specific builder methods like bold() and underline(), which have the same functionality but are pithier.

§Example

Make text bold using attr():

use yansi::{Paint, Attribute};

painted.attr(Attribute::Bold);

Make text bold using using bold().

use yansi::Paint;

painted.bold();
Source§

fn bold(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Bold].

§Example
println!("{}", value.bold());
Source§

fn dim(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Dim].

§Example
println!("{}", value.dim());
Source§

fn italic(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Italic].

§Example
println!("{}", value.italic());
Source§

fn underline(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Underline].

§Example
println!("{}", value.underline());

Returns self with the attr() set to [Attribute :: Blink].

§Example
println!("{}", value.blink());

Returns self with the attr() set to [Attribute :: RapidBlink].

§Example
println!("{}", value.rapid_blink());
Source§

fn invert(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Invert].

§Example
println!("{}", value.invert());
Source§

fn conceal(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Conceal].

§Example
println!("{}", value.conceal());
Source§

fn strike(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Strike].

§Example
println!("{}", value.strike());
Source§

fn quirk(&self, value: Quirk) -> Painted<&T>

Enables the yansi Quirk value.

This method should be used rarely. Instead, prefer to use quirk-specific builder methods like mask() and wrap(), which have the same functionality but are pithier.

§Example

Enable wrapping using .quirk():

use yansi::{Paint, Quirk};

painted.quirk(Quirk::Wrap);

Enable wrapping using wrap().

use yansi::Paint;

painted.wrap();
Source§

fn mask(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Mask].

§Example
println!("{}", value.mask());
Source§

fn wrap(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Wrap].

§Example
println!("{}", value.wrap());
Source§

fn linger(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Linger].

§Example
println!("{}", value.linger());
Source§

fn clear(&self) -> Painted<&T>

👎Deprecated since 1.0.1:

renamed to resetting() due to conflicts with Vec::clear(). The clear() method will be removed in a future release.

Returns self with the quirk() set to [Quirk :: Clear].

§Example
println!("{}", value.clear());
Source§

fn resetting(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Resetting].

§Example
println!("{}", value.resetting());
Source§

fn bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Bright].

§Example
println!("{}", value.bright());
Source§

fn on_bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: OnBright].

§Example
println!("{}", value.on_bright());
Source§

fn whenever(&self, value: Condition) -> Painted<&T>

Conditionally enable styling based on whether the Condition value applies. Replaces any previous condition.

See the crate level docs for more details.

§Example

Enable styling painted only when both stdout and stderr are TTYs:

use yansi::{Paint, Condition};

painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);
Source§

fn new(self) -> Painted<Self>
where Self: Sized,

Create a new Painted with a default Style. Read more
Source§

fn paint<S>(&self, style: S) -> Painted<&Self>
where S: Into<Style>,

Apply a style wholesale to self. Any previous style is replaced. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToCompactString for T
where T: Display,

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> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. 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.
Source§

impl<T> ValidateIp for T
where T: ToString,

Source§

fn validate_ipv4(&self) -> bool

Validates whether the given string is an IP V4
Source§

fn validate_ipv6(&self) -> bool

Validates whether the given string is an IP V6
Source§

fn validate_ip(&self) -> bool

Validates whether the given string is an IP