use std::{
fs,
io::{self, Write},
path::Path,
str,
sync::{atomic::AtomicUsize, Arc},
time::Instant,
};
use anyhow::Result;
use tree_sitter_tags::{TagsConfiguration, TagsContext};
pub struct TagsOptions {
pub scope: Option<String>,
pub quiet: bool,
pub print_time: bool,
pub cancellation_flag: Arc<AtomicUsize>,
}
pub fn generate_tags(
path: &Path,
name: &str,
config: &TagsConfiguration,
indent: bool,
opts: &TagsOptions,
) -> Result<()> {
let mut context = TagsContext::new();
let stdout = io::stdout();
let mut stdout = stdout.lock();
let indent_str = if indent {
if !opts.quiet {
writeln!(&mut stdout, "{name}")?;
}
"\t"
} else {
""
};
let source = fs::read(path)?;
let start = Instant::now();
for tag in context
.generate_tags(config, &source, Some(&opts.cancellation_flag))?
.0
{
let tag = tag?;
if !opts.quiet {
write!(
&mut stdout,
"{indent_str}{:<10}\t | {:<8}\t{} {} - {} `{}`",
str::from_utf8(&source[tag.name_range]).unwrap_or(""),
&config.syntax_type_name(tag.syntax_type_id),
if tag.is_definition { "def" } else { "ref" },
tag.span.start,
tag.span.end,
str::from_utf8(&source[tag.line_range]).unwrap_or(""),
)?;
if let Some(docs) = tag.docs {
if docs.len() > 120 {
write!(&mut stdout, "\t{:?}...", docs.get(0..120).unwrap_or(""))?;
} else {
write!(&mut stdout, "\t{:?}", &docs)?;
}
}
writeln!(&mut stdout)?;
}
}
if opts.print_time {
writeln!(
&mut stdout,
"{indent_str}time: {}ms",
start.elapsed().as_millis(),
)?;
}
Ok(())
}