1pub mod config;
2pub mod directives;
3pub mod formatter;
4pub mod parser;
5pub mod syntax;
6pub mod utils;
7pub mod yaml_engine;
8
9pub use config::BlankLines;
10pub use config::Config;
11pub use config::ConfigBuilder;
12pub use config::LineEnding;
13pub use config::MathDelimiterStyle;
14pub use config::ParserOptions;
15pub use config::TabStopMode;
16pub use config::WrapMode;
17pub use formatter::ExternalCodeBlock;
18pub use formatter::FormattedCodeMap;
19pub use formatter::collect_code_blocks;
20pub use formatter::format_tree;
21pub use formatter::format_tree_with_formatted_code;
22pub use syntax::SyntaxNode;
23
24fn detect_line_ending(input: &str) -> &str {
25 let rn_pos = input.find("\r\n");
26 let n_pos = input.find('\n');
27
28 if let (Some(rn), Some(n)) = (rn_pos, n_pos) {
29 if rn < n {
30 return "\r\n";
31 }
32 } else if rn_pos.is_some() {
33 return "\r\n";
34 }
35
36 "\n"
37}
38
39fn apply_line_ending(text: &str, target: &str) -> String {
40 if target == "\r\n" {
41 text.replace("\r\n", "\n").replace("\n", "\r\n")
42 } else {
43 text.replace("\r\n", "\n")
44 }
45}
46
47pub fn format(input: &str, config: Option<Config>, range: Option<(usize, usize)>) -> String {
48 let config = config.unwrap_or_default();
49 let target_line_ending = match config.line_ending {
50 Some(LineEnding::Lf) => "\n",
51 Some(LineEnding::Crlf) => "\r\n",
52 Some(LineEnding::Auto) | None => detect_line_ending(input),
53 };
54
55 let tree = parser::parse(input, Some(config.parser_options()));
56 let out = formatter::format_tree(&tree, &config, range);
57 apply_line_ending(&out, target_line_ending)
58}
59
60pub fn format_with_defaults(input: &str) -> String {
61 format(input, None, None)
62}