Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/ide/src/ide/assists/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod pack_bindings;
mod remove_empty_inherit;
mod remove_empty_let_in;
mod remove_unused_binding;
mod remove_unused_with;
mod rewrite_string;

use crate::{DefDatabase, FileRange, TextEdit, WorkspaceEdit};
Expand Down Expand Up @@ -53,6 +54,7 @@ pub(crate) fn assists(db: &dyn DefDatabase, frange: FileRange) -> Vec<Assist> {
remove_empty_inherit::remove_empty_inherit,
remove_empty_let_in::remove_empty_let_in,
remove_unused_binding::remove_unused_binding,
remove_unused_with::remove_unused_with,
rewrite_string::quote_attr,
rewrite_string::rewrite_indented_to_string,
rewrite_string::rewrite_string_to_indented,
Expand Down
79 changes: 79 additions & 0 deletions crates/ide/src/ide/assists/remove_unused_with.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! Remove an unused `with ...`.
//!
//! ```nix
//! foo = with pkgs; [ pkgs.bar ];
//! ```
//! =>
//! ```nix
//! foo = [ pkgs.bar ];
//! ```
use super::{AssistKind, AssistsCtx};
use crate::DiagnosticKind::UnusedWith;
use crate::TextEdit;
use syntax::ast;

pub(super) fn remove_unused_with(ctx: &mut AssistsCtx<'_>) -> Option<()> {
let cursor_with = ctx.covering_node::<ast::With>()?;
let with_range = cursor_with.with_token()?.text_range();

let file = ctx.frange.file_id;
let check = ctx.db.liveness_check(file);
let diags = check.as_ref().to_diagnostics(ctx.db, file);

let no_relevant_diags = diags
.filter(|d| d.kind == UnusedWith && d.range.intersect(with_range).is_some())
.count()
== 0;

if no_relevant_diags {
return None;
}

let semicolon_token = cursor_with.semicolon_token()?;
let trivia_range = std::iter::successors(semicolon_token.next_token(), |tok| tok.next_token())
.take_while(|tok| tok.kind().is_trivia())
.last()
.unwrap_or(semicolon_token);

ctx.add(
"remove_unused_with",
"Remove unused with",
AssistKind::QuickFix,
vec![TextEdit {
delete: with_range.cover(trivia_range.text_range()),
insert: Default::default(),
}],
);

Some(())
}

#[cfg(test)]
mod tests {
use expect_test::expect;

define_check_assist!(super::remove_unused_with);

#[test]
fn in_use_with() {
check_no("a: $0with lib; bar");
}

#[test]
fn unused_with() {
// Simple
check("a: $0with 1;a", expect!["a: a"]);

// With trivia
check("a: $0with /* trivia */ 1; a", expect!["a: a"]);

// With array
check("a: $0with [ 1 ]; a", expect!["a: a"]);

// 1st of multiple
check("a: $0with 1; with 2; a", expect!["a: with 2; a"]);

// 2nd of multiple
check("a: with 1; $0with 2; a", expect!["a: with 1; a"]);
}
}
12 changes: 12 additions & 0 deletions docs/code_actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,18 @@ let
in {}
```

### `remove_unused_with`

Remove an unused `with ...`.

```nix
foo = with pkgs; [ pkgs.bar ];
```
=>
```nix
foo = [ pkgs.bar ];
```

### `rewrite_string_to_indented` and `rewrite_indented_to_string`

Rewrite between double quoted strings and indented strings
Expand Down