Skip to content

Commit

Permalink
Implement a --show-source setting (#698)
Browse files Browse the repository at this point in the history
  • Loading branch information
harupy authored Nov 18, 2022
1 parent 49559da commit e81efa5
Show file tree
Hide file tree
Showing 14 changed files with 166 additions and 16 deletions.
22 changes: 21 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ edition = "2021"
name = "ruff"

[dependencies]
annotate-snippets = { version = "0.9.1", features = ["color"] }
anyhow = { version = "1.0.66" }
atty = { version = "0.2.14" }
bincode = { version = "1.3.3" }
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ ruff path/to/code/ --select F401 --select F403
See `ruff --help` for more:

```shell
ruff: An extremely fast Python linter.
Ruff: An extremely fast Python linter.

Usage: ruff [OPTIONS] <FILES>...

Expand Down Expand Up @@ -231,10 +231,12 @@ Options:
List of mappings from file pattern to code to exclude
--format <FORMAT>
Output serialization format for error messages [default: text] [possible values: text, json]
--show-source
Show violations with source code
--show-files
See the files ruff will be run against with the current settings
See the files Ruff will be run against with the current settings
--show-settings
See ruff's settings
See Ruff's settings
--add-noqa
Enable automatic additions of noqa directives to failing lines
--dummy-variable-rgx <DUMMY_VARIABLE_RGX>
Expand All @@ -244,7 +246,7 @@ Options:
--line-length <LINE_LENGTH>
Set the line-length for length-associated checks and automatic formatting
--max-complexity <MAX_COMPLEXITY>
Set the maximum cyclomatic complexity for complexity-associated checks
Max McCabe complexity allowed for a function
--stdin-filename <STDIN_FILENAME>
The name of the file when passing it through stdin
-h, --help
Expand Down
7 changes: 7 additions & 0 deletions flake8_to_ruff/src/converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ mod tests {
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_quotes: None,
Expand Down Expand Up @@ -295,6 +296,7 @@ mod tests {
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_quotes: None,
Expand Down Expand Up @@ -331,6 +333,7 @@ mod tests {
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_quotes: None,
Expand Down Expand Up @@ -367,6 +370,7 @@ mod tests {
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_quotes: None,
Expand Down Expand Up @@ -403,6 +407,7 @@ mod tests {
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_quotes: Some(flake8_quotes::settings::Options {
Expand Down Expand Up @@ -482,6 +487,7 @@ mod tests {
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_quotes: None,
Expand Down Expand Up @@ -519,6 +525,7 @@ mod tests {
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None,
flake8_annotations: None,
flake8_bugbear: None,
flake8_quotes: Some(flake8_quotes::settings::Options {
Expand Down
9 changes: 6 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::settings::configuration::Configuration;
use crate::settings::types::{PatternPrefixPair, PerFileIgnore, PythonVersion};

#[derive(Debug, Parser)]
#[command(author, about = "ruff: An extremely fast Python linter.")]
#[command(author, about = "Ruff: An extremely fast Python linter.")]
#[command(version)]
pub struct Cli {
#[arg(required = true)]
Expand Down Expand Up @@ -72,10 +72,13 @@ pub struct Cli {
/// Output serialization format for error messages.
#[arg(long, value_enum, default_value_t=SerializationFormat::Text)]
pub format: SerializationFormat,
/// See the files ruff will be run against with the current settings.
/// Show violations with source code.
#[arg(long)]
pub show_source: bool,
/// See the files Ruff will be run against with the current settings.
#[arg(long)]
pub show_files: bool,
/// See ruff's settings.
/// See Ruff's settings.
#[arg(long)]
pub show_settings: bool,
/// Enable automatic additions of noqa directives to failing lines.
Expand Down
22 changes: 19 additions & 3 deletions src/linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::check_tokens::check_tokens;
use crate::checks::{Check, CheckCode, CheckKind, LintSource};
use crate::code_gen::SourceGenerator;
use crate::directives::Directives;
use crate::message::Message;
use crate::message::{Message, Source};
use crate::noqa::add_noqa;
use crate::settings::Settings;
use crate::source_code_locator::SourceCodeLocator;
Expand Down Expand Up @@ -176,7 +176,15 @@ pub fn lint_stdin(
// Convert to messages.
Ok(checks
.into_iter()
.map(|check| Message::from_check(path.to_string_lossy().to_string(), check))
.map(|check| {
let filename = path.to_string_lossy().to_string();
let source = if settings.show_source {
Some(Source::from_check(&check, &locator))
} else {
None
};
Message::from_check(check, filename, source)
})
.collect())
}

Expand Down Expand Up @@ -233,7 +241,15 @@ pub fn lint_path(
// Convert to messages.
let messages: Vec<Message> = checks
.into_iter()
.map(|check| Message::from_check(path.to_string_lossy().to_string(), check))
.map(|check| {
let filename = path.to_string_lossy().to_string();
let source = if settings.show_source {
Some(Source::from_check(&check, &locator))
} else {
None
};
Message::from_check(check, filename, source)
})
.collect();
#[cfg(not(target_family = "wasm"))]
cache::set(path, &metadata, settings, autofix, &messages, mode);
Expand Down
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ fn run_once(
location: Default::default(),
end_location: Default::default(),
filename: path.to_string_lossy().to_string(),
source: None,
}]
} else {
error!("Failed to check {}: {message}", path.to_string_lossy());
Expand Down Expand Up @@ -281,6 +282,9 @@ fn inner_main() -> Result<ExitCode> {
if let Some(fix) = fix {
configuration.fix = fix;
}
if cli.show_source {
configuration.show_source = true;
}

if cli.show_settings && cli.show_files {
eprintln!("Error: specify --show-settings or show-files (not both).");
Expand Down
79 changes: 74 additions & 5 deletions src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ use std::cmp::Ordering;
use std::fmt;
use std::path::Path;

use annotate_snippets::display_list::{DisplayList, FormatOptions};
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
use colored::Colorize;
use rustpython_parser::ast::Location;
use serde::{Deserialize, Serialize};

use crate::ast::types::Range;
use crate::checks::{Check, CheckKind};
use crate::fs::relativize_path;
use crate::source_code_locator::SourceCodeLocator;

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Message {
Expand All @@ -16,16 +20,18 @@ pub struct Message {
pub location: Location,
pub end_location: Location,
pub filename: String,
pub source: Option<Source>,
}

impl Message {
pub fn from_check(filename: String, check: Check) -> Self {
pub fn from_check(check: Check, filename: String, source: Option<Source>) -> Self {
Self {
kind: check.kind,
fixed: check.fix.map(|fix| fix.applied).unwrap_or_default(),
location: Location::new(check.location.row(), check.location.column() + 1),
end_location: Location::new(check.end_location.row(), check.end_location.column() + 1),
filename,
source,
}
}
}
Expand All @@ -48,8 +54,7 @@ impl PartialOrd for Message {

impl fmt::Display for Message {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
let label = format!(
"{}{}{}{}{}{} {} {}",
relativize_path(Path::new(&self.filename)).white().bold(),
":".cyan(),
Expand All @@ -58,7 +63,71 @@ impl fmt::Display for Message {
self.location.column(),
":".cyan(),
self.kind.code().as_ref().red().bold(),
self.kind.body()
)
self.kind.body(),
);
match &self.source {
None => write!(f, "{}", label),
Some(source) => {
let snippet = Snippet {
title: Some(Annotation {
label: Some(&label),
annotation_type: AnnotationType::Error,
// The ID (error number) is already encoded in the `label`.
id: None,
}),
footer: vec![],
slices: vec![Slice {
source: &source.contents,
line_start: self.location.row(),
annotations: vec![SourceAnnotation {
label: self.kind.code().as_ref(),
annotation_type: AnnotationType::Error,
range: source.range,
}],
// The origin (file name, line number, and column number) is already encoded
// in the `label`.
origin: None,
fold: false,
}],
opt: FormatOptions {
color: true,
..Default::default()
},
};
// `split_once(' ')` strips "error: " from `message`.
let message = DisplayList::from(snippet).to_string();
let (_, message) = message.split_once(' ').unwrap();
write!(f, "{}", message)
}
}
}
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Source {
pub contents: String,
pub range: (usize, usize),
}

impl Source {
pub fn from_check(check: &Check, locator: &SourceCodeLocator) -> Self {
let source = locator.slice_source_code_range(&Range {
location: Location::new(check.location.row(), 0),
end_location: Location::new(check.end_location.row() + 1, 0),
});
let num_chars_in_range = locator
.slice_source_code_range(&Range {
location: check.location,
end_location: check.end_location,
})
.chars()
.count();
Source {
contents: source.to_string(),
range: (
check.location.column(),
check.location.column() + num_chars_in_range,
),
}
}
}
2 changes: 2 additions & 0 deletions src/settings/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct Configuration {
pub select: Vec<CheckCodePrefix>,
pub src: Vec<PathBuf>,
pub target_version: PythonVersion,
pub show_source: bool,
// Plugins
pub flake8_annotations: flake8_annotations::settings::Settings,
pub flake8_bugbear: flake8_bugbear::settings::Settings,
Expand Down Expand Up @@ -134,6 +135,7 @@ impl Configuration {
.collect()
})
.unwrap_or_default(),
show_source: options.show_source.unwrap_or_default(),
// Plugins
flake8_annotations: options
.flake8_annotations
Expand Down
Loading

0 comments on commit e81efa5

Please sign in to comment.