From ea93576c8550cb0c74ede2323b4abda1fe8a2853 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Mon, 26 May 2025 10:57:25 +0100 Subject: [PATCH 1/3] Marker: Add .character() support This provides the character index of the marker which could be used in the manipulation of source material somehow Signed-off-by: Daniel Silverstone --- marked-yaml/src/lib.rs | 2 +- marked-yaml/src/loader.rs | 32 +++++---- marked-yaml/src/spanned_serde.rs | 49 ++++++++++++-- marked-yaml/src/types.rs | 112 ++++++++++++++++++++----------- 4 files changed, 138 insertions(+), 57 deletions(-) diff --git a/marked-yaml/src/lib.rs b/marked-yaml/src/lib.rs index 6ae4af3..35e9b50 100644 --- a/marked-yaml/src/lib.rs +++ b/marked-yaml/src/lib.rs @@ -47,7 +47,7 @@ let YAML = "Daniel: Author\nUser: Not Author\n"; let roles: HashMap, Spanned> = from_yaml(0, YAML).unwrap(); assert_eq!(roles["Daniel"], "Author"); -assert_eq!(roles["User"].span().start().copied(), Some(Marker::new(0, 2, 7))); +assert_eq!(roles["User"].span().start().copied(), Some(Marker::new(0, 21, 2, 7))); ``` You do not have to have all values [`Spanned`], and you can deserialize from an already diff --git a/marked-yaml/src/loader.rs b/marked-yaml/src/loader.rs index 2acf343..4b7afa0 100644 --- a/marked-yaml/src/loader.rs +++ b/marked-yaml/src/loader.rs @@ -409,7 +409,7 @@ impl MarkedLoader { } fn marker(&self, mark: YamlMarker) -> Marker { - Marker::new(self.source, mark.line(), mark.col() + 1) + Marker::new(self.source, mark.index(), mark.line(), mark.col() + 1) } fn finish(mut self) -> Result { @@ -538,7 +538,7 @@ mod test { let err = parse_yaml(0, "foo"); assert_eq!( err, - Err(LoadError::TopLevelMustBeMapping(Marker::new(0, 1, 1))) + Err(LoadError::TopLevelMustBeMapping(Marker::new(0, 0, 1, 1))) ); assert!(format!("{}", err.err().unwrap()).contains("1:1: ")); } @@ -547,7 +547,7 @@ mod test { fn toplevel_is_sequence() { assert_eq!( parse_yaml(0, "[]"), - Err(LoadError::TopLevelMustBeMapping(Marker::new(0, 1, 1))) + Err(LoadError::TopLevelMustBeMapping(Marker::new(0, 0, 1, 1))) ); } @@ -562,8 +562,8 @@ mod test { assert_eq!( err, Err(LoadError::DuplicateKey(Box::new(DuplicateKeyInner { - prev_key: MarkedScalarNode::new(Span::new_start(Marker::new(0, 1, 1)), "foo"), - key: MarkedScalarNode::new(Span::new_start(Marker::new(0, 1, 11)), "foo") + prev_key: MarkedScalarNode::new(Span::new_start(Marker::new(0, 0, 1, 1)), "foo"), + key: MarkedScalarNode::new(Span::new_start(Marker::new(0, 10, 1, 11)), "foo") }))) ); @@ -581,7 +581,10 @@ mod test { #[test] fn unexpected_anchor() { let err = parse_yaml(0, "&foo {}"); - assert_eq!(err, Err(LoadError::UnexpectedAnchor(Marker::new(0, 1, 6)))); + assert_eq!( + err, + Err(LoadError::UnexpectedAnchor(Marker::new(0, 5, 1, 6))) + ); assert!(format!("{}", err.err().unwrap()).starts_with("1:6: ")); } @@ -589,7 +592,7 @@ mod test { fn unexpected_anchor2() { assert_eq!( parse_yaml(0, "{bar: &foo []}"), - Err(LoadError::UnexpectedAnchor(Marker::new(0, 1, 12))) + Err(LoadError::UnexpectedAnchor(Marker::new(0, 11, 1, 12))) ); } @@ -597,7 +600,7 @@ mod test { fn unexpected_anchor3() { assert_eq!( parse_yaml(0, "{bar: &foo susan}"), - Err(LoadError::UnexpectedAnchor(Marker::new(0, 1, 12))) + Err(LoadError::UnexpectedAnchor(Marker::new(0, 11, 1, 12))) ); } @@ -606,7 +609,7 @@ mod test { let err = parse_yaml(0, "{? {} : {}}"); assert_eq!( err, - Err(LoadError::MappingKeyMustBeScalar(Marker::new(0, 1, 4))) + Err(LoadError::MappingKeyMustBeScalar(Marker::new(0, 3, 1, 4))) ); assert!(format!("{}", err.err().unwrap()).starts_with("1:4: ")); } @@ -615,14 +618,17 @@ mod test { fn mapping_key_sequence() { assert_eq!( parse_yaml(0, "{? [] : {}}"), - Err(LoadError::MappingKeyMustBeScalar(Marker::new(0, 1, 4))) + Err(LoadError::MappingKeyMustBeScalar(Marker::new(0, 3, 1, 4))) ); } #[test] fn unexpected_tag() { let err = parse_yaml(0, "{foo: !!str bar}"); - assert_eq!(err, Err(LoadError::UnexpectedTag(Marker::new(0, 1, 13)))); + assert_eq!( + err, + Err(LoadError::UnexpectedTag(Marker::new(0, 12, 1, 13))) + ); assert!(format!("{}", err.err().unwrap()).starts_with("1:13: ")); } @@ -630,7 +636,7 @@ mod test { fn nested_mapping_key_mapping() { assert_eq!( parse_yaml(0, "{foo: {? [] : {}}}"), - Err(LoadError::MappingKeyMustBeScalar(Marker::new(0, 1, 10))) + Err(LoadError::MappingKeyMustBeScalar(Marker::new(0, 9, 1, 10))) ); } @@ -653,7 +659,7 @@ mod test { fn toplevel_sequence_wanted_got_mapping() { assert_eq!( parse_yaml_with_options(0, "{}", LoaderOptions::default().toplevel_sequence()), - Err(LoadError::TopLevelMustBeSequence(Marker::new(0, 1, 1))) + Err(LoadError::TopLevelMustBeSequence(Marker::new(0, 0, 1, 1))) ); } diff --git a/marked-yaml/src/spanned_serde.rs b/marked-yaml/src/spanned_serde.rs index 6df52f0..851716c 100644 --- a/marked-yaml/src/spanned_serde.rs +++ b/marked-yaml/src/spanned_serde.rs @@ -62,7 +62,7 @@ impl Spanned { /// /// ``` /// # use marked_yaml::{Spanned, Span, Marker}; - /// # let span = Span::new_start(Marker::new(0,1,2)); + /// # let span = Span::new_start(Marker::new(0, 1, 1, 2)); /// let spanned = Spanned::new(span, "Hello World"); /// assert_eq!(spanned.span(), &span); /// ``` @@ -132,18 +132,22 @@ impl Borrow for Spanned<&'_ str> { const SPANNED_TYPE: &str = "$___::marked_data::serde::Spanned"; const SPANNED_SPAN_START_SOURCE: &str = "$___::marked_data::serde::Spanned::span_start_source"; +const SPANNED_SPAN_START_CHARACTER: &str = "$___::marked_data::serde::Spanned::span_start_char"; const SPANNED_SPAN_START_LINE: &str = "$___::marked_data::serde::Spanned::span_start_line"; const SPANNED_SPAN_START_COLUMN: &str = "$___::marked_data::serde::Spanned::span_start_column"; const SPANNED_SPAN_END_SOURCE: &str = "$___::marked_data::serde::Spanned::span_end_source"; +const SPANNED_SPAN_END_CHARACTER: &str = "$___::marked_data::serde::Spanned::span_end_char"; const SPANNED_SPAN_END_LINE: &str = "$___::marked_data::serde::Spanned::span_end_line"; const SPANNED_SPAN_END_COLUMN: &str = "$___::marked_data::serde::Spanned::span_end_column"; const SPANNED_INNER: &str = "$___::marked_data::serde::Spanned::inner"; -const SPANNED_FIELDS: [&str; 7] = [ +const SPANNED_FIELDS: [&str; 9] = [ SPANNED_SPAN_START_SOURCE, + SPANNED_SPAN_START_CHARACTER, SPANNED_SPAN_START_LINE, SPANNED_SPAN_START_COLUMN, SPANNED_SPAN_END_SOURCE, + SPANNED_SPAN_END_CHARACTER, SPANNED_SPAN_END_LINE, SPANNED_SPAN_END_COLUMN, SPANNED_INNER, @@ -177,6 +181,12 @@ where let span_start = if key == Some(SPANNED_SPAN_START_SOURCE) { let source: usize = visitor.next_value()?; + if visitor.next_key()? != Some(SPANNED_SPAN_START_CHARACTER) { + return Err(serde::de::Error::custom( + "marked node span start character missing", + )); + } + let character: usize = visitor.next_value()?; if visitor.next_key()? != Some(SPANNED_SPAN_START_LINE) { return Err(serde::de::Error::custom( "marked node span start line missing", @@ -190,13 +200,19 @@ where } let column: usize = visitor.next_value()?; key = visitor.next_key()?; - Some(Marker::new(source, line, column)) + Some(Marker::new(source, character, line, column)) } else { None }; let span_end = if key == Some(SPANNED_SPAN_END_SOURCE) { let source: usize = visitor.next_value()?; + if visitor.next_key()? != Some(SPANNED_SPAN_END_CHARACTER) { + return Err(serde::de::Error::custom( + "marked node span end character missing", + )); + } + let character: usize = visitor.next_value()?; if visitor.next_key()? != Some(SPANNED_SPAN_END_LINE) { return Err(serde::de::Error::custom( "marked node span end line missing", @@ -210,7 +226,7 @@ where } let column: usize = visitor.next_value()?; key = visitor.next_key()?; - Some(Marker::new(source, line, column)) + Some(Marker::new(source, character, line, column)) } else { None }; @@ -834,9 +850,11 @@ struct SpannedDeserializer<'de, T> { enum SpannedDeserializerState { SendStartSource, + SendStartCharacter, SendStartLine, SendStartColumn, SendEndSource, + SendEndCharacter, SendEndLine, SendEndColumn, SendValue, @@ -872,9 +890,11 @@ where { let key = match self.state { SpannedDeserializerState::SendStartSource => SPANNED_SPAN_START_SOURCE, + SpannedDeserializerState::SendStartCharacter => SPANNED_SPAN_START_CHARACTER, SpannedDeserializerState::SendStartLine => SPANNED_SPAN_START_LINE, SpannedDeserializerState::SendStartColumn => SPANNED_SPAN_START_COLUMN, SpannedDeserializerState::SendEndSource => SPANNED_SPAN_END_SOURCE, + SpannedDeserializerState::SendEndCharacter => SPANNED_SPAN_END_CHARACTER, SpannedDeserializerState::SendEndLine => SPANNED_SPAN_END_LINE, SpannedDeserializerState::SendEndColumn => SPANNED_SPAN_END_COLUMN, SpannedDeserializerState::SendValue => SPANNED_INNER, @@ -896,6 +916,16 @@ where .start() .expect("Span missing start") .source(); + self.state = SpannedDeserializerState::SendStartCharacter; + seed.deserialize(v.into_deserializer()) + } + SpannedDeserializerState::SendStartCharacter => { + let v = self + .node + .mark_span() + .start() + .expect("Span missing start") + .character(); self.state = SpannedDeserializerState::SendStartLine; seed.deserialize(v.into_deserializer()) } @@ -930,6 +960,16 @@ where .end() .expect("Span missing end") .source(); + self.state = SpannedDeserializerState::SendEndCharacter; + seed.deserialize(v.into_deserializer()) + } + SpannedDeserializerState::SendEndCharacter => { + let v = self + .node + .mark_span() + .end() + .expect("Span missing end") + .character(); self.state = SpannedDeserializerState::SendEndLine; seed.deserialize(v.into_deserializer()) } @@ -1504,6 +1544,7 @@ shouting: TRUE Error::IntegerParseFailure(_e, s) => { let start = s.start().unwrap(); assert_eq!(start.source(), 0); + assert_eq!(start.character(), 93); assert_eq!(start.line(), 4); assert_eq!(start.column(), 21); } diff --git a/marked-yaml/src/types.rs b/marked-yaml/src/types.rs index aec5691..2e676ea 100644 --- a/marked-yaml/src/types.rs +++ b/marked-yaml/src/types.rs @@ -54,11 +54,12 @@ where /// let map = node.as_mapping().unwrap(); /// let bar = map.get("foo").unwrap(); /// // the "bar" string started on line 1, column 7 of source ID 100. -/// assert_eq!(bar.span().start(), Some(&Marker::new(100, 1, 7))); +/// assert_eq!(bar.span().start(), Some(&Marker::new(100, 6, 1, 7))); /// ``` #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Marker { source: usize, + character: usize, line: usize, column: usize, } @@ -72,14 +73,16 @@ impl Marker { /// /// ``` /// # use marked_yaml::Marker; - /// let marker = Marker::new(0, 1, 2); + /// let marker = Marker::new(0, 3, 1, 2); /// # assert_eq!(marker.source(), 0); + /// # assert_eq!(marker.character(), 3); /// # assert_eq!(marker.line(), 1); /// # assert_eq!(marker.column(), 2); /// ``` - pub fn new(source: usize, line: usize, column: usize) -> Self { + pub fn new(source: usize, character: usize, line: usize, column: usize) -> Self { Self { source, + character, line, column, } @@ -96,13 +99,29 @@ impl Marker { /// /// ``` /// # use marked_yaml::Marker; - /// # let marker = Marker::new(0, 1, 2); + /// # let marker = Marker::new(0, 3, 1, 2); /// assert_eq!(marker.source(), 0); /// ``` pub fn source(&self) -> usize { self.source } + /// The character index at which this marker resides + /// + /// When parsing YAML, we record where nodes start (and often finish). + /// This is the character index into the source text of where this + /// marker resides. Character indices start with zero since they're + /// meant for software rather than humans. + /// + /// ``` + /// # use marked_yaml::Marker; + /// # let marker = Marker::new(0, 3, 1, 2); + /// assert_eq!(marker.character(), 3); + /// ``` + pub fn character(&self) -> usize { + self.character + } + /// The line number on which this marker resides, 1-indexed /// /// When parsing YAML, we record where nodes start (and often finish). @@ -111,7 +130,7 @@ impl Marker { /// /// ``` /// # use marked_yaml::Marker; - /// # let marker = Marker::new(0, 1, 2); + /// # let marker = Marker::new(0, 3, 1, 2); /// assert_eq!(marker.line(), 1); /// ``` pub fn line(&self) -> usize { @@ -126,7 +145,7 @@ impl Marker { /// /// ``` /// # use marked_yaml::Marker; - /// # let marker = Marker::new(0, 1, 2); + /// # let marker = Marker::new(0, 3, 1, 2); /// assert_eq!(marker.column(), 2); /// ``` pub fn column(&self) -> usize { @@ -142,7 +161,7 @@ impl Marker { /// /// ``` /// # use marked_yaml::Marker; - /// # let marker = Marker::new(0, 1, 2); + /// # let marker = Marker::new(0, 3, 1, 2); /// let rendered = marker.render(|_| "name"); /// assert_eq!(format!("{}", rendered), "name:1:2") /// ``` @@ -162,7 +181,7 @@ impl Marker { /// /// ``` /// # use marked_yaml::Marker; - /// # let mut marker = Marker::new(0, 0, 0); + /// # let mut marker = Marker::new(0, 0, 0, 0); /// assert_ne!(marker.source(), 1); /// marker.set_source(1); /// assert_eq!(marker.source(), 1); @@ -171,11 +190,25 @@ impl Marker { self.source = source; } + /// Set the character index for this marker + /// + /// + /// ``` + /// # use marked_yaml::Marker; + /// # let mut marker = Marker::new(0, 0, 0, 0); + /// assert_ne!(marker.character(), 1); + /// marker.set_character(1); + /// assert_eq!(marker.character(), 1); + /// ``` + pub fn set_character(&mut self, character: usize) { + self.character = character; + } + /// Set the line number for this marker /// /// ``` /// # use marked_yaml::Marker; - /// # let mut marker = Marker::new(0, 0, 0); + /// # let mut marker = Marker::new(0, 0, 0, 0); /// assert_ne!(marker.line(), 1); /// marker.set_line(1); /// assert_eq!(marker.line(), 1); @@ -188,7 +221,7 @@ impl Marker { /// /// ``` /// # use marked_yaml::Marker; - /// # let mut marker = Marker::new(0, 0, 0); + /// # let mut marker = Marker::new(0, 0, 0, 0); /// assert_ne!(marker.column(), 1); /// marker.set_column(1); /// assert_eq!(marker.column(), 1); @@ -210,7 +243,7 @@ impl Display for Marker { /// use marked_yaml::{parse_yaml, Marker, Span}; /// let node = parse_yaml(100, "{foo: bar}").unwrap(); /// let map = node.as_mapping().unwrap(); -/// assert_eq!(map.span(), &Span::new_with_marks(Marker::new(100, 1, 1), Marker::new(100, 1, 10))); +/// assert_eq!(map.span(), &Span::new_with_marks(Marker::new(100, 0, 1, 1), Marker::new(100, 9, 1, 10))); /// ``` #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Span { @@ -245,8 +278,8 @@ impl Span { /// /// ``` /// # use marked_yaml::{Marker, Span}; - /// let span = Span::new_start(Marker::new(0, 1, 2)); - /// # assert_eq!(span.start().unwrap(), &Marker::new(0, 1, 2)); + /// let span = Span::new_start(Marker::new(0, 1, 1, 2)); + /// # assert_eq!(span.start().unwrap(), &Marker::new(0, 1, 1, 2)); /// # assert_eq!(span.end(), None); /// ``` pub fn new_start(start: Marker) -> Self { @@ -263,9 +296,9 @@ impl Span { /// /// ``` /// # use marked_yaml::{Marker,Span}; - /// let span = Span::new_with_marks(Marker::new(0, 1, 1), Marker::new(10, 2, 1)); - /// # assert_eq!(span.start().unwrap(), &Marker::new(0, 1, 1)); - /// # assert_eq!(span.end().unwrap(), &Marker::new(10, 2, 1)); + /// let span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1)); + /// # assert_eq!(span.start().unwrap(), &Marker::new(0, 0, 1, 1)); + /// # assert_eq!(span.end().unwrap(), &Marker::new(10, 1, 2, 1)); /// ``` pub fn new_with_marks(start: Marker, end: Marker) -> Self { Self { @@ -278,8 +311,8 @@ impl Span { /// /// ``` /// # use marked_yaml::{Marker, Span}; - /// # let span = Span::new_with_marks(Marker::new(0, 1, 1), Marker::new(10, 2, 1)); - /// assert_eq!(span.start(), Some(&Marker::new(0, 1, 1))); + /// # let span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1)); + /// assert_eq!(span.start(), Some(&Marker::new(0, 0, 1, 1))); /// ``` pub fn start(&self) -> Option<&Marker> { self.start.as_ref() @@ -289,8 +322,8 @@ impl Span { /// /// ``` /// # use marked_yaml::{Marker, Span}; - /// # let span = Span::new_with_marks(Marker::new(0, 1, 1), Marker::new(10, 2, 1)); - /// assert_eq!(span.end(), Some(&Marker::new(10, 2, 1))); + /// # let span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1)); + /// assert_eq!(span.end(), Some(&Marker::new(10, 1, 2, 1))); /// ``` pub fn end(&self) -> Option<&Marker> { self.end.as_ref() @@ -300,9 +333,9 @@ impl Span { /// /// ``` /// # use marked_yaml::{Marker, Span}; - /// # let mut span = Span::new_with_marks(Marker::new(0, 1, 1), Marker::new(10, 2, 1)); + /// # let mut span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1)); /// span.start_mut().unwrap().set_line(5); - /// assert_eq!(span.start(), Some(&Marker::new(0, 5, 1))); + /// assert_eq!(span.start(), Some(&Marker::new(0, 0, 5, 1))); /// ``` pub fn start_mut(&mut self) -> Option<&mut Marker> { self.start.as_mut() @@ -312,9 +345,9 @@ impl Span { /// /// ``` /// # use marked_yaml::{Marker, Span}; - /// # let mut span = Span::new_with_marks(Marker::new(0, 1, 1), Marker::new(10, 2, 1)); + /// # let mut span = Span::new_with_marks(Marker::new(0, 0, 1, 1), Marker::new(10, 1, 2, 1)); /// span.end_mut().unwrap().set_line(5); - /// assert_eq!(span.end(), Some(&Marker::new(10, 5, 1))); + /// assert_eq!(span.end(), Some(&Marker::new(10, 1, 5, 1))); /// ``` pub fn end_mut(&mut self) -> Option<&mut Marker> { self.end.as_mut() @@ -326,8 +359,8 @@ impl Span { /// # use marked_yaml::{Marker, Span}; /// # let mut span = Span::new_blank(); /// assert_eq!(span.start(), None); - /// span.set_start(Some(Marker::new(0, 1, 2))); - /// assert_eq!(span.start(), Some(&Marker::new(0, 1, 2))); + /// span.set_start(Some(Marker::new(0, 1, 1, 2))); + /// assert_eq!(span.start(), Some(&Marker::new(0, 1, 1, 2))); /// ``` pub fn set_start(&mut self, start: Option) { self.start = start; @@ -339,8 +372,8 @@ impl Span { /// # use marked_yaml::{Marker, Span}; /// # let mut span = Span::new_blank(); /// assert_eq!(span.end(), None); - /// span.set_end(Some(Marker::new(0, 1, 2))); - /// assert_eq!(span.end(), Some(&Marker::new(0, 1, 2))); + /// span.set_end(Some(Marker::new(0, 1, 1, 2))); + /// assert_eq!(span.end(), Some(&Marker::new(0, 1, 1, 2))); /// ``` pub fn set_end(&mut self, end: Option) { self.end = end; @@ -392,7 +425,7 @@ pub enum Node { /// let map = node.as_mapping().unwrap(); /// let bar = map.get("foo").unwrap(); /// // the "bar" string started on line 1, column 7 of source ID 100. -/// assert_eq!(bar.span().start(), Some(&Marker::new(100, 1, 7))); +/// assert_eq!(bar.span().start(), Some(&Marker::new(100, 6, 1, 7))); /// ``` #[derive(Clone, Debug)] pub struct MarkedScalarNode { @@ -418,7 +451,7 @@ pub(crate) type MappingHash = LinkedHashMap; /// use marked_yaml::{parse_yaml, Marker, Span}; /// let node = parse_yaml(100, "{foo: bar}").unwrap(); /// let map = node.as_mapping().unwrap(); -/// assert_eq!(map.span(), &Span::new_with_marks(Marker::new(100, 1, 1), Marker::new(100, 1, 10))); +/// assert_eq!(map.span(), &Span::new_with_marks(Marker::new(100, 0, 1, 1), Marker::new(100, 9, 1, 10))); /// ``` #[derive(Clone, Debug)] pub struct MarkedMappingNode { @@ -439,7 +472,7 @@ pub struct MarkedMappingNode { /// let map = node.as_mapping().unwrap(); /// let seq = map.get("foo").unwrap(); /// let seq = seq.as_sequence().unwrap(); -/// assert_eq!(seq.span(), &Span::new_with_marks(Marker::new(100, 1, 7), Marker::new(100, 1, 11))); +/// assert_eq!(seq.span(), &Span::new_with_marks(Marker::new(100, 6, 1, 7), Marker::new(100, 10, 1, 11))); /// ``` #[derive(Clone, Debug)] pub struct MarkedSequenceNode { @@ -538,8 +571,8 @@ assert_eq!(node.span(), &Span::new_blank()); let mut node = "#, stringify!($t), r#"::new_empty(Span::new_blank()); -node.span_mut().set_start(Some(Marker::new(0, 1, 0))); -assert_eq!(node.span().start(), Some(&Marker::new(0, 1, 0))); +node.span_mut().set_start(Some(Marker::new(0, 0, 1, 0))); +assert_eq!(node.span().start(), Some(&Marker::new(0, 0, 1, 0))); ```"# ), pub fn span_mut(&mut self) -> &mut Span { @@ -578,8 +611,8 @@ impl Node { /// let mut node: Node = "foobar".into(); /// let mut span = node.span_mut(); /// assert_eq!(span.start(), None); - /// span.set_start(Some(Marker::new(0, 1, 0))); - /// assert_eq!(span.start(), Some(&Marker::new(0, 1, 0))); + /// span.set_start(Some(Marker::new(0, 0, 1, 0))); + /// assert_eq!(span.start(), Some(&Marker::new(0, 0, 1, 0))); /// ``` pub fn span_mut(&mut self) -> &mut Span { match self { @@ -1388,8 +1421,9 @@ mod test { #[test] fn basic_marker_checks() { - let marker = Marker::new(0, 1, 2); + let marker = Marker::new(0, 3, 1, 2); assert_eq!(marker.source(), 0); + assert_eq!(marker.character(), 3); assert_eq!(marker.line(), 1); assert_eq!(marker.column(), 2); assert_eq!(format!("{}", marker), "1:2"); @@ -1405,8 +1439,8 @@ mod test { let span = Span::new_blank(); assert_eq!(span.start(), None); assert_eq!(span.end(), None); - let mark = Marker::new(0, 1, 2); - let mark2 = Marker::new(3, 4, 5); + let mark = Marker::new(0, 1, 1, 2); + let mark2 = Marker::new(3, 9, 4, 5); let span = Span::new_start(mark); assert_eq!(span.start(), Some(&mark)); assert_eq!(span.end(), None); @@ -1432,7 +1466,7 @@ mod test { // Now check the spans assert_eq!(node.span(), map.span()); let seq = map.get_sequence("heterogenous").unwrap(); - assert_eq!(seq.span().start(), Some(&Marker::new(0, 24, 3))); + assert_eq!(seq.span().start(), Some(&Marker::new(0, 431, 24, 3))); assert_eq!(seq.span(), map.get_node("heterogenous").unwrap().span()); // Helpers for the sequence node assert_eq!(seq.get_node(0), seq.first()); From 373c20c321a72062430c9ad68ca1346a29ceb392 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Mon, 26 May 2025 11:12:37 +0100 Subject: [PATCH 2/3] marked-yaml: Test .character() some more This is the example case provided by @hougesen on #24 which is not completely ideal. Not least, we don't actually have a reliable end marker with the current YAML parser we're using. Signed-off-by: Daniel Silverstone --- marked-yaml/tests/character.rs | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 marked-yaml/tests/character.rs diff --git a/marked-yaml/tests/character.rs b/marked-yaml/tests/character.rs new file mode 100644 index 0000000..0ab690e --- /dev/null +++ b/marked-yaml/tests/character.rs @@ -0,0 +1,44 @@ +//! All the tests in here relate to the ability to get character offsets for things. + +#[test] +fn fix_24_character_offset_works() { + let input = r#"# some comment + +key: value # another comment +"# + .to_string(); + + let document = marked_yaml::parse_yaml(0, &input).unwrap(); + + // With the above shape, we know the document is a mapping, so let's retrieve + // the "key" value from it + + let node = document.as_mapping().unwrap().get_scalar("key").unwrap(); + let span = node.span(); + eprintln!("{span:?}"); + eprintln!("{node:?}"); + let (start, end) = ( + span.start().unwrap().character(), + // Because span.end() isn't reliable for scalar nodes right now, + // if there's no end marker, try and synthesise it from the node's value. + // This is unreliable because the node might have been folded, or had escaped + // characters in it which we won't notice. + span.end() + .map(marked_yaml::Marker::character) + .unwrap_or_else(|| span.start().unwrap().character() + node.as_str().chars().count()), + ); + + let output = input + .chars() + .take(start) + .chain("new_value".chars()) + .chain(input.chars().skip(end)) + .collect::(); + + let expected_output = r#"# some comment + +key: new_value # another comment +"#; + + assert_eq!(output, expected_output); +} From 803ed682468f678c3d8cd701066b9e816a86be3e Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Mon, 26 May 2025 11:23:14 +0100 Subject: [PATCH 3/3] chore: Update to cache@v4 Signed-off-by: Daniel Silverstone --- .github/workflows/basic.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/basic.yaml b/.github/workflows/basic.yaml index ff45efa..95f2cd7 100644 --- a/.github/workflows/basic.yaml +++ b/.github/workflows/basic.yaml @@ -55,12 +55,12 @@ jobs: path: ~/.cargo/registry key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - name: Cache cargo git trees - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.cargo/git key: ${{ runner.os }}-cargo-gits-${{ hashFiles('**/Cargo.lock') }} - name: Cache cargo build - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: target key: ${{ runner.os }}-cargo-build-${{ matrix.target }}-${{ steps.rustc.outputs.commit_hash }}-${{ hashFiles('**/Cargo.lock') }}