From 6cbf83c9462b993f2fa5b3c4334dd469c182c8af Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Thu, 7 Feb 2019 20:00:58 +0200 Subject: [PATCH 1/2] Add new assist to remove dbg!() calls This fixes #758. Currently we try to maintain the cursor position relative to the statement under cursor, if the cursor is inside the dbg! macro call. Meaning: let foo = dbg!(some.complex<|>().expression()); Should turn into: let foo = some.complex<|>().expression(); With the cursor staying in place. --- crates/ra_assists/src/lib.rs | 2 + crates/ra_assists/src/remove_dbg.rs | 124 ++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 crates/ra_assists/src/remove_dbg.rs diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 062dd880440..555af51bce0 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -73,6 +73,7 @@ mod fill_match_arms; mod introduce_variable; mod replace_if_let_with_match; mod split_import; +mod remove_dbg; fn all_assists() -> &'static [fn(AssistCtx) -> Option] { &[ add_derive::add_derive, @@ -83,6 +84,7 @@ fn all_assists() -> &'static [fn(AssistCtx) -> Option) -> Option { + let macro_call = ctx.node_at_offset::()?; + + if !is_valid_macrocall(macro_call, "dbg")? { + return None; + } + + let macro_range = macro_call.syntax().range(); + + // If the cursor is inside the macrocall, we'll try to maintain + // the cursor position by subtracting the length of dbg!( from the start + // of the filerange, otherwise we'll default to using the start of the macrocall + let cursor_pos = { + let file_range = ctx.frange.range; + + let offset_start = file_range + .start() + .checked_sub(macro_range.start()) + .unwrap_or_else(|| TextUnit::from(0)); + + let dbg_size = dbg!(TextUnit::of_str("dbg!(")); + + if offset_start > dbg_size { + file_range.start() - dbg_size + } else { + macro_range.start() + } + }; + + let macro_content = { + let macro_args = macro_call.token_tree()?.syntax(); + let _ = dbg!(macro_args.text()); + let range = dbg!(macro_args.range()); + let start = range.start() + TextUnit::of_char('('); + let end = range.end() - TextUnit::of_char(')'); + + macro_args.text().slice(start..end).to_string() + }; + + ctx.build("remove dbg!()", |edit| { + edit.replace(macro_range, macro_content); + edit.set_cursor(cursor_pos); + }) +} + +/// Verifies that the given macro_call actually matches the given name +/// and contains proper ending tokens +fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option { + let path = macro_call.path()?; + let name_ref = path.segment()?.name_ref()?; + + // Make sure it is actually a dbg-macrocall, dbg followed by ! + let excl = path.syntax().next_sibling()?; + + if name_ref.text() != macro_name || excl.kind() != EXCL { + return None; + } + + let node = macro_call.token_tree()?.syntax(); + let first_child = node.first_child()?; + let last_child = node.last_child()?; + + match (first_child.kind(), last_child.kind()) { + (L_PAREN, R_PAREN) | (L_BRACK, R_BRACK) | (L_CURLY, R_CURLY) => Some(true), + _ => Some(false), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::helpers::{check_assist, check_assist_not_applicable}; + + #[test] + fn test_remove_dbg() { + check_assist(remove_dbg, "<|>dbg!(1 + 1)", "<|>1 + 1"); + + check_assist(remove_dbg, "dbg!<|>((1 + 1))", "<|>(1 + 1)"); + + check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 <|>+ 1"); + + check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = <|>1 + 1"); + + check_assist( + remove_dbg, + " +fn foo(n: usize) { + if let Some(_) = dbg!(n.<|>checked_sub(4)) { + // ... + } +} +", + " +fn foo(n: usize) { + if let Some(_) = n.<|>checked_sub(4) { + // ... + } +} +", + ); + } + #[test] + fn test_remove_dbg_with_brackets_and_braces() { + check_assist(remove_dbg, "dbg![<|>1 + 1]", "<|>1 + 1"); + check_assist(remove_dbg, "dbg!{<|>1 + 1}", "<|>1 + 1"); + } + + #[test] + fn test_remove_dbg_not_applicable() { + check_assist_not_applicable(remove_dbg, "<|>vec![1, 2, 3]"); + check_assist_not_applicable(remove_dbg, "<|>dbg(5, 6, 7)"); + check_assist_not_applicable(remove_dbg, "<|>dbg!(5, 6, 7"); + } +} From be7c5eecc4ec9e099bf34e78289cd672aacbd168 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Thu, 7 Feb 2019 20:42:00 +0200 Subject: [PATCH 2/2] Remove unnecessary dbg! calls --- crates/ra_assists/src/remove_dbg.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/ra_assists/src/remove_dbg.rs b/crates/ra_assists/src/remove_dbg.rs index 6609abab296..40f97a84920 100644 --- a/crates/ra_assists/src/remove_dbg.rs +++ b/crates/ra_assists/src/remove_dbg.rs @@ -28,7 +28,7 @@ pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option { .checked_sub(macro_range.start()) .unwrap_or_else(|| TextUnit::from(0)); - let dbg_size = dbg!(TextUnit::of_str("dbg!(")); + let dbg_size = TextUnit::of_str("dbg!("); if offset_start > dbg_size { file_range.start() - dbg_size @@ -39,8 +39,7 @@ pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option { let macro_content = { let macro_args = macro_call.token_tree()?.syntax(); - let _ = dbg!(macro_args.text()); - let range = dbg!(macro_args.range()); + let range = macro_args.range(); let start = range.start() + TextUnit::of_char('('); let end = range.end() - TextUnit::of_char(')');