Enable tab completion for ruff rule (#7560)

## Summary

Writing `ruff rule E1`, then tab, shows:

<img width="724" alt="Screen Shot 2023-09-20 at 9 29 09 PM"
src="00297f24-8828-4485-a00e-6af1ab4e7875">

Closes https://github.com/astral-sh/ruff/issues/2812.
This commit is contained in:
Charlie Marsh 2023-09-20 22:05:39 -04:00 committed by GitHub
parent ad893f8295
commit b685ee4749
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 3 deletions

View file

@ -5,6 +5,8 @@
//!
//! [Ruff]: https://github.com/astral-sh/ruff
#[cfg(feature = "clap")]
pub use registry::clap_completion::RuleParser;
#[cfg(feature = "clap")]
pub use rule_selector::clap_completion::RuleSelectorParser;
pub use rule_selector::RuleSelector;

View file

@ -360,6 +360,64 @@ pub const INCOMPATIBLE_CODES: &[(Rule, Rule, &str); 2] = &[
),
];
#[cfg(feature = "clap")]
pub mod clap_completion {
use clap::builder::{PossibleValue, TypedValueParser, ValueParserFactory};
use strum::IntoEnumIterator;
use crate::registry::Rule;
#[derive(Clone)]
pub struct RuleParser;
impl ValueParserFactory for Rule {
type Parser = RuleParser;
fn value_parser() -> Self::Parser {
RuleParser
}
}
impl TypedValueParser for RuleParser {
type Value = Rule;
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))?;
Rule::from_code(value).map_err(|_| {
let mut error =
clap::Error::new(clap::error::ErrorKind::ValueValidation).with_cmd(cmd);
if let Some(arg) = arg {
error.insert(
clap::error::ContextKind::InvalidArg,
clap::error::ContextValue::String(arg.to_string()),
);
}
error.insert(
clap::error::ContextKind::InvalidValue,
clap::error::ContextValue::String(value.to_string()),
);
error
})
}
fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
Some(Box::new(Rule::iter().map(|rule| {
let name = rule.noqa_code().to_string();
let help = rule.as_ref().to_string();
PossibleValue::new(name).help(help)
})))
}
}
}
#[cfg(test)]
mod tests {
use std::mem::size_of;