Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --[no-]unindent for removing leading indentation #7

Merged
merged 3 commits into from
Oct 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 50 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ struct Args {
/// The input path. If unset, stdin is used.
input: Option<PathBuf>,

/// Whether the input should be formatted to be Discord-compatible.
#[clap(short, long)]
/// Wrap the output in a Discord-flavoured-markdown–style ANSI codeblock.
#[clap(short, long, overrides_with = "_no_discord")]
discord: bool,

/// Don't wrap the output in a markdown-style codeblock. [default]
#[clap(short = 'D', long = "no-discord")]
#[clap(hide_short_help = true)]
#[doc(hidden)]
_no_discord: bool,

// Logically this comes after `Args::strip_ansi`, but in clap it makes more sense before.
// Also see https://jwodder.github.io/kbits/posts/clap-bool-negate/
/// Strip all ANSI escape sequences from the input before processing. [default]
Expand All @@ -39,6 +45,16 @@ struct Args {
#[doc(hidden)]
_no_unwrap_codeblock: bool,

/// Strip any top-level indentation in the input prior to highlighting it.
#[clap(short = 'u', long, overrides_with = "_no_unindent")]
unindent: bool,

/// Keep indents as-is. [default]
#[clap(short = 'U', long = "no-unindent")]
#[clap(hide_short_help = true)]
#[doc(hidden)]
_no_unindent: bool,

/// Softly enforce a byte size limit.
///
/// This means that if the size limit is exceeded, less colors are used
Expand Down Expand Up @@ -92,11 +108,18 @@ fn main() -> Result<()> {
&input
};

if args.strip_ansi {
// If the input doesn't contain escape sequences, avoid processing it because strip-ansi-escapes
// also strips tabs unfortunately. (https://github.com/luser/strip-ansi-escapes/issues/20)
if args.strip_ansi && stripped.contains('\x1B') {
input = strip_ansi_escapes::strip_str(stripped);
stripped = &input;
}

if args.unindent {
input = dedent(stripped);
stripped = &input;
}

let out = termcolor::Ansi::new(std::io::stdout().lock());
let mut highlighter = Highlighter::default();
if args.discord {
Expand All @@ -123,3 +146,27 @@ fn unwrap_codeblock(input: &str) -> &str {
};
rest
}

fn dedent(input: &str) -> String {
let shared_indent = input
.lines()
.filter(|l| !l.trim().is_empty())
.map(|l| {
let nonspace = l.find(|c: char| !c.is_whitespace()).unwrap();
&l[..nonspace]
})
.min_by_key(|s| s.len() + s.matches('\t').count()) // Assume tabs are 2-wide
.unwrap_or("");

input
.split_inclusive('\n')
.map(|l| {
if shared_indent.starts_with(l) {
// Trim partial indents
""
} else {
l.strip_prefix(shared_indent).unwrap_or(l)
}
})
.collect()
}