diff --git a/.github/workflows/pr-lint.yaml b/.github/workflows/pr-lint.yaml index 41b47a771..d1e4f9c61 100644 --- a/.github/workflows/pr-lint.yaml +++ b/.github/workflows/pr-lint.yaml @@ -4,6 +4,9 @@ on: pull_request: types: - opened +``` + + - opened - edited - synchronize diff --git a/crates/cli/src/commands/list.rs b/crates/cli/src/commands/list.rs index ca89fdec6..07e7e4789 100644 --- a/crates/cli/src/commands/list.rs +++ b/crates/cli/src/commands/list.rs @@ -13,6 +13,9 @@ use crate::{ #[derive(Args, Debug, Serialize)] pub struct ListArgs { /// List only at or above an enforcement level. + /// List only items targeting a specific language. + #[clap(long = "language", alias = "lang")] + pub lang: Option, #[clap(long = "level")] pub level: Option, /// List items from a specific source. diff --git a/crates/cli/src/commands/patterns_list.rs b/crates/cli/src/commands/patterns_list.rs index 73f68ec1f..3829d4d72 100644 --- a/crates/cli/src/commands/patterns_list.rs +++ b/crates/cli/src/commands/patterns_list.rs @@ -33,9 +33,13 @@ impl Listable for ResolvedGritDefinition { normal_tags.extend(more_tags); normal_tags } -} pub(crate) async fn run_patterns_list(arg: ListArgs, parent: GlobalFormatFlags) -> Result<()> { let (resolved, curr_repo) = resolve_from_flags_or_cwd(&parent, &arg.source).await?; - list_applyables(false, false, resolved, arg.level, &parent, curr_repo).await -} + let filtered_resolved: Vec<_> = if let Some(ref lang) = arg.lang { + resolved.into_iter().filter(|pattern| pattern.language().map_or(false, |l| l == lang)).collect() + } else { + resolved + }; + list_applyables(false, false, filtered_resolved, arg.level, &parent, curr_repo).await +} \ No newline at end of file diff --git a/crates/cli_bin/tests/snapshots/apply__language_option_inline_pattern_apply.snap b/crates/cli_bin/tests/snapshots/apply__language_option_inline_pattern_apply.snap index c7b0ba948..74562810a 100644 --- a/crates/cli_bin/tests/snapshots/apply__language_option_inline_pattern_apply.snap +++ b/crates/cli_bin/tests/snapshots/apply__language_option_inline_pattern_apply.snap @@ -8,5 +8,27 @@ import os import openai from flask import Flask, redirect, render_template, request, url_for +import pytest + +def test_language_option_inline_pattern_apply(): + # Set up the test environment and arguments + args = ["grit", "patterns", "list", "--lang", "python"] + expected_patterns = ["pattern1", "pattern2"] # Example expected patterns for Python + + # Run the command with the language argument + result = run_command(args) + + # Assert that the output contains the expected patterns for the specified language + for pattern in expected_patterns: + assert pattern in result.output + +app = Flask(__name__) +openai.api_key = dotenv.fetch("OPENAI_API_KEY") +``` + + + +``` + app = Flask(__name__) openai.api_key = dotenv.fetch("OPENAI_API_KEY") diff --git a/crates/core/src/pattern_compiler/within_compiler.rs b/crates/core/src/pattern_compiler/within_compiler.rs index 22718f725..266a618a1 100644 --- a/crates/core/src/pattern_compiler/within_compiler.rs +++ b/crates/core/src/pattern_compiler/within_compiler.rs @@ -21,6 +21,10 @@ impl NodeCompiler for WithinCompiler { .child_by_field_name("pattern") .ok_or_else(|| anyhow!("missing pattern of pattern within"))?; let within = PatternCompiler::from_node(&within, context)?; - Ok(Within::new(within)) + let until = node + .child_by_field_name("until") + .map(|n| PatternCompiler::from_node(&n, context)) + .transpose()?; + Ok(Within::new(within, until)) } -} +} \ No newline at end of file diff --git a/crates/grit-pattern-matcher/src/pattern/resolved_pattern.rs b/crates/grit-pattern-matcher/src/pattern/resolved_pattern.rs index 17b673b3c..bee1e3476 100644 --- a/crates/grit-pattern-matcher/src/pattern/resolved_pattern.rs +++ b/crates/grit-pattern-matcher/src/pattern/resolved_pattern.rs @@ -32,7 +32,7 @@ pub trait ResolvedPattern<'a, Q: QueryContext>: Clone + Debug + PartialEq { fn from_list_parts(parts: impl Iterator) -> Self; - fn from_node_binding(node: Q::Node<'a>) -> Self { + fn from_node_binding(node: &Q::Node<'a>) -> Self { Self::from_binding(Binding::from_node(node)) } diff --git a/crates/grit-pattern-matcher/src/pattern/within.rs b/crates/grit-pattern-matcher/src/pattern/within.rs index 1a23c8f20..c88fff704 100644 --- a/crates/grit-pattern-matcher/src/pattern/within.rs +++ b/crates/grit-pattern-matcher/src/pattern/within.rs @@ -11,11 +11,12 @@ use grit_util::{AnalysisLogs, AstNode}; #[derive(Debug, Clone)] pub struct Within { pub pattern: Pattern, + pub until: Option>, } impl Within { - pub fn new(pattern: Pattern) -> Self { - Self { pattern } + pub fn new(pattern: Pattern, until: Option>) -> Self { + Self { pattern, until } } } @@ -52,7 +53,7 @@ impl Matcher for Within { for n in node.ancestors() { let state = cur_state.clone(); if self.pattern.execute( - &ResolvedPattern::from_node_binding(n), + &ResolvedPattern::from_node_binding(&n), &mut cur_state, context, logs, @@ -61,6 +62,17 @@ impl Matcher for Within { } else { cur_state = state; } + + if let Some(until) = &self.until { + if until.execute( + &ResolvedPattern::from_node_binding(&n), + &mut cur_state, + context, + logs, + )? { + break; + } + } } if did_match { *init_state = cur_state; @@ -69,4 +81,4 @@ impl Matcher for Within { Ok(false) } } -} +} \ No newline at end of file