mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 01:51:30 +00:00
Implement shell autocompletion for rule codes
For example: $ ruff check --select=EM<Tab> EM -- flake8-errmsg EM10 EM1 -- EM101 -- raw-string-in-exception EM102 -- f-string-in-exception EM103 -- dot-format-in-exception (You will need to enable autocompletion as described in the Autocompletion section in the README.) Fixes #2808. (The --help help change in the README is due to a clap bug, for which I already submitted a fix: https://github.com/clap-rs/clap/pull/4710.)
This commit is contained in:
parent
ca49b00e55
commit
70e378b736
5 changed files with 86 additions and 7 deletions
|
@ -468,7 +468,7 @@ Options:
|
||||||
--show-settings
|
--show-settings
|
||||||
See the settings Ruff will use to lint a given Python file
|
See the settings Ruff will use to lint a given Python file
|
||||||
-h, --help
|
-h, --help
|
||||||
Print help
|
Print help (see more with '--help')
|
||||||
|
|
||||||
Rule selection:
|
Rule selection:
|
||||||
--select <RULE_CODE>
|
--select <RULE_CODE>
|
||||||
|
|
|
@ -21,7 +21,7 @@ bisection = { version = "0.1.0" }
|
||||||
bitflags = { version = "1.3.2" }
|
bitflags = { version = "1.3.2" }
|
||||||
cfg-if = { version = "1.0.0" }
|
cfg-if = { version = "1.0.0" }
|
||||||
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
|
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" }
|
colored = { version = "2.0.0" }
|
||||||
dirs = { version = "4.0.0" }
|
dirs = { version = "4.0.0" }
|
||||||
fern = { version = "0.6.1" }
|
fern = { version = "0.6.1" }
|
||||||
|
|
|
@ -233,3 +233,76 @@ pub(crate) enum Specificity {
|
||||||
Code4Chars,
|
Code4Chars,
|
||||||
Code5Chars,
|
Code5Chars,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod clap_completion {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -109,7 +109,8 @@ pub struct CheckArgs {
|
||||||
long,
|
long,
|
||||||
value_delimiter = ',',
|
value_delimiter = ',',
|
||||||
value_name = "RULE_CODE",
|
value_name = "RULE_CODE",
|
||||||
help_heading = "Rule selection"
|
help_heading = "Rule selection",
|
||||||
|
hide_possible_values = true
|
||||||
)]
|
)]
|
||||||
pub select: Option<Vec<RuleSelector>>,
|
pub select: Option<Vec<RuleSelector>>,
|
||||||
/// Comma-separated list of rule codes to disable.
|
/// Comma-separated list of rule codes to disable.
|
||||||
|
@ -117,7 +118,8 @@ pub struct CheckArgs {
|
||||||
long,
|
long,
|
||||||
value_delimiter = ',',
|
value_delimiter = ',',
|
||||||
value_name = "RULE_CODE",
|
value_name = "RULE_CODE",
|
||||||
help_heading = "Rule selection"
|
help_heading = "Rule selection",
|
||||||
|
hide_possible_values = true
|
||||||
)]
|
)]
|
||||||
pub ignore: Option<Vec<RuleSelector>>,
|
pub ignore: Option<Vec<RuleSelector>>,
|
||||||
/// Like --select, but adds additional rule codes on top of the selected
|
/// Like --select, but adds additional rule codes on top of the selected
|
||||||
|
@ -126,7 +128,8 @@ pub struct CheckArgs {
|
||||||
long,
|
long,
|
||||||
value_delimiter = ',',
|
value_delimiter = ',',
|
||||||
value_name = "RULE_CODE",
|
value_name = "RULE_CODE",
|
||||||
help_heading = "Rule selection"
|
help_heading = "Rule selection",
|
||||||
|
hide_possible_values = true
|
||||||
)]
|
)]
|
||||||
pub extend_select: Option<Vec<RuleSelector>>,
|
pub extend_select: Option<Vec<RuleSelector>>,
|
||||||
/// Like --ignore. (Deprecated: You can just use --ignore instead.)
|
/// Like --ignore. (Deprecated: You can just use --ignore instead.)
|
||||||
|
@ -164,7 +167,8 @@ pub struct CheckArgs {
|
||||||
long,
|
long,
|
||||||
value_delimiter = ',',
|
value_delimiter = ',',
|
||||||
value_name = "RULE_CODE",
|
value_name = "RULE_CODE",
|
||||||
help_heading = "Rule selection"
|
help_heading = "Rule selection",
|
||||||
|
hide_possible_values = true
|
||||||
)]
|
)]
|
||||||
pub fixable: Option<Vec<RuleSelector>>,
|
pub fixable: Option<Vec<RuleSelector>>,
|
||||||
/// List of rule codes to treat as ineligible for autofix. Only applicable
|
/// List of rule codes to treat as ineligible for autofix. Only applicable
|
||||||
|
@ -173,7 +177,8 @@ pub struct CheckArgs {
|
||||||
long,
|
long,
|
||||||
value_delimiter = ',',
|
value_delimiter = ',',
|
||||||
value_name = "RULE_CODE",
|
value_name = "RULE_CODE",
|
||||||
help_heading = "Rule selection"
|
help_heading = "Rule selection",
|
||||||
|
hide_possible_values = true
|
||||||
)]
|
)]
|
||||||
pub unfixable: Option<Vec<RuleSelector>>,
|
pub unfixable: Option<Vec<RuleSelector>>,
|
||||||
/// Respect file exclusions via `.gitignore` and other standard ignore
|
/// Respect file exclusions via `.gitignore` and other standard ignore
|
||||||
|
|
|
@ -57,6 +57,7 @@ pub fn register_rules(input: &Input) -> proc_macro2::TokenStream {
|
||||||
PartialOrd,
|
PartialOrd,
|
||||||
Ord,
|
Ord,
|
||||||
AsRefStr,
|
AsRefStr,
|
||||||
|
::strum_macros::IntoStaticStr,
|
||||||
)]
|
)]
|
||||||
#[strum(serialize_all = "kebab-case")]
|
#[strum(serialize_all = "kebab-case")]
|
||||||
pub enum Rule { #rule_variants }
|
pub enum Rule { #rule_variants }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue