report: reuse ariadne

This commit is contained in:
Astro 2022-02-04 17:41:28 +01:00
parent 9f115c5beb
commit ae4cf0aef4
6 changed files with 84 additions and 125 deletions

16
Cargo.lock generated
View File

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ariadne"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7080ae01b2f0c312065d4914cd0f0de045eb8832e9415b355106a6cff3073cb4"
dependencies = [
"yansi",
]
[[package]]
name = "atty"
version = "0.2.14"
@ -59,6 +68,7 @@ checksum = "328b822bdcba4d4e402be8d9adb6eebf269f969f8eadef977a553ff3c4fbcb58"
name = "deadnix"
version = "0.1.3"
dependencies = [
"ariadne",
"clap",
"rnix",
"rowan",
@ -257,3 +267,9 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yansi"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"

View File

@ -14,3 +14,4 @@ rowan = "0.12"
rnix = "0.10"
clap = "3"
walkdir = "2"
ariadne = "0.1"

View File

@ -38,38 +38,32 @@ $ nix run github:astro/deadnix test.nix
```
```
test.nix:1:
> unusedArgs@{ unusedArg, usedArg, ... }:
> ^^^^^^^^^^ ^^^^^^^^^
> | |
> | Unused lambda pattern: unusedArg
> Unused lambda pattern: unusedArgs
test.nix:3:
> inherit (builtins) unused_inherit;
> ^^^^^^^^^^^^^^
> |
> Unused let binding: unused_inherit
test.nix:5:
> unused = "fnord";
> ^^^^^^
> |
> Unused let binding: unused
test.nix:10:
> shadowed = 42;
> ^^^^^^^^
> |
> Unused let binding: shadowed
test.nix:11:
> _unused = unused: false;
> ^^^^^^^ ^^^^^^
> | |
> | Unused lambda argument: unused
> Unused let binding: _unused
test.nix:13:
> x = { unusedArg2, x ? args.y, ... }@args: used1 + x;
> ^^^^^^^^^^
> |
> Unused lambda pattern: unusedArg2
Warning: Unused declarations were found.
╭─[example.nix:1:1]
1 │ unusedArgs@{ unusedArg, usedArg, ... }:
· ─────┬──── ────┬────
· │ ╰────── Unused lambda pattern: unusedArg
· │
· ╰────────────────── Unused lambda pattern: unusedArgs
3 │ inherit (builtins) unused_inherit;
· ───────┬──────
· ╰──────── Unused let binding: unused_inherit
5 │ unused = "fnord";
· ───┬──
· ╰──── Unused let binding: unused
10 │ shadowed = 42;
· ────┬───
· ╰───── Unused let binding: shadowed
11 │ _unused = unused: false;
· ───┬─── ───┬──
· │ ╰──── Unused lambda argument: unused
· │
· ╰────────────── Unused let binding: _unused
13 │ x = { unusedArg2, x ? args.y, ... }@args: used1 + x;
· ─────┬────
· ╰────── Unused lambda pattern: unusedArg2
────╯
```

View File

@ -125,7 +125,7 @@ fn main() {
let results = settings.find_dead_code(&ast.node());
report_count += results.len();
if !quiet && !results.is_empty() {
crate::report::Report::new(file.to_string(), &content, results.clone()).print();
crate::report::print(file.to_string(), &content, &results);
}
if edit {
let new_ast = crate::edit::edit_dead_code(&content, results.into_iter());

View File

@ -1,98 +1,32 @@
use ariadne::{Label, Report, ReportKind, sources};
use crate::dead_code::DeadCode;
use rnix::types::TypedNode;
pub struct LineReport {
line_start: usize,
line_number: usize,
line: String,
results: Vec<DeadCode>,
}
pub fn print(file: String, content: &str, results: &[DeadCode]) {
let first_result_range = results[0].binding.name.node().text_range();
let mut builder = Report::build(
ReportKind::Warning,
file.clone(),
first_result_range.start().into()
)
.with_message("Unused declarations were found.");
pub struct Report {
file_path: String,
line_reports: Vec<LineReport>,
}
// reverse order to avoid overlapping lanes
let mut order = results.len();
for result in results {
let range = result.binding.name.node().text_range();
builder = builder.with_label(Label::new((file.clone(), range.start().into()..range.end().into()))
.with_message(format!("{}", result))
.with_color(result.scope.color())
.with_order(order as i32)
);
impl Report {
/// Create a report grouped by line
///
/// Assumes results are pre-sorted by order of appearance.
pub fn new(file_path: String, content: &str, results: Vec<DeadCode>) -> Self {
let mut lines = Vec::new();
let mut offset = 0;
while let Some(next) = content[offset..].find('\n') {
let line = &content[offset..offset + next];
lines.push((offset, line));
offset += next + 1;
}
lines.push((offset, &content[offset..]));
let mut last_line = 0;
let mut line_reports = Vec::new();
for result in results {
let range = result.binding.name.node().text_range();
let start = usize::from(range.start());
let line_number = lines.iter().filter(|(offset, _)| *offset <= start).count();
if line_number != last_line {
last_line = line_number;
line_reports.push(LineReport {
line_start: lines[line_number - 1].0,
line_number,
line: lines[line_number - 1].1.to_string(),
results: Vec::new(),
});
}
let line_results = &mut line_reports.last_mut().unwrap().results;
line_results.push(result);
}
Report {
file_path,
line_reports,
}
order -= 1;
}
pub fn print(&self) {
for LineReport {
line_start,
line_number,
line,
results,
} in &self.line_reports
{
// file location
println!("{}:{}:", self.file_path, line_number);
// line
println!("> {}", line);
// underscores ^^^^^^^^^
let mut pos = *line_start;
print!("> ");
for result in results.iter() {
let range = result.binding.name.node().text_range();
let start = usize::from(range.start());
let end = usize::from(range.end());
print!("{0: <1$}{2:^<3$}", "", start - pos, "", end - start);
pos = end;
}
println!();
let mut bars = String::new();
let mut pos = *line_start;
for result in results.iter() {
let range = result.binding.name.node().text_range();
let start = usize::from(range.start());
bars = format!("{}{1: <2$}|", bars, "", start - pos);
pos = start + 1;
}
println!("> {}", bars);
// messages
for result in results.iter().rev() {
let range = result.binding.name.node().text_range();
let start = usize::from(range.start());
println!("> {}{}", &bars[..start - line_start], result);
}
}
}
builder.finish()
.print(sources(vec![
(file, content)
]))
.unwrap()
}

View File

@ -1,10 +1,11 @@
use crate::{binding::Binding, usage};
use std::fmt;
use rnix::{
types::{AttrSet, EntryHolder, Ident, Lambda, LetIn, Pattern, TokenWrapper, TypedNode},
NixLanguage, SyntaxKind,
};
use rowan::api::SyntaxNode;
use std::fmt;
use ariadne::Color;
use crate::{binding::Binding, usage};
/// AST subtree that declares variables
#[derive(Debug, Clone)]
@ -217,4 +218,17 @@ impl Scope {
}),
}
}
pub fn color(&self) -> Color {
match self {
Scope::LambdaPattern(_, _) =>
Color::Magenta,
Scope::LambdaArg(_, _) =>
Color::Cyan,
Scope::LetIn(_) =>
Color::Red,
Scope::RecAttrSet(_) =>
Color::Yellow,
}
}
}