use super::types::{RewriteCategory, RewriteResult};
pub(super) fn is_code_file(path: &str) -> bool {
std::path::Path::new(path)
.extension()
.and_then(|ext| ext.to_str())
.and_then(rskim_core::Language::from_extension)
.is_some()
}
pub(super) fn try_rewrite_cat(args: &[&str]) -> Option<RewriteResult> {
if args.is_empty() {
return None;
}
let mut files: Vec<&str> = Vec::new();
let mut has_unsupported_flag = false;
for arg in args {
if arg.starts_with('-') && *arg != "-" {
if *arg == "-s" {
continue;
}
has_unsupported_flag = true;
break;
}
files.push(arg);
}
if has_unsupported_flag || files.is_empty() {
return None;
}
if !files.iter().all(|f| is_code_file(f)) {
return None;
}
let mut tokens: Vec<String> = vec!["skim".to_string()];
tokens.extend(files.iter().map(|f| f.to_string()));
tokens.push("--mode=pseudo".to_string());
if files.len() > 1 {
tokens.push("--no-header".to_string());
}
Some(RewriteResult {
tokens,
category: RewriteCategory::Read,
})
}
pub(super) fn parse_line_count_and_files<'a>(
args: &[&'a str],
) -> Option<(Option<u64>, Vec<&'a str>)> {
if args.is_empty() {
return None;
}
let mut count: Option<u64> = None;
let mut files: Vec<&'a str> = Vec::new();
let mut i = 0;
while i < args.len() {
let arg = args[i];
if arg == "-n" {
i += 1;
if i >= args.len() {
return None;
}
count = Some(args[i].parse::<u64>().ok()?);
} else if let Some(rest) = arg.strip_prefix("-n") {
count = Some(rest.parse::<u64>().ok()?);
} else if arg.starts_with('-') && arg != "-" {
let potential_num = &arg[1..];
if let Ok(n) = potential_num.parse::<u64>() {
count = Some(n);
} else {
return None;
}
} else {
files.push(arg);
}
i += 1;
}
if files.is_empty() {
return None;
}
Some((count, files))
}
fn try_rewrite_head_tail(args: &[&str], line_flag: &str) -> Option<RewriteResult> {
let (count, files) = parse_line_count_and_files(args)?;
if !files.iter().all(|f| is_code_file(f)) {
return None;
}
let mut tokens: Vec<String> = vec!["skim".to_string()];
tokens.extend(files.iter().map(|f| f.to_string()));
tokens.push("--mode=pseudo".to_string());
if let Some(n) = count {
tokens.push(line_flag.to_string());
tokens.push(n.to_string());
}
Some(RewriteResult {
tokens,
category: RewriteCategory::Read,
})
}
pub(super) fn try_rewrite_head(args: &[&str]) -> Option<RewriteResult> {
try_rewrite_head_tail(args, "--max-lines")
}
pub(super) fn try_rewrite_tail(args: &[&str]) -> Option<RewriteResult> {
try_rewrite_head_tail(args, "--last-lines")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_code_file_rs() {
assert!(is_code_file("file.rs"));
}
#[test]
fn test_is_code_file_ts() {
assert!(is_code_file("src/main.ts"));
}
#[test]
fn test_is_code_file_txt() {
assert!(!is_code_file("file.txt"));
}
#[test]
fn test_is_code_file_no_extension() {
assert!(!is_code_file("Makefile"));
}
#[test]
fn test_parse_line_count_dash_n_space() {
let result = parse_line_count_and_files(&["-n", "20", "file.ts"]);
assert_eq!(result, Some((Some(20), vec!["file.ts"])));
}
#[test]
fn test_parse_line_count_dash_n_no_space() {
let result = parse_line_count_and_files(&["-n20", "file.ts"]);
assert_eq!(result, Some((Some(20), vec!["file.ts"])));
}
#[test]
fn test_parse_line_count_bare_number() {
let result = parse_line_count_and_files(&["-20", "file.ts"]);
assert_eq!(result, Some((Some(20), vec!["file.ts"])));
}
#[test]
fn test_parse_line_count_no_count() {
let result = parse_line_count_and_files(&["file.ts"]);
assert_eq!(result, Some((None, vec!["file.ts"])));
}
#[test]
fn test_parse_line_count_no_files() {
let result = parse_line_count_and_files(&["-n", "20"]);
assert!(result.is_none());
}
#[test]
fn test_parse_line_count_empty() {
let result = parse_line_count_and_files(&[]);
assert!(result.is_none());
}
}