mod reporting;
mod source;
use anyhow::{Context, anyhow};
use camino::Utf8Path;
use cap_std::fs_utf8::Dir;
use mdtablefix::{
io::SourceDocument,
report::{FileReport, LineDelta, render_report_line},
};
pub use reporting::{ExitStatus, Mode, exit_status, report_line_endings};
use reporting::{listed, render_diff};
pub use source::{Inputs, ReadOnlyDir, assess, write_back};
use crate::select::{
ConflictGuard,
conflict::{ConflictMarkerState, marker_state, refuses},
};
pub type Formatter = dyn Fn(&SourceDocument<'_>) -> String + Sync;
pub fn analyse(
mode: Mode,
guard: &ConflictGuard,
directory: &Dir,
display_path: &Utf8Path,
storage_key: &Utf8Path,
format: &Formatter,
) -> anyhow::Result<(FileReport, String)> {
if mode == Mode::ListFiles {
return Ok((
FileReport {
display_path: display_path.to_owned(),
is_changed: false,
delta: LineDelta::default(),
},
listed(display_path),
));
}
let readable = ReadOnlyDir::new(
directory
.try_clone()
.with_context(|| format!("duplicating the capability on {storage_key}"))?,
);
let assessment = assess(&readable, storage_key, format)?;
report_line_endings(assessment.counts, "file", Some(display_path.as_str()));
let is_changed = assessment.is_changed();
let delta = if is_changed {
LineDelta::between(&assessment.original, &assessment.formatted)
} else {
LineDelta::default()
};
let payload = match mode {
Mode::Print => assessment.formatted,
Mode::Check if is_changed => format!("{}\n", render_report_line(display_path, delta)),
Mode::Diff if is_changed => render_diff(display_path, &assessment)?,
Mode::InPlace if is_changed => {
let markers = marker_state(&assessment.original);
if markers == ConflictMarkerState::Present && refuses(markers, guard.operation_state()?)
{
return Err(anyhow!(
"refusing to rewrite {display_path}: it contains conflict markers and a \
merge, rebase, revert, or cherry-pick is in progress. Resolve it first, or \
pass --allow-conflicted to rewrite it anyway."
));
}
if !write_back(directory, storage_key, &assessment)? {
return Err(anyhow!(
"not rewriting {display_path}: it changed while it was being formatted, so \
the text this run read is no longer there. Run mdtablefix again to format \
the file as it is now."
));
}
String::new()
}
Mode::InPlace | Mode::Check | Mode::Diff | Mode::ListFiles => String::new(),
};
Ok((
FileReport {
display_path: display_path.to_owned(),
is_changed,
delta,
},
payload,
))
}
#[must_use]
pub fn in_argument_order<T>(results: Vec<(usize, T)>) -> Vec<T> {
let mut indexed = results;
indexed.sort_by_key(|(index, _)| *index);
indexed.into_iter().map(|(_, value)| value).collect()
}
#[cfg(test)]
#[path = "driver_contract_tests.rs"]
mod contract_tests;
#[cfg(test)]
#[path = "driver_in_place_tests.rs"]
mod in_place_tests;
#[cfg(test)]
#[path = "driver_report_tests.rs"]
mod report_tests;
#[cfg(test)]
#[path = "driver_test_support.rs"]
mod test_support;