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