mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-24 01:46:31 +00:00
Add SpannedStr and SpannedText
This commit is contained in:
parent
5b4600f54b
commit
7218b6c879
@ -3,6 +3,7 @@
|
|||||||
//! This module defines various structs describing a span of text from a
|
//! This module defines various structs describing a span of text from a
|
||||||
//! larger string.
|
//! larger string.
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// A string with associated spans.
|
/// A string with associated spans.
|
||||||
///
|
///
|
||||||
@ -13,6 +14,78 @@ pub struct SpannedString<T> {
|
|||||||
spans: Vec<IndexedSpan<T>>,
|
spans: Vec<IndexedSpan<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The immutable, borrowed equivalent of `SpannedString`.
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct SpannedStr<'a, T>
|
||||||
|
where
|
||||||
|
T: 'a,
|
||||||
|
{
|
||||||
|
source: &'a str,
|
||||||
|
spans: &'a [IndexedSpan<T>],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Describes an object that appears like a `SpannedStr`.
|
||||||
|
pub trait SpannedText<T> {
|
||||||
|
/// Returns the source text.
|
||||||
|
fn source(&self) -> &str;
|
||||||
|
|
||||||
|
/// Returns the spans for this text.
|
||||||
|
fn spans(&self) -> &[IndexedSpan<T>];
|
||||||
|
|
||||||
|
/// Returns a `SpannedText` by reference.
|
||||||
|
fn as_ref<'a>(&'a self) -> SpannedTextRef<'a, T, Self> {
|
||||||
|
SpannedTextRef {
|
||||||
|
r: self,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A reference to another `SpannedText`.
|
||||||
|
pub struct SpannedTextRef<'a, T, C>
|
||||||
|
where
|
||||||
|
C: 'a + SpannedText<T> + ?Sized,
|
||||||
|
{
|
||||||
|
r: &'a C,
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> SpannedText<T> for &'a SpannedString<T> {
|
||||||
|
fn source(&self) -> &str {
|
||||||
|
&self.source
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spans(&self) -> &[IndexedSpan<T>] {
|
||||||
|
&self.spans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, C> SpannedText<T> for SpannedTextRef<'a, T, C>
|
||||||
|
where
|
||||||
|
C: 'a + SpannedText<T> + ?Sized,
|
||||||
|
{
|
||||||
|
fn source(&self) -> &str {
|
||||||
|
self.r.source()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spans(&self) -> &[IndexedSpan<T>] {
|
||||||
|
self.r.spans()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> SpannedText<T> for SpannedStr<'a, T>
|
||||||
|
where
|
||||||
|
T: 'a,
|
||||||
|
{
|
||||||
|
fn source(&self) -> &str {
|
||||||
|
self.source
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spans(&self) -> &[IndexedSpan<T>] {
|
||||||
|
self.spans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, T> From<S> for SpannedString<T>
|
impl<S, T> From<S> for SpannedString<T>
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
@ -23,12 +96,72 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T> SpannedStr<'a, T>
|
||||||
|
where
|
||||||
|
T: 'a,
|
||||||
|
{
|
||||||
|
/// Creates a new `SpannedStr` from the given references.
|
||||||
|
pub fn new(source: &'a str, spans: &'a [IndexedSpan<T>]) -> Self {
|
||||||
|
SpannedStr { source, spans }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gives access to the parsed styled spans.
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
|
||||||
|
pub fn spans<'b>(&self) -> Vec<Span<'a, T>> {
|
||||||
|
self.spans
|
||||||
|
.iter()
|
||||||
|
.map(|span| span.resolve(self.source))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the indexed spans.
|
||||||
|
pub fn spans_raw(&self) -> &'a [IndexedSpan<T>] {
|
||||||
|
self.spans
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the source (non-parsed) string.
|
||||||
|
pub fn source(&self) -> &'a str {
|
||||||
|
self.source
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `self` is empty.
|
||||||
|
///
|
||||||
|
/// Can be caused by an empty source, or no span.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.source.is_empty() || self.spans.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Clone for SpannedStr<'a, T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
SpannedStr {
|
||||||
|
source: self.source,
|
||||||
|
spans: self.spans,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpannedString<()> {
|
||||||
|
/// Returns a simple spanned string without any attribute.
|
||||||
|
pub fn plain<S>(content: S) -> Self
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
Self::single_span(content, ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> SpannedString<T> {
|
impl<T> SpannedString<T> {
|
||||||
|
/// Returns an empty `SpannedString`.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::with_spans(String::new(), Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new `SpannedString` manually.
|
/// Creates a new `SpannedString` manually.
|
||||||
///
|
///
|
||||||
/// It is not recommended to use this directly.
|
/// It is not recommended to use this directly.
|
||||||
/// Instead, look for methods like `Markdown::parse`.
|
/// Instead, look for methods like `Markdown::parse`.
|
||||||
pub fn new<S>(source: S, spans: Vec<IndexedSpan<T>>) -> Self
|
pub fn with_spans<S>(source: S, spans: Vec<IndexedSpan<T>>) -> Self
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
@ -46,7 +179,12 @@ impl<T> SpannedString<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new SpannedString with a single span.
|
/// Returns a new SpannedString with a single span.
|
||||||
pub fn single_span(source: String, attr: T) -> Self {
|
pub fn single_span<S>(source: S, attr: T) -> Self
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
let source = source.into();
|
||||||
|
|
||||||
let spans = vec![
|
let spans = vec![
|
||||||
IndexedSpan {
|
IndexedSpan {
|
||||||
content: IndexedCow::Borrowed {
|
content: IndexedCow::Borrowed {
|
||||||
@ -57,7 +195,7 @@ impl<T> SpannedString<T> {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
Self::new(source, spans)
|
Self::with_spans(source, spans)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends the given `StyledString` to `self`.
|
/// Appends the given `StyledString` to `self`.
|
||||||
@ -110,6 +248,11 @@ impl<T> SpannedString<T> {
|
|||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.source.is_empty() || self.spans.is_empty()
|
self.source.is_empty() || self.spans.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a `SpannedStr` referencing `self`.
|
||||||
|
pub fn as_spanned_str<'a>(&'a self) -> SpannedStr<'a, T> {
|
||||||
|
SpannedStr::new(&self.source, &self.spans)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An indexed span with an associated attribute.
|
/// An indexed span with an associated attribute.
|
||||||
@ -148,6 +291,17 @@ impl<T> IndexedSpan<T> {
|
|||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.content.is_empty()
|
self.content.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a single span around the entire text.
|
||||||
|
pub fn simple(content: &str, attr: T) -> Self {
|
||||||
|
IndexedSpan {
|
||||||
|
content: IndexedCow::Borrowed {
|
||||||
|
start: 0,
|
||||||
|
end: content.len(),
|
||||||
|
},
|
||||||
|
attr,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A span of text that can be either owned, or indexed in another String.
|
/// A span of text that can be either owned, or indexed in another String.
|
||||||
|
Loading…
Reference in New Issue
Block a user