Skip to main content

miette/
named_source.rs

1use std::borrow::Cow;
2
3use crate::{MietteError, MietteSpanContents, SourceCode, SpanContents};
4
5/// Utility struct for when you have a regular [`SourceCode`] type that doesn't
6/// implement `name`. For example [`String`]. Or if you want to override the
7/// `name` returned by the `SourceCode`.
8#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct NamedSource<S: SourceCode + 'static> {
10    source: S,
11    name: String,
12    language: Option<String>,
13}
14
15impl<S: SourceCode> std::fmt::Debug for NamedSource<S> {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        f.debug_struct("NamedSource")
18            .field("name", &self.name)
19            .field("source", &"<redacted>")
20            .field("language", &self.language);
21        Ok(())
22    }
23}
24
25impl<S: SourceCode + 'static> NamedSource<S> {
26    /// Create a new `NamedSource` using a regular [`SourceCode`] and giving
27    /// its returned [`SpanContents`] a name.
28    pub fn new(name: impl AsRef<str>, source: S) -> Self
29    where
30        S: Send + Sync,
31    {
32        Self { source, name: name.as_ref().to_string(), language: None }
33    }
34
35    /// Gets the name of this `NamedSource`.
36    pub fn name(&self) -> &str {
37        &self.name
38    }
39
40    /// Returns a reference the inner [`SourceCode`] type for this
41    /// `NamedSource`.
42    pub fn inner(&self) -> &S {
43        &self.source
44    }
45
46    /// Sets the [`language`](SpanContents::language) for this source code.
47    #[must_use]
48    pub fn with_language(mut self, language: impl Into<String>) -> Self {
49        self.language = Some(language.into());
50        self
51    }
52}
53
54impl<S: SourceCode + 'static> SourceCode for NamedSource<S> {
55    fn read_span<'a>(
56        &'a self,
57        span: &crate::SourceSpan,
58        context_lines_before: usize,
59        context_lines_after: usize,
60    ) -> Result<MietteSpanContents<'a>, MietteError> {
61        let inner_contents =
62            self.inner().read_span(span, context_lines_before, context_lines_after)?;
63        let mut contents = MietteSpanContents::new_named(
64            Cow::Borrowed(self.name.as_str()),
65            inner_contents.data(),
66            *inner_contents.span(),
67            inner_contents.line(),
68            inner_contents.column(),
69            inner_contents.line_count(),
70        );
71        if let Some(language) = &self.language {
72            contents = contents.with_language(language);
73        }
74        Ok(contents)
75    }
76
77    fn name(&self) -> Option<&str> {
78        Some(&self.name)
79    }
80}