use clap::*;
use intspan::*;
use std::io::BufRead;
pub fn make_subcommand() -> Command {
Command::new("create")
.about("Create block fasta files from links of ranges")
.after_help(
r###"
* <genome.fa> is a multi-fasta file contains genome sequences
* <infiles> are files of links of ranges, usually generated by `linkr`
* infile == stdin means reading from STDIN
* Need `samtools` in $PATH
"###,
)
.arg(
Arg::new("genome.fa")
.required(true)
.num_args(1)
.index(1)
.help("Path to genome.fa"),
)
.arg(
Arg::new("infiles")
.required(true)
.num_args(1..)
.index(2)
.help("Sets the input files to use"),
)
.arg(
Arg::new("name")
.long("name")
.num_args(1)
.help("Set a species name for ranges"),
)
.arg(
Arg::new("outfile")
.long("outfile")
.short('o')
.num_args(1)
.default_value("stdout")
.help("Output filename. [stdout] for screen"),
)
}
pub fn execute(args: &ArgMatches) -> anyhow::Result<()> {
let mut writer = writer(args.get_one::<String>("outfile").unwrap());
let genome = args.get_one::<String>("genome.fa").unwrap();
for infile in args.get_many::<String>("infiles").unwrap() {
let reader = reader(infile);
for line in reader.lines().map_while(Result::ok) {
let parts: Vec<&str> = line.split('\t').collect();
for part in &parts {
let mut range = Range::from_str(part);
if !range.is_valid() {
continue;
}
let seq = get_seq(&range, genome)?;
if args.contains_id("name") {
let name = args.get_one::<String>("name").unwrap();
*range.name_mut() = name.to_string();
}
writer.write_all(format!(">{}\n{}\n", range, seq).as_ref())?;
}
writer.write_all("\n".as_ref())?;
}
}
Ok(())
}
fn get_seq(range: &Range, genome: &str) -> anyhow::Result<String> {
let pos = format!("{}:{}-{}", range.chr(), range.start(), range.end());
let mut gseq = get_seq_faidx(genome, &pos)?;
if range.strand() == "-" {
gseq = std::str::from_utf8(&bio::alphabets::dna::revcomp(gseq.bytes()))
.unwrap()
.to_string();
}
Ok(gseq)
}