use crate::{AppendAsLine, PatternIOProcessor, Prefer};
use clap::{Parser, Subcommand};
use std::path::PathBuf;
use sysexits::Result;
#[derive(Subcommand)]
pub enum Action {
#[command(aliases = ["cffref", "cff-reference"])]
Cffreference {
#[arg(long = "input", short = 'i')]
input_file: Option<PathBuf>,
#[arg(long = "output", short = 'o')]
output_file: Option<PathBuf>,
},
#[command(aliases = ["changelog"])]
CommentChanges {
#[arg(long, short = 'd')]
delimiter: String,
#[arg(aliases = ["count"], long, short = 'n')]
depth: Option<usize>,
#[arg(aliases = ["hyperlink"], long, short = 'l')]
link: Vec<String>,
#[arg(aliases = ["dir", "directory"], long = "output", short = 'o')]
output_directory: Option<String>,
#[arg(long, short = 't')]
target: Vec<String>,
},
Rs2md {
#[arg(long = "inner")]
extract_inner: bool,
#[arg(long = "outer")]
extract_outer: bool,
#[arg(long = "input", short = 'i')]
input_files: Vec<PathBuf>,
#[arg(long = "output", short = 'o')]
output_file: Option<PathBuf>,
},
Uncrlf {
#[arg(long = "edit", short = 'e')]
file_to_edit: Option<PathBuf>,
#[arg(long = "input", short = 'i')]
input_file: Option<PathBuf>,
#[arg(long = "output", short = 'o')]
output_file: Option<PathBuf>,
},
}
impl Action {
fn cffreference(s: &str) -> String {
let mut buffer = String::new();
let mut has_preferred_citation = false;
let mut has_type = false;
let mut references = false;
for line in s.lines() {
if references {
match line.chars().next() {
Some(' ' | '-') => {}
_ => {
references = false;
}
}
}
if !line.is_empty()
&& !line.starts_with('#')
&& !line.starts_with("---")
&& !line.starts_with("...")
&& !line.starts_with("cff-version:")
&& !line.starts_with("message:")
&& !line.starts_with("references:")
&& !references
{
if line.starts_with("preferred-citation:") {
has_preferred_citation = true;
} else if line.starts_with("type:") {
has_type = true;
}
buffer.append_as_line(line);
} else if line.starts_with("references:") {
references = true;
}
}
if has_preferred_citation {
let mut preferred_citation_reached = false;
let mut result = String::new();
for line in buffer.lines() {
if preferred_citation_reached && line.starts_with(' ') {
result.push_str(&(" ".to_string() + line + "\n"));
} else if preferred_citation_reached {
preferred_citation_reached = false;
}
if line.starts_with("preferred-citation:") {
preferred_citation_reached = true;
}
}
let mut lines = result.lines();
lines
.next()
.map_or_else(String::new, |l| " - ".to_string() + l.trim() + "\n")
+ &lines.map(|l| l.to_string() + "\n").collect::<String>()
} else {
let mut lines = buffer.lines();
(if has_type {
lines
.next()
.map_or_else(String::new, |l| " - ".to_string() + l.trim() + "\n")
} else {
" - type: software\n".to_string()
}) + &lines
.map(|l| " ".to_string() + l + "\n")
.collect::<String>()
}
}
fn rs2md(s: &str, extract_inner: bool, extract_outer: bool) -> String {
s.lines()
.map(str::trim_start)
.filter(|l| {
(extract_inner && l.starts_with("///"))
|| (extract_outer && l.starts_with("//!"))
})
.map(|l| {
if l.len() > 3 {
l.split_at(4).1.trim_end().to_string() + "\n"
} else {
"\n".to_string()
}
})
.collect::<String>()
}
pub fn run(&self) -> Result<()> {
match self {
Self::Cffreference {
input_file,
output_file,
} => (|s: String| -> String { Self::cffreference(&s) })
.io_append(input_file, output_file),
Self::CommentChanges {
delimiter,
depth,
link,
target,
output_directory,
} => crate::CommentChanges::new(
*depth,
delimiter.to_string(),
link
.iter()
.zip(target.iter())
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect(),
)
.main(output_directory.as_ref().map_or(".", |directory| directory)),
Self::Rs2md {
extract_inner,
extract_outer,
input_files,
output_file,
} => (|s: String| -> String {
Self::rs2md(&s, *extract_inner, *extract_outer)
})
.io(input_files, output_file),
Self::Uncrlf {
file_to_edit,
input_file,
output_file,
} => |mut s: String| -> String {
s.retain(|c| c != '\r');
s
}
.io(
input_file.prefer(file_to_edit.clone()),
output_file.prefer(file_to_edit.clone()),
),
}
}
}
#[derive(Parser)]
#[clap(about, version)]
pub struct Clap {
#[clap(subcommand)]
action: Action,
}
crate::getters!(@ref Clap { action: Action });