ndg_commonmark/syntax/
mod.rs1pub mod error;
9pub mod types;
10
11pub use error::{SyntaxError, SyntaxResult};
13pub use types::{SyntaxConfig, SyntaxHighlighter, SyntaxManager};
14
15#[cfg(all(feature = "syntastica", feature = "syntect"))]
17compile_error!(
18 "Cannot enable both 'syntastica' and 'syntect' features simultaneously. They are mutually exclusive."
19);
20
21#[cfg(feature = "syntastica")]
23mod syntastica;
24#[cfg(feature = "syntastica")]
25pub use syntastica::*;
26
27#[cfg(feature = "syntect")]
29mod syntect;
30#[cfg(feature = "syntect")]
31pub use syntect::*;
32
33pub fn create_default_manager() -> SyntaxResult<SyntaxManager> {
44 #[cfg(all(feature = "syntastica", feature = "syntect"))]
46 {
47 return Err(SyntaxError::MutuallyExclusiveBackends);
48 }
49
50 #[cfg(feature = "syntastica")]
51 {
52 return create_syntastica_manager();
53 }
54
55 #[cfg(feature = "syntect")]
56 {
57 return create_syntect_manager();
58 }
59
60 #[cfg(not(any(feature = "syntastica", feature = "syntect")))]
61 {
62 Err(SyntaxError::NoBackendAvailable)
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::{types::*, *};
69
70 #[test]
71 fn test_syntax_config_default() {
72 let config = SyntaxConfig::default();
73 assert!(config.fallback_to_plain);
74 assert!(config.language_aliases.contains_key("js"));
75 assert_eq!(config.language_aliases["js"], "javascript");
76 }
77
78 #[cfg(feature = "syntect")]
79 #[test]
80 fn test_syntect_highlighter() {
81 let highlighter = SyntectHighlighter::default();
82 assert_eq!(highlighter.name(), "Syntect");
83 assert!(!highlighter.supported_languages().is_empty());
84 assert!(!highlighter.available_themes().is_empty());
85 }
86
87 #[cfg(feature = "syntect")]
88 #[test]
89 fn test_syntect_highlight_simple() {
90 let highlighter = SyntectHighlighter::default();
91 let result = highlighter.highlight("fn main() {}", "rust", None);
92 assert!(result.is_ok());
93 let html = result.unwrap();
94 assert!(html.contains("main"));
95 }
96
97 #[cfg(feature = "syntastica")]
98 #[test]
99 fn test_syntastica_highlighter() {
100 let highlighter = SyntasticaHighlighter::new().unwrap();
101 assert_eq!(highlighter.name(), "Syntastica");
102 assert!(!highlighter.supported_languages().is_empty());
103 assert!(!highlighter.available_themes().is_empty());
104 }
105
106 #[cfg(feature = "syntastica")]
107 #[test]
108 fn test_syntastica_highlight_simple() {
109 let highlighter = SyntasticaHighlighter::new().unwrap();
110 let result = highlighter.highlight("fn main() {}", "rust", None);
111 assert!(result.is_ok());
112 let html = result.unwrap();
113 assert!(html.contains("main"));
114 }
115
116 #[cfg(any(feature = "syntastica", feature = "syntect"))]
117 #[test]
118 fn test_syntax_manager() {
119 let manager = create_default_manager().unwrap();
120 assert!(!manager.highlighter().supported_languages().is_empty());
121
122 let resolved = manager.resolve_language("js");
123 assert_eq!(resolved, "javascript");
124 }
125
126 #[cfg(any(feature = "syntastica", feature = "syntect"))]
127 #[test]
128 fn test_language_resolution() {
129 let manager = create_default_manager().unwrap();
130
131 assert_eq!(manager.resolve_language("js"), "javascript");
133 assert_eq!(manager.resolve_language("py"), "python");
134 assert_eq!(manager.resolve_language("ts"), "typescript");
135
136 assert_eq!(manager.resolve_language("rust"), "rust");
138 assert_eq!(manager.resolve_language("nix"), "nix");
139 }
140
141 #[test]
142 fn test_modular_access_to_syntax_types() {
143 use super::{
145 error::{SyntaxError, SyntaxResult},
146 types::SyntaxConfig,
147 };
148
149 let error = SyntaxError::UnsupportedLanguage("test".to_string());
151 assert!(matches!(error, SyntaxError::UnsupportedLanguage(_)));
152
153 let result: SyntaxResult<String> = Err(SyntaxError::NoBackendAvailable);
155 assert!(result.is_err());
156
157 let config = SyntaxConfig::default();
159 assert!(config.fallback_to_plain);
160 assert!(config.language_aliases.contains_key("js"));
161
162 let _config2: SyntaxConfig = SyntaxConfig::default();
164 let _error2: SyntaxError = SyntaxError::BackendError("test".to_string());
165 }
166
167 #[cfg(any(feature = "syntastica", feature = "syntect"))]
168 #[test]
169 fn test_extended_theme_availability() {
170 let manager = create_default_manager().unwrap();
171 let themes = manager.highlighter().available_themes();
172
173 assert!(
175 themes.len() > 30,
176 "Expected > 30 themes, got {}",
177 themes.len()
178 );
179
180 #[cfg(feature = "syntastica")]
182 {
183 assert!(
184 themes.contains(&"github::dark".to_string()),
185 "Expected github::dark theme"
186 );
187 assert!(
188 themes.contains(&"gruvbox::dark".to_string()),
189 "Expected gruvbox::dark theme"
190 );
191 assert!(
192 themes.contains(&"nord::nord".to_string()),
193 "Expected nord::nord theme"
194 );
195 assert!(
196 themes.contains(&"dracula::dracula".to_string()),
197 "Expected dracula::dracula theme"
198 );
199 }
200
201 #[cfg(feature = "syntect")]
202 {
203 assert!(
204 themes.contains(&"Nord".to_string()),
205 "Expected Nord theme from two-face"
206 );
207 assert!(
208 themes.contains(&"Dracula".to_string()),
209 "Expected Dracula theme from two-face"
210 );
211 assert!(
212 themes.contains(&"GruvboxDark".to_string()),
213 "Expected GruvboxDark theme from two-face"
214 );
215 assert!(
216 themes.contains(&"VisualStudioDarkPlus".to_string()),
217 "Expected VisualStudioDarkPlus theme from two-face"
218 );
219 }
220
221 println!("Available themes ({}):", themes.len());
222 for theme in &themes {
223 println!(" - {}", theme);
224 }
225 }
226
227 #[cfg(feature = "syntect")]
228 #[test]
229 fn test_nix_language_support() {
230 let manager = create_default_manager().unwrap();
231 let languages = manager.highlighter().supported_languages();
232
233 assert!(
235 languages.contains(&"nix".to_string()),
236 "Expected Nix language support via two-face"
237 );
238
239 let nix_code = r#"
243{ pkgs ? import <nixpkgs> {} }:
244
245pkgs.stdenv.mkDerivation rec {
246 pname = "hello";
247 version = "2.12";
248
249 src = pkgs.fetchurl {
250 url = "mirror://gnu/hello/${pname}-${version}.tar.gz";
251 sha256 = "1ayhp9v4m4rdhjmnl2bq3cibrbqqkgjbl3s7yk2nhlh8vj3ay16g";
252 };
253}
254"#;
255
256 let result = manager.highlight_code(nix_code, "nix", Some("Nord"));
257 assert!(
258 result.is_ok(),
259 "Failed to highlight Nix code: {:?}",
260 result.err()
261 );
262 }
263}