From 4eab70f82664c8e0eef4f5665ee3a800711d6701 Mon Sep 17 00:00:00 2001 From: Riccardo Mazzarini Date: Fri, 15 Dec 2023 13:14:19 +0100 Subject: [PATCH] refactor: add `ExtmarkVirtTextChunk` --- CHANGELOG.md | 9 +++ crates/oxi-api/src/types/extmark_infos.rs | 4 +- .../src/types/extmark_virt_text_chunk.rs | 80 +++++++++++++++++++ crates/oxi-api/src/types/mod.rs | 2 + tests/src/api/extmark.rs | 49 +++++++++--- 5 files changed, 129 insertions(+), 15 deletions(-) create mode 100644 crates/oxi-api/src/types/extmark_virt_text_chunk.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a8707db..5076f119 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## [Unreleased] +### Added + +- a new `ExtmarkVirtTextChunk` struct; + +### Changed + +- the type of `ExtmarkInfos`'s `virt_text` field from + `Option)>>` to `Vec`; + ## [0.4.0] - Dec 11 2023 [Unreleased]: https://github.com/noib3/nvim-oxi/compare/v0.4.0...HEAD diff --git a/crates/oxi-api/src/types/extmark_infos.rs b/crates/oxi-api/src/types/extmark_infos.rs index ed0dd3d1..a1fbd584 100644 --- a/crates/oxi-api/src/types/extmark_infos.rs +++ b/crates/oxi-api/src/types/extmark_infos.rs @@ -5,7 +5,7 @@ use oxi_types::{ }; use serde::Deserialize; -use super::{ExtmarkHlMode, ExtmarkVirtTextPosition, OneOrMore}; +use super::{ExtmarkHlMode, ExtmarkVirtTextChunk, ExtmarkVirtTextPosition}; /// Extmark infos returned by `Buffer::get_extmark_by_id`. #[non_exhaustive] @@ -47,7 +47,7 @@ pub struct ExtmarkInfos { pub virt_lines_leftcol: Option, #[serde(default)] - pub virt_text: Option)>>, + pub virt_text: Vec, #[serde(default)] pub virt_text_hide: Option, diff --git a/crates/oxi-api/src/types/extmark_virt_text_chunk.rs b/crates/oxi-api/src/types/extmark_virt_text_chunk.rs new file mode 100644 index 00000000..81f35564 --- /dev/null +++ b/crates/oxi-api/src/types/extmark_virt_text_chunk.rs @@ -0,0 +1,80 @@ +use oxi_types::Integer; + +use super::OneOrMore; + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct ExtmarkVirtTextChunk { + pub text: String, + pub hl_groups: Vec, +} + +impl<'de> serde::de::Deserialize<'de> for ExtmarkVirtTextChunk { + fn deserialize(deserializer: D) -> Result + where + D: serde::de::Deserializer<'de>, + { + use serde::de::{self, Visitor}; + + struct ExtmarkVirtTextChunkVisitor; + + impl<'de> Visitor<'de> for ExtmarkVirtTextChunkVisitor { + type Value = ExtmarkVirtTextChunk; + + fn expecting( + &self, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.write_str("a (text, hl_group) tuple") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + let text = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + + let hl_groups = seq + .next_element::>()? + .map(|groups| match groups { + OneOrMore::One(group) => vec![group], + OneOrMore::List(groups) => groups, + }) + .unwrap_or_default(); + + Ok(ExtmarkVirtTextChunk { text, hl_groups }) + } + } + + deserializer.deserialize_seq(ExtmarkVirtTextChunkVisitor) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize)] +#[serde(untagged)] +pub enum StringOrInt { + String(String), + Int(Integer), +} + +impl From for StringOrInt { + #[inline] + fn from(s: String) -> Self { + Self::String(s) + } +} + +impl From<&str> for StringOrInt { + #[inline] + fn from(s: &str) -> Self { + Self::String(s.to_owned()) + } +} + +impl From for StringOrInt { + #[inline] + fn from(i: Integer) -> Self { + Self::Int(i) + } +} diff --git a/crates/oxi-api/src/types/mod.rs b/crates/oxi-api/src/types/mod.rs index 0eecd13e..d5b8be3e 100644 --- a/crates/oxi-api/src/types/mod.rs +++ b/crates/oxi-api/src/types/mod.rs @@ -19,6 +19,7 @@ mod editor_context; mod extmark_hl_mode; mod extmark_infos; mod extmark_position; +mod extmark_virt_text_chunk; mod extmark_virt_text_position; mod got_mode; mod highlight_infos; @@ -66,6 +67,7 @@ pub use editor_context::*; pub use extmark_hl_mode::*; pub use extmark_infos::*; pub use extmark_position::*; +pub use extmark_virt_text_chunk::*; pub use extmark_virt_text_position::*; pub use got_mode::*; pub use highlight_infos::*; diff --git a/tests/src/api/extmark.rs b/tests/src/api/extmark.rs index f74db3e8..ebd5e7a9 100644 --- a/tests/src/api/extmark.rs +++ b/tests/src/api/extmark.rs @@ -63,16 +63,24 @@ fn get_extmarks() { assert_eq!(Some(ExtmarkHlMode::Combine), infos.hl_mode); #[cfg(feature = "neovim-nightly")] - let virt_text = vec![( - "foo".to_owned(), - vec!["Foo".to_owned(), "Bar".to_owned()].into(), - )]; + let virt_text = vec![ExtmarkVirtTextChunk { + text: "foo".to_owned(), + hl_groups: vec!["Foo".into(), "Bar".into()], + }]; #[cfg(not(feature = "neovim-nightly"))] - let virt_text = - vec![("".into(), "Foo".into()), ("foo".into(), "Bar".into())]; + let virt_text = vec![ + ExtmarkVirtTextChunk { + text: "".to_owned(), + hl_groups: vec!["Foo".into()], + }, + ExtmarkVirtTextChunk { + text: "foo".to_owned(), + hl_groups: vec!["Bar".into()], + }, + ]; - assert_eq!(Some(virt_text), infos.virt_text); + assert_eq!(infos.virt_text, virt_text); assert_eq!(Some(ExtmarkVirtTextPosition::Overlay), infos.virt_text_pos); } @@ -167,18 +175,33 @@ fn set_get_del_extmark() { #[cfg(feature = "neovim-nightly")] let virt_text = vec![ - ("foo".to_owned(), "Foo".into()), - ("bar".to_owned(), vec!["Bar".to_owned(), "Baz".to_owned()].into()), + ExtmarkVirtTextChunk { + text: "foo".to_owned(), + hl_groups: vec!["Foo".into()], + }, + ExtmarkVirtTextChunk { + text: "bar".to_owned(), + hl_groups: vec!["Bar".into(), "Baz".into()], + }, ]; #[cfg(not(feature = "neovim-nightly"))] let virt_text = vec![ - ("foo".into(), "Foo".into()), - ("".into(), "Bar".into()), - ("bar".into(), "Baz".into()), + ExtmarkVirtTextChunk { + text: "foo".to_owned(), + hl_groups: vec!["Foo".into()], + }, + ExtmarkVirtTextChunk { + text: "".to_owned(), + hl_groups: vec!["Bar".into()], + }, + ExtmarkVirtTextChunk { + text: "bar".to_owned(), + hl_groups: vec!["Baz".into()], + }, ]; - assert_eq!(Some(virt_text), infos.virt_text); + assert_eq!(infos.virt_text, virt_text); assert_eq!(Some(ExtmarkVirtTextPosition::Overlay), infos.virt_text_pos);