pub mod config;
pub mod error;
pub mod file_resolver;
pub mod formatter;
pub mod incremental_cache;
pub mod parser;
pub mod settings;
pub mod skills;
pub mod transform;
pub mod typography;
pub mod wrapping;
use std::path::Path;
pub use config::{DEFAULT_WRAP_WIDTH, FormatOptions, ListSpacing};
pub use error::{Error, Result};
pub use formatter::filling::fill_markdown;
pub use wrapping::line_wrappers::{line_wrap_by_sentence, line_wrap_to_width};
pub use wrapping::sentence::split_sentences_regex;
pub use wrapping::text_filling::{Wrap, fill_text};
pub use wrapping::text_wrapping::{
html_md_word_split, simple_word_split, wrap_paragraph, wrap_paragraph_lines,
};
impl FormatOptions {
pub fn reformat_text(&self, text: &str) -> String {
if self.plaintext {
let wrap = if self.width > 0 { Wrap::Wrap } else { Wrap::None };
fill_text(text, wrap, self.width, "", "", 0, None)
} else {
fill_markdown(
text,
true,
self.width,
self.semantic,
self.cleanups,
self.smartquotes,
self.ellipses,
None,
self.list_spacing,
)
}
}
pub fn reformat_file(
&self,
path: &Path,
output: Option<&Path>,
inplace: bool,
nobackup: bool,
) -> Result<()> {
let content = std::fs::read_to_string(path)?;
let formatted = self.reformat_text(&content);
if inplace && formatted == content {
return Ok(());
}
if inplace {
if !nobackup {
let backup_path = path.with_extension("bak");
std::fs::copy(path, &backup_path)?;
}
atomic_write(path, &formatted)?;
} else if let Some(out) = output {
if let Some(parent) = out.parent() {
std::fs::create_dir_all(parent)?;
}
atomic_write(out, &formatted)?;
} else {
print!("{formatted}");
}
Ok(())
}
}
#[allow(clippy::too_many_arguments, clippy::fn_params_excessive_bools)]
pub fn reformat_text(
text: &str,
width: usize,
plaintext: bool,
semantic: bool,
cleanups: bool,
smartquotes: bool,
ellipses: bool,
list_spacing: ListSpacing,
) -> String {
let opts =
FormatOptions { width, plaintext, semantic, cleanups, smartquotes, ellipses, list_spacing };
opts.reformat_text(text)
}
#[allow(clippy::too_many_arguments, clippy::fn_params_excessive_bools)]
pub fn reformat_file(
path: &Path,
output: Option<&Path>,
width: usize,
inplace: bool,
nobackup: bool,
plaintext: bool,
semantic: bool,
cleanups: bool,
smartquotes: bool,
ellipses: bool,
list_spacing: ListSpacing,
) -> Result<()> {
let opts =
FormatOptions { width, plaintext, semantic, cleanups, smartquotes, ellipses, list_spacing };
opts.reformat_file(path, output, inplace, nobackup)
}
fn atomic_write(path: &Path, content: &str) -> Result<()> {
use std::io::Write;
#[cfg(unix)]
let original_permissions = path.metadata().ok().map(|m| m.permissions());
let dir = path.parent().unwrap_or(Path::new("."));
let mut tmp = tempfile::NamedTempFile::new_in(dir)?;
tmp.write_all(content.as_bytes())?;
tmp.persist(path).map_err(|e| Error::Io(e.error))?;
#[cfg(unix)]
if let Some(perms) = original_permissions {
std::fs::set_permissions(path, perms)?;
}
Ok(())
}