feat(cli): rework parse to use new input handler
Co-authored-by: Will Lillis <will.lillis24@gmail.com>
This commit is contained in:
parent
b3183363a2
commit
6bad1bc6c5
2 changed files with 118 additions and 66 deletions
155
cli/src/main.rs
155
cli/src/main.rs
|
|
@ -9,7 +9,6 @@ use anyhow::{anyhow, Context, Result};
|
|||
use clap::{crate_authors, Args, Command, FromArgMatches as _, Subcommand, ValueEnum};
|
||||
use clap_complete::generate;
|
||||
use dialoguer::{theme::ColorfulTheme, Confirm, FuzzySelect, Input};
|
||||
use glob::glob;
|
||||
use heck::ToUpperCamelCase;
|
||||
use regex::Regex;
|
||||
use semver::Version as SemverVersion;
|
||||
|
|
@ -19,11 +18,13 @@ use tree_sitter_cli::{
|
|||
fuzz_language_corpus, FuzzOptions, EDIT_COUNT, ITERATION_COUNT, LOG_ENABLED,
|
||||
LOG_GRAPH_ENABLED, START_SEED,
|
||||
},
|
||||
highlight,
|
||||
highlight::{self, HighlightOptions},
|
||||
init::{generate_grammar_files, get_root_path, migrate_package_json, JsonConfigOpts},
|
||||
input::{get_input, get_tmp_source_file, CliInput},
|
||||
logger,
|
||||
parse::{self, ParseFileOptions, ParseOutput, ParseTheme},
|
||||
playground, query, tags,
|
||||
parse::{self, ParseFileOptions, ParseOutput, ParseResult, ParseTheme},
|
||||
playground, query,
|
||||
tags::{self, TagsOptions},
|
||||
test::{self, TestOptions, TestStats},
|
||||
test_highlight, test_tags, util, version, wasm,
|
||||
};
|
||||
|
|
@ -153,9 +154,9 @@ struct Parse {
|
|||
long = "paths",
|
||||
help = "The path to a file with paths to source file(s)"
|
||||
)]
|
||||
pub paths_file: Option<String>,
|
||||
pub paths_file: Option<PathBuf>,
|
||||
#[arg(num_args=1.., help = "The source file(s) to use")]
|
||||
pub paths: Option<Vec<String>>,
|
||||
pub paths: Option<Vec<PathBuf>>,
|
||||
#[arg(
|
||||
long,
|
||||
help = "Select a language by the scope instead of a file extension"
|
||||
|
|
@ -853,20 +854,6 @@ impl Parse {
|
|||
|
||||
let timeout = self.timeout.unwrap_or_default();
|
||||
|
||||
let (paths, language) = if let Some(target_test) = self.test_number {
|
||||
let (test_path, language_names) = test::get_tmp_test_file(target_test, color)?;
|
||||
let languages = loader.languages_at_path(current_dir)?;
|
||||
let language = languages
|
||||
.iter()
|
||||
.find(|(_, n)| language_names.contains(&Box::from(n.as_str())))
|
||||
.map(|(l, _)| l.clone());
|
||||
let paths = collect_paths(None, Some(vec![test_path.to_str().unwrap().to_owned()]))?;
|
||||
(paths, language)
|
||||
} else {
|
||||
(collect_paths(self.paths_file.as_deref(), self.paths)?, None)
|
||||
};
|
||||
|
||||
let max_path_length = paths.iter().map(|p| p.chars().count()).max().unwrap_or(0);
|
||||
let mut has_error = false;
|
||||
let loader_config = config.get()?;
|
||||
loader.find_all_languages(&loader_config)?;
|
||||
|
|
@ -874,40 +861,24 @@ impl Parse {
|
|||
let should_track_stats = self.stat;
|
||||
let mut stats = parse::Stats::default();
|
||||
|
||||
for path in &paths {
|
||||
let path = Path::new(&path);
|
||||
|
||||
let language = if let Some(ref language) = language {
|
||||
language.clone()
|
||||
} else {
|
||||
loader.select_language(path, current_dir, self.scope.as_deref())?
|
||||
};
|
||||
parser
|
||||
.set_language(&language)
|
||||
.context("incompatible language")?;
|
||||
|
||||
let opts = ParseFileOptions {
|
||||
language: language.clone(),
|
||||
path,
|
||||
edits: &edits
|
||||
.iter()
|
||||
.map(std::string::String::as_str)
|
||||
.collect::<Vec<&str>>(),
|
||||
max_path_length,
|
||||
output,
|
||||
print_time: time,
|
||||
timeout,
|
||||
debug: self.debug,
|
||||
debug_graph: self.debug_graph,
|
||||
cancellation_flag: Some(&cancellation_flag),
|
||||
encoding,
|
||||
open_log: self.open_log,
|
||||
no_ranges: self.no_ranges,
|
||||
parse_theme: &parse_theme,
|
||||
};
|
||||
|
||||
let parse_result = parse::parse_file_at_path(&mut parser, &opts)?;
|
||||
let options = ParseFileOptions {
|
||||
edits: &edits
|
||||
.iter()
|
||||
.map(std::string::String::as_str)
|
||||
.collect::<Vec<&str>>(),
|
||||
output,
|
||||
print_time: time,
|
||||
timeout,
|
||||
debug: self.debug,
|
||||
debug_graph: self.debug_graph,
|
||||
cancellation_flag: Some(&cancellation_flag),
|
||||
encoding,
|
||||
open_log: self.open_log,
|
||||
no_ranges: self.no_ranges,
|
||||
parse_theme: &parse_theme,
|
||||
};
|
||||
|
||||
let mut update_stats = |parse_result: ParseResult| {
|
||||
if should_track_stats {
|
||||
stats.total_parses += 1;
|
||||
if parse_result.successful {
|
||||
|
|
@ -920,6 +891,84 @@ impl Parse {
|
|||
}
|
||||
|
||||
has_error |= !parse_result.successful;
|
||||
};
|
||||
|
||||
let input = get_input(
|
||||
self.paths_file.as_deref(),
|
||||
self.paths,
|
||||
self.test_number,
|
||||
&cancellation_flag,
|
||||
)?;
|
||||
match input {
|
||||
CliInput::Paths(paths) => {
|
||||
let max_path_length = paths
|
||||
.iter()
|
||||
.map(|p| p.to_string_lossy().chars().count())
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
for path in &paths {
|
||||
let path = Path::new(&path);
|
||||
let language =
|
||||
loader.select_language(path, current_dir, self.scope.as_deref())?;
|
||||
|
||||
let parse_result = parse::parse_file_at_path(
|
||||
&mut parser,
|
||||
&language,
|
||||
path,
|
||||
&path.display().to_string(),
|
||||
max_path_length,
|
||||
&options,
|
||||
)?;
|
||||
update_stats(parse_result);
|
||||
}
|
||||
}
|
||||
|
||||
CliInput::Test {
|
||||
name,
|
||||
contents,
|
||||
languages: language_names,
|
||||
} => {
|
||||
let path = get_tmp_source_file(&contents)?;
|
||||
let languages = loader.languages_at_path(current_dir)?;
|
||||
let language = languages
|
||||
.iter()
|
||||
.find(|(_, n)| language_names.contains(&Box::from(n.as_str())))
|
||||
.or_else(|| languages.first())
|
||||
.map(|(l, _)| l.clone())
|
||||
.ok_or_else(|| anyhow!("No language found"))?;
|
||||
|
||||
let parse_result = parse::parse_file_at_path(
|
||||
&mut parser,
|
||||
&language,
|
||||
&path,
|
||||
&name,
|
||||
name.chars().count(),
|
||||
&options,
|
||||
)?;
|
||||
update_stats(parse_result);
|
||||
fs::remove_file(path)?;
|
||||
}
|
||||
|
||||
CliInput::Stdin(contents) => {
|
||||
// Place user input and parser output on separate lines
|
||||
println!();
|
||||
|
||||
let path = get_tmp_source_file(&contents)?;
|
||||
let name = "stdin";
|
||||
let language = loader.select_language(&path, current_dir, None)?;
|
||||
|
||||
let parse_result = parse::parse_file_at_path(
|
||||
&mut parser,
|
||||
&language,
|
||||
&path,
|
||||
name,
|
||||
name.chars().count(),
|
||||
&options,
|
||||
)?;
|
||||
update_stats(parse_result);
|
||||
fs::remove_file(path)?;
|
||||
}
|
||||
}
|
||||
|
||||
if should_track_stats {
|
||||
|
|
|
|||
|
|
@ -178,10 +178,7 @@ pub enum ParseOutput {
|
|||
}
|
||||
|
||||
pub struct ParseFileOptions<'a> {
|
||||
pub language: Language,
|
||||
pub path: &'a Path,
|
||||
pub edits: &'a [&'a str],
|
||||
pub max_path_length: usize,
|
||||
pub output: ParseOutput,
|
||||
pub print_time: bool,
|
||||
pub timeout: u64,
|
||||
|
|
@ -201,11 +198,17 @@ pub struct ParseResult {
|
|||
pub duration: Option<Duration>,
|
||||
}
|
||||
|
||||
pub fn parse_file_at_path(parser: &mut Parser, opts: &ParseFileOptions) -> Result<ParseResult> {
|
||||
pub fn parse_file_at_path(
|
||||
parser: &mut Parser,
|
||||
language: &Language,
|
||||
path: &Path,
|
||||
name: &str,
|
||||
max_path_length: usize,
|
||||
opts: &ParseFileOptions,
|
||||
) -> Result<ParseResult> {
|
||||
let mut _log_session = None;
|
||||
parser.set_language(&opts.language)?;
|
||||
let mut source_code = fs::read(opts.path)
|
||||
.with_context(|| format!("Error reading source file {:?}", opts.path))?;
|
||||
parser.set_language(language)?;
|
||||
let mut source_code = fs::read(path).with_context(|| format!("Error reading {name:?}"))?;
|
||||
|
||||
// Render an HTML graph if `--debug-graph` was passed
|
||||
if opts.debug_graph {
|
||||
|
|
@ -551,13 +554,13 @@ pub fn parse_file_at_path(parser: &mut Parser, opts: &ParseFileOptions) -> Resul
|
|||
}
|
||||
|
||||
if first_error.is_some() || opts.print_time {
|
||||
let path = opts.path.to_string_lossy();
|
||||
let path = path.to_string_lossy();
|
||||
write!(
|
||||
&mut stdout,
|
||||
"{:width$}\tParse: {parse_duration_ms:>7.2} ms\t{:>6} bytes/ms",
|
||||
path,
|
||||
name,
|
||||
(source_code.len() as u128 * 1_000_000) / parse_duration.as_nanos(),
|
||||
width = opts.max_path_length
|
||||
width = max_path_length
|
||||
)?;
|
||||
if let Some(node) = first_error {
|
||||
let start = node.start_position();
|
||||
|
|
@ -587,7 +590,7 @@ pub fn parse_file_at_path(parser: &mut Parser, opts: &ParseFileOptions) -> Resul
|
|||
&mut stdout,
|
||||
"\n{:width$}\tEdit: {edit_duration_ms:>7.2} ms",
|
||||
" ".repeat(path.len()),
|
||||
width = opts.max_path_length,
|
||||
width = max_path_length,
|
||||
)?;
|
||||
}
|
||||
writeln!(&mut stdout)?;
|
||||
|
|
@ -607,8 +610,8 @@ pub fn parse_file_at_path(parser: &mut Parser, opts: &ParseFileOptions) -> Resul
|
|||
writeln!(
|
||||
&mut stdout,
|
||||
"{:width$}\tParse: {duration_ms:>7.2} ms\t(timed out)",
|
||||
opts.path.to_str().unwrap(),
|
||||
width = opts.max_path_length
|
||||
path.to_str().unwrap(),
|
||||
width = max_path_length
|
||||
)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue