Skip to main content

panache_formatter/
lib.rs

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}