-
Notifications
You must be signed in to change notification settings - Fork 2
Crate-level API changes for tree-sitter-lint #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: run-context
Are you sure you want to change the base?
Changes from 23 commits
b2c06c0
551e376
3d4682c
422058d
2118d3c
54b39ed
0602f3c
b05884b
d341747
1930ccf
3c2a567
5fe38b3
5a3ede1
0ad0481
c0ae26e
c73c3da
d8f21b0
3a039da
debbbc0
30a1c71
c0bf4ca
2eba2c5
e471b0d
672ac41
c5f3fa2
c371ae9
53e844f
57495f8
31959d1
2061904
6daf28a
6bb81e1
325d3e0
355ea2b
2e842eb
3b1230c
c5a8c85
d250c7c
c5b2e88
7626af8
526d110
d93d175
db220fe
7543d9d
045b98d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| [package] | ||
| name = "tree-sitter-grep" | ||
| name = "tree_sitter_lint_tree-sitter-grep" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
| license = "Unlicense OR MIT" | ||
|
|
@@ -8,6 +8,7 @@ authors = [ | |
| "Peter Stuart <peter@peterstuart.org>" | ||
| ] | ||
| description = """ | ||
| (not-yet-landed version used by tree-sitter-lint) | ||
| tree-sitter-grep is a grep-like search tool that | ||
| recursively searches the current directory for a | ||
| tree-sitter query pattern. Like ripgrep, it respects | ||
|
|
@@ -25,6 +26,7 @@ rust-version = "1.70" | |
| bstr = "1.1.0" | ||
| bytecount = "0.6" | ||
| clap = { version = "4.3.0", features = ["derive", "wrap_help"] } | ||
| derive_builder = "0.12.0" | ||
| encoding_rs = "0.8.14" | ||
| encoding_rs_io = "0.1.6" | ||
| ignore = { package = "tree_sitter_grep_ignore", git = "https://github.com/helixbass/ripgrep", rev = "669ebd3", version = "0.4.20-dev.0" } | ||
|
|
@@ -34,10 +36,13 @@ log = "0.4.5" | |
| memchr = "2.1" | ||
| memmap = { package = "memmap2", version = "0.5.3" } | ||
| once_cell = "1.18.0" | ||
| ouroboros = "0.17.2" | ||
| proc_macros = { package = "tree_sitter_grep_proc_macros", path = "proc_macros", version = "0.1.0" } | ||
| rayon = "1.7.0" | ||
| regex = "1.8.2" | ||
| ropey = "1.6.0" | ||
| serde = { version = "1.0.77", features = ["derive"] } | ||
| streaming-iterator = "0.1.9" | ||
| strum_macros = "0.25.1" | ||
| termcolor = "1.2.0" | ||
| thiserror = "1.0.43" | ||
|
|
@@ -65,6 +70,9 @@ tree-sitter-swift = "0.3.6" | |
| tree-sitter-toml = "0.20.0" | ||
| tree-sitter-typescript = "0.20.2" | ||
|
|
||
| [patch.crates-io] | ||
| tree-sitter = { git = "https://github.com/helixbass/tree-sitter", rev = "57e98fb0" } | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Read about how to do this "force dependencies to use this version" The thing that I guess I wasn't anticipating is that I also had to do this in any "outer" crates ( |
||
|
|
||
| [[bin]] | ||
| name = "tree-sitter-grep" | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,4 +3,5 @@ format_macro_bodies = true | |
| format_macro_matchers = true | ||
| group_imports = "StdExternalCrate" | ||
| imports_granularity = "Crate" | ||
| wrap_comments = true | ||
| edition = "2021" | ||
| # wrap_comments = true | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The thing of |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,16 @@ | ||
| use std::{ | ||
| collections::HashMap, | ||
| fs, | ||
| path::{Path, PathBuf}, | ||
| sync::{Arc, Mutex}, | ||
| }; | ||
|
|
||
| use clap::{ArgGroup, Parser}; | ||
| use derive_builder::Builder; | ||
| use ignore::{types::Types, WalkBuilder, WalkParallel}; | ||
| use rayon::iter::IterBridge; | ||
| use termcolor::BufferWriter; | ||
| use tree_sitter::Query; | ||
|
|
||
| use crate::{ | ||
| language::SupportedLanguage, | ||
|
|
@@ -23,7 +26,8 @@ use crate::{ | |
|
|
||
| const ALL_NODES_QUERY: &str = "(_) @node"; | ||
|
|
||
| #[derive(Parser)] | ||
| #[derive(Builder, Clone, Default, Parser)] | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exposed an Presumably there should be some additional validation eg that some of the invariants that |
||
| #[builder(default, setter(strip_option, into))] | ||
| #[clap(group( | ||
| ArgGroup::new("query_or_filter") | ||
| .multiple(true) | ||
|
|
@@ -37,13 +41,16 @@ pub struct Args { | |
| /// | ||
| /// This conflicts with the --query option. | ||
| #[arg(short = 'Q', long = "query-file", conflicts_with = "query_text")] | ||
| pub path_to_query_file: Option<PathBuf>, | ||
| path_to_query_file: Option<PathBuf>, | ||
|
|
||
| /// The source text of a tree-sitter query. | ||
| /// | ||
| /// This conflicts with the --query-file option. | ||
| #[arg(short, long = "query", conflicts_with = "path_to_query_file")] | ||
| pub query_text: Option<String>, | ||
| query_text: Option<String>, | ||
|
|
||
| #[clap(skip)] | ||
| query_per_language: Option<HashMap<SupportedLanguage, Arc<Query>>>, | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is "tackling a couple birds with one stone" (?), first this is allowing passing in pre-parsed queries, second this is supporting "query-per-language" (vs "just one query") Query-per-language allows |
||
|
|
||
| /// The name of the tree-sitter query capture (without leading "@") whose | ||
| /// matching nodes will be output. | ||
|
|
@@ -174,7 +181,11 @@ impl Args { | |
| } | ||
|
|
||
| pub(crate) fn get_project_file_walker_types(&self) -> Types { | ||
| get_project_file_walker_types(self.language) | ||
| get_project_file_walker_types(self.language.map(|language| vec![language]).or_else(|| { | ||
| self.query_per_language | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is basically asserting that if you pass Some of this is probably a little bit conceptually unresolved but that seems more or less like the right idea |
||
| .as_ref() | ||
| .map(|query_per_language| query_per_language.keys().cloned().collect()) | ||
| })) | ||
| } | ||
|
|
||
| pub(crate) fn get_project_file_walker(&self) -> WalkParallel { | ||
|
|
@@ -199,18 +210,81 @@ impl Args { | |
| Ok(get_loaded_filter(self.filter.as_deref(), self.filter_arg.as_deref())?.map(Arc::new)) | ||
| } | ||
|
|
||
| pub(crate) fn get_loaded_query_text(&self) -> Result<String, Error> { | ||
| pub(crate) fn get_loaded_query_text_per_language( | ||
| &self, | ||
| ) -> Result<QueryOrQueryTextPerLanguage, Error> { | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This may seem like a weird "half-step" (toward The reason is that we do want to go ahead and fail fast if eg we got passed a path to a query file that we can't read But eg for the case of auto-language (and not having passed |
||
| Ok( | ||
| match (self.path_to_query_file.as_ref(), self.query_text.as_ref()) { | ||
| (Some(path_to_query_file), None) => fs::read_to_string(path_to_query_file) | ||
| match ( | ||
| self.path_to_query_file.as_ref(), | ||
| self.query_text.as_ref(), | ||
| self.query_per_language.as_ref(), | ||
| ) { | ||
| (Some(path_to_query_file), None, None) => fs::read_to_string(path_to_query_file) | ||
| .map_err(|source| Error::QueryFileReadError { | ||
| source, | ||
| path_to_query_file: path_to_query_file.clone(), | ||
| })?, | ||
| (None, Some(query_text)) => query_text.clone(), | ||
| (None, None) => ALL_NODES_QUERY.to_owned(), | ||
| })? | ||
| .into(), | ||
| (None, Some(query_text), None) => query_text.clone().into(), | ||
| (None, None, Some(query_per_language)) => query_per_language.clone().into(), | ||
| (None, None, None) => ALL_NODES_QUERY.to_owned().into(), | ||
| _ => unreachable!(), | ||
| }, | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| impl ArgsBuilder { | ||
| pub fn maybe_language(&mut self, language: Option<SupportedLanguage>) -> &mut Self { | ||
| self.language = Some(language); | ||
| self | ||
| } | ||
| } | ||
|
|
||
| pub enum QueryOrQueryTextPerLanguage { | ||
| SingleQueryText(String), | ||
| PerLanguage(HashMap<SupportedLanguage, Arc<Query>>), | ||
| } | ||
|
|
||
| impl QueryOrQueryTextPerLanguage { | ||
| pub fn get_query_or_query_text_for_language( | ||
| &self, | ||
| language: SupportedLanguage, | ||
| ) -> QueryOrQueryText { | ||
| match self { | ||
| QueryOrQueryTextPerLanguage::SingleQueryText(query_text) => (&**query_text).into(), | ||
| QueryOrQueryTextPerLanguage::PerLanguage(per_language) => { | ||
| per_language.get(&language).unwrap().clone().into() | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl From<String> for QueryOrQueryTextPerLanguage { | ||
| fn from(value: String) -> Self { | ||
| Self::SingleQueryText(value) | ||
| } | ||
| } | ||
|
|
||
| impl From<HashMap<SupportedLanguage, Arc<Query>>> for QueryOrQueryTextPerLanguage { | ||
| fn from(value: HashMap<SupportedLanguage, Arc<Query>>) -> Self { | ||
| Self::PerLanguage(value) | ||
| } | ||
| } | ||
|
|
||
| pub enum QueryOrQueryText<'a> { | ||
| QueryText(&'a str), | ||
| Query(Arc<Query>), | ||
| } | ||
|
|
||
| impl<'a> From<&'a str> for QueryOrQueryText<'a> { | ||
| fn from(value: &'a str) -> Self { | ||
| Self::QueryText(value) | ||
| } | ||
| } | ||
|
|
||
| impl<'a> From<Arc<Query>> for QueryOrQueryText<'a> { | ||
| fn from(value: Arc<Query>) -> Self { | ||
| Self::Query(value) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per helixbass/tree-sitter-lint#4, updating this to allow publishing that crate while this hasn't "landed"