1use crate::{MietteError, MietteSpanContents, SourceCode, SpanContents};
2
3#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct NamedSource<S: SourceCode + 'static> {
8 source: S,
9 name: String,
10 language: Option<String>,
11}
12
13impl<S: SourceCode> std::fmt::Debug for NamedSource<S> {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 f.debug_struct("NamedSource")
16 .field("name", &self.name)
17 .field("source", &"<redacted>")
18 .field("language", &self.language);
19 Ok(())
20 }
21}
22
23impl<S: SourceCode + 'static> NamedSource<S> {
24 pub fn new(name: impl AsRef<str>, source: S) -> Self
27 where
28 S: Send + Sync,
29 {
30 Self { source, name: name.as_ref().to_string(), language: None }
31 }
32
33 pub fn name(&self) -> &str {
35 &self.name
36 }
37
38 pub fn inner(&self) -> &S {
41 &self.source
42 }
43
44 #[must_use]
46 pub fn with_language(mut self, language: impl Into<String>) -> Self {
47 self.language = Some(language.into());
48 self
49 }
50}
51
52impl<S: SourceCode + 'static> SourceCode for NamedSource<S> {
53 fn read_span<'a>(
54 &'a self,
55 span: &crate::SourceSpan,
56 context_lines_before: usize,
57 context_lines_after: usize,
58 ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
59 let inner_contents =
60 self.inner().read_span(span, context_lines_before, context_lines_after)?;
61 let mut contents = MietteSpanContents::new_named(
62 self.name.clone(),
63 inner_contents.data(),
64 *inner_contents.span(),
65 inner_contents.line(),
66 inner_contents.column(),
67 inner_contents.line_count(),
68 );
69 if let Some(language) = &self.language {
70 contents = contents.with_language(language);
71 }
72 Ok(Box::new(contents))
73 }
74
75 fn name(&self) -> Option<&str> {
76 Some(&self.name)
77 }
78}