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