• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! This module provides a trait for creating custom syntax highlighters that
2 //! highlight [`Diagnostic`](crate::Diagnostic) source code with ANSI escape
3 //! sequences when rendering with the [`GraphicalReportHighlighter`](crate::GraphicalReportHandler).
4 //!
5 //! It also provides built-in highlighter implementations that you can use out of the box.
6 //! By default, there are no syntax highlighters exported by miette
7 //! (except for the no-op [`BlankHighlighter`]).
8 //! To enable support for specific highlighters, you should enable their associated feature flag.
9 //!
10 //! Currently supported syntax highlighters and their feature flags:
11 //! * `syntect-highlighter` - Enables [`syntect`](https://docs.rs/syntect/latest/syntect/) syntax highlighting support via the [`SyntectHighlighter`]
12 //!
13 
14 use std::{ops::Deref, sync::Arc};
15 
16 use crate::SpanContents;
17 use owo_colors::Styled;
18 
19 #[cfg(feature = "syntect-highlighter")]
20 pub use self::syntect::*;
21 pub use blank::*;
22 
23 mod blank;
24 #[cfg(feature = "syntect-highlighter")]
25 mod syntect;
26 
27 /// A syntax highlighter for highlighting miette [`SourceCode`](crate::SourceCode) snippets.
28 pub trait Highlighter {
29     ///  Creates a new [HighlighterState] to begin parsing and highlighting
30     /// a [SpanContents].
31     ///
32     /// The [GraphicalReportHandler](crate::GraphicalReportHandler) will call
33     /// this method at the start of rendering a [SpanContents].
34     ///
35     /// The [SpanContents] is provided as input only so that the [Highlighter]
36     /// can detect language syntax and make other initialization decisions prior
37     /// to highlighting, but it is not intended that the Highlighter begin
38     /// highlighting at this point. The returned [HighlighterState] is
39     /// responsible for the actual rendering.
start_highlighter_state<'h>( &'h self, source: &dyn SpanContents<'_>, ) -> Box<dyn HighlighterState + 'h>40     fn start_highlighter_state<'h>(
41         &'h self,
42         source: &dyn SpanContents<'_>,
43     ) -> Box<dyn HighlighterState + 'h>;
44 }
45 
46 /// A stateful highlighter that incrementally highlights lines of a particular
47 /// source code.
48 ///
49 /// The [GraphicalReportHandler](crate::GraphicalReportHandler)
50 /// will create a highlighter state by calling
51 /// [start_highlighter_state](Highlighter::start_highlighter_state) at the
52 /// start of rendering, then it will iteratively call
53 /// [highlight_line](HighlighterState::highlight_line) to render individual
54 /// highlighted lines. This allows [Highlighter] implementations to maintain
55 /// mutable parsing and highlighting state.
56 pub trait HighlighterState {
57     /// Highlight an individual line from the source code by returning a vector of [Styled]
58     /// regions.
highlight_line<'s>(&mut self, line: &'s str) -> Vec<Styled<&'s str>>59     fn highlight_line<'s>(&mut self, line: &'s str) -> Vec<Styled<&'s str>>;
60 }
61 
62 /// Arcified trait object for Highlighter. Used internally by [GraphicalReportHandler]
63 ///
64 /// Wrapping the trait object in this way allows us to implement Debug and Clone.
65 #[derive(Clone)]
66 #[repr(transparent)]
67 pub(crate) struct MietteHighlighter(Arc<dyn Highlighter + Send + Sync>);
68 
69 impl MietteHighlighter {
nocolor() -> Self70     pub(crate) fn nocolor() -> Self {
71         Self::from(BlankHighlighter)
72     }
73 
74     #[cfg(feature = "syntect-highlighter")]
syntect_truecolor() -> Self75     pub(crate) fn syntect_truecolor() -> Self {
76         Self::from(SyntectHighlighter::default())
77     }
78 }
79 
80 impl Default for MietteHighlighter {
81     #[cfg(feature = "syntect-highlighter")]
default() -> Self82     fn default() -> Self {
83         use std::io::IsTerminal;
84         match std::env::var("NO_COLOR") {
85             _ if !std::io::stdout().is_terminal() || !std::io::stderr().is_terminal() => {
86                 //TODO: should use ANSI styling instead of 24-bit truecolor here
87                 Self(Arc::new(SyntectHighlighter::default()))
88             }
89             Ok(string) if string != "0" => MietteHighlighter::nocolor(),
90             _ => Self(Arc::new(SyntectHighlighter::default())),
91         }
92     }
93     #[cfg(not(feature = "syntect-highlighter"))]
default() -> Self94     fn default() -> Self {
95         return MietteHighlighter::nocolor();
96     }
97 }
98 
99 impl<T: Highlighter + Send + Sync + 'static> From<T> for MietteHighlighter {
from(value: T) -> Self100     fn from(value: T) -> Self {
101         Self(Arc::new(value))
102     }
103 }
104 
105 impl std::fmt::Debug for MietteHighlighter {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result106     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107         write!(f, "MietteHighlighter(...)")
108     }
109 }
110 
111 impl Deref for MietteHighlighter {
112     type Target = dyn Highlighter + Send + Sync;
deref(&self) -> &Self::Target113     fn deref(&self) -> &Self::Target {
114         &*self.0
115     }
116 }
117