Skip to content

Commit

Permalink
Show rule codes in shell tab completion
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Sep 14, 2023
1 parent 21539f1 commit 492a142
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 44 deletions.
2 changes: 2 additions & 0 deletions crates/ruff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
//!
//! [Ruff]: https://github.com/astral-sh/ruff

#[cfg(feature = "clap")]
pub use rule_selector::clap_completion::RuleSelectorParser;
pub use rule_selector::RuleSelector;
pub use rules::pycodestyle::rules::{IOError, SyntaxError};

Expand Down
70 changes: 45 additions & 25 deletions crates/ruff/src/rule_selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,14 @@ pub enum Specificity {
}

#[cfg(feature = "clap")]
mod clap_completion {
pub mod clap_completion {
use clap::builder::{PossibleValue, TypedValueParser, ValueParserFactory};
use strum::IntoEnumIterator;

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

Expand All @@ -362,17 +363,29 @@ mod clap_completion {

fn parse_ref(
&self,
_cmd: &clap::Command,
_arg: Option<&clap::Arg>,
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))
value.parse().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> + '_>> {
Expand All @@ -387,27 +400,34 @@ mod clap_completion {
RuleCodePrefix::iter()
// Filter out rule gated behind `#[cfg(feature = "unreachable-code")]`, which is
// off-by-default
.filter(|p| {
format!("{}{}", p.linter().common_prefix(), p.short_code())
!= "RUF014"
.filter(|prefix| {
format!(
"{}{}",
prefix.linter().common_prefix(),
prefix.short_code()
) != "RUF014"
})
.map(|p| {
let prefix = p.linter().common_prefix();
let code = p.short_code();

let mut rules_iter = p.rules();
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
.filter_map(|prefix| {
// Ex) `UP`
if prefix.short_code().is_empty() {
let code = prefix.linter().common_prefix();
let name = prefix.linter().name();
return Some(PossibleValue::new(code).help(name));
}

// Ex) `UP004`
if is_single_rule_selector(&prefix) {
let rule = prefix.rules().next()?;
let code = format!(
"{}{}",
prefix.linter().common_prefix(),
prefix.short_code()
);
let name: &'static str = rule.into();
return Some(PossibleValue::new(code).help(name));
}

None
}),
),
),
Expand Down
26 changes: 10 additions & 16 deletions crates/ruff_cli/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use std::path::PathBuf;
use std::str::FromStr;

use clap::{command, Parser};
use regex::Regex;
use ruff::line_width::LineLength;
use rustc_hash::FxHashMap;

use ruff::line_width::LineLength;
use ruff::logging::LogLevel;
use ruff::registry::Rule;
use ruff::settings::types::{
FilePattern, PatternPrefixPair, PerFileIgnore, PreviewMode, PythonVersion, SerializationFormat,
};
use ruff::RuleSelector;
use ruff::{RuleSelector, RuleSelectorParser};
use ruff_workspace::configuration::{Configuration, RuleSelection};
use ruff_workspace::resolver::ConfigProcessor;

Expand Down Expand Up @@ -129,7 +128,7 @@ pub struct CheckCommand {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = parse_rule_selector,
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide_possible_values = true
)]
Expand All @@ -139,7 +138,7 @@ pub struct CheckCommand {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = parse_rule_selector,
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide_possible_values = true
)]
Expand All @@ -149,7 +148,7 @@ pub struct CheckCommand {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = parse_rule_selector,
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide_possible_values = true
)]
Expand All @@ -159,7 +158,7 @@ pub struct CheckCommand {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = parse_rule_selector,
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide = true
)]
Expand Down Expand Up @@ -191,7 +190,7 @@ pub struct CheckCommand {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = parse_rule_selector,
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide_possible_values = true
)]
Expand All @@ -201,7 +200,7 @@ pub struct CheckCommand {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = parse_rule_selector,
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide_possible_values = true
)]
Expand All @@ -211,7 +210,7 @@ pub struct CheckCommand {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = parse_rule_selector,
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide_possible_values = true
)]
Expand All @@ -221,7 +220,7 @@ pub struct CheckCommand {
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = parse_rule_selector,
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide = true
)]
Expand Down Expand Up @@ -511,11 +510,6 @@ impl FormatCommand {
}
}

fn parse_rule_selector(env: &str) -> Result<RuleSelector, std::io::Error> {
RuleSelector::from_str(env)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))
}

fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
match (yes, no) {
(true, false) => Some(true),
Expand Down
4 changes: 2 additions & 2 deletions crates/ruff_cli/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ fn preview_group_selector() {
----- stdout -----
----- stderr -----
error: invalid value 'PREVIEW' for '--select <RULE_CODE>': Unknown rule selector: `PREVIEW`
error: invalid value 'PREVIEW' for '--select <RULE_CODE>'
For more information, try '--help'.
"###);
Expand All @@ -470,7 +470,7 @@ fn preview_enabled_group_ignore() {
----- stdout -----
----- stderr -----
error: invalid value 'PREVIEW' for '--ignore <RULE_CODE>': Unknown rule selector: `PREVIEW`
error: invalid value 'PREVIEW' for '--ignore <RULE_CODE>'
For more information, try '--help'.
"###);
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ Ruff supports two command-line flags that alter its exit code behavior:
`--exit-non-zero-on-fix` can result in a non-zero exit code even if no violations remain after
autofixing.

## Autocompletion
## Shell autocompletion

Ruff supports autocompletion for most shells. A shell-specific completion script can be generated
by `ruff generate-shell-completion <SHELL>`, where `<SHELL>` is one of `bash`, `elvish`, `fig`, `fish`,
Expand Down

0 comments on commit 492a142

Please sign in to comment.