Skip to content
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

Implement shell autocompletion for rule codes #2906

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ Options:
--show-settings
See the settings Ruff will use to lint a given Python file
-h, --help
Print help
Print help (see more with '--help')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is related to hide_possible_values, but I'm trying to wrap my head around what it's saying, when it would show up, and what would change by adding --help -- isn't this message printed when the user runs --help?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah ... this also confused me quite a bit. As it turns out this is a Clap bug. I submitted a fix to upstream with clap-rs/clap#4710.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing that!


Rule selection:
--select <RULE_CODE>
Expand Down
2 changes: 1 addition & 1 deletion crates/ruff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ bisection = { version = "0.1.0" }
bitflags = { version = "1.3.2" }
cfg-if = { version = "1.0.0" }
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
clap = { workspace = true, features = ["derive", "env"] }
clap = { workspace = true, features = ["derive", "env", "string"] }
colored = { version = "2.0.0" }
dirs = { version = "4.0.0" }
fern = { version = "0.6.1" }
Expand Down
73 changes: 73 additions & 0 deletions crates/ruff/src/rule_selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,76 @@ pub(crate) enum Specificity {
Code4Chars,
Code5Chars,
}

mod clap_completion {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put it in a submodule so that we can easily feature gate it in the future (since we'll probably want to turn clap into an optional dependency for the ruff library).

use clap::builder::{PossibleValue, TypedValueParser, ValueParserFactory};
use strum::IntoEnumIterator;

use crate::{
codes::RuleCodePrefix,
registry::{Linter, RuleNamespace},
RuleSelector,
};

#[derive(Clone)]
pub struct RuleSelectorParser;

impl ValueParserFactory for RuleSelector {
type Parser = RuleSelectorParser;

fn value_parser() -> Self::Parser {
RuleSelectorParser
}
}

impl TypedValueParser for RuleSelectorParser {
type Value = RuleSelector;

fn parse_ref(
&self,
_cmd: &clap::Command,
_arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
let value = value
.to_str()
.ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;

value
.parse()
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::InvalidValue, e))
}

fn possible_values(
&self,
) -> Option<Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_>> {
Some(Box::new(
std::iter::once(PossibleValue::new("ALL").help("all rules")).chain(
Linter::iter()
.filter_map(|l| {
let prefix = l.common_prefix();
(!prefix.is_empty()).then(|| PossibleValue::new(prefix).help(l.name()))
})
.chain(RuleCodePrefix::iter().map(|p| {
let prefix = p.linter().common_prefix();
let code = p.short_code();

let mut rules_iter = p.into_iter();
let rule1 = rules_iter.next();
let rule2 = rules_iter.next();

let value = PossibleValue::new(format!("{prefix}{code}"));

if rule2.is_none() {
let rule1 = rule1.unwrap();
let name: &'static str = rule1.into();
value.help(name)
} else {
value
}
})),
),
))
}
}
}
15 changes: 10 additions & 5 deletions crates/ruff_cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,17 @@ pub struct CheckArgs {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
help_heading = "Rule selection",
hide_possible_values = true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added hide_possible_values because we don't want ruff help check to list all 4,000 codes.^^

)]
pub select: Option<Vec<RuleSelector>>,
/// Comma-separated list of rule codes to disable.
#[arg(
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
help_heading = "Rule selection",
hide_possible_values = true
)]
pub ignore: Option<Vec<RuleSelector>>,
/// Like --select, but adds additional rule codes on top of the selected
Expand All @@ -126,7 +128,8 @@ pub struct CheckArgs {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
help_heading = "Rule selection",
hide_possible_values = true
)]
pub extend_select: Option<Vec<RuleSelector>>,
/// Like --ignore. (Deprecated: You can just use --ignore instead.)
Expand Down Expand Up @@ -164,7 +167,8 @@ pub struct CheckArgs {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
help_heading = "Rule selection",
hide_possible_values = true
)]
pub fixable: Option<Vec<RuleSelector>>,
/// List of rule codes to treat as ineligible for autofix. Only applicable
Expand All @@ -173,7 +177,8 @@ pub struct CheckArgs {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
help_heading = "Rule selection",
hide_possible_values = true
)]
pub unfixable: Option<Vec<RuleSelector>>,
/// Respect file exclusions via `.gitignore` and other standard ignore
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_macros/src/register_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub fn register_rules(input: &Input) -> proc_macro2::TokenStream {
PartialOrd,
Ord,
AsRefStr,
::strum_macros::IntoStaticStr,
)]
#[strum(serialize_all = "kebab-case")]
pub enum Rule { #rule_variants }
Expand Down