From f32081fa185b3a9df021f277c2c27fbd123d0951 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 25 Sep 2019 14:29:41 +0300 Subject: move assists to subdir --- crates/ra_assists/src/assists/remove_dbg.rs | 137 ++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 crates/ra_assists/src/assists/remove_dbg.rs (limited to 'crates/ra_assists/src/assists/remove_dbg.rs') diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/assists/remove_dbg.rs new file mode 100644 index 000000000..870133fda --- /dev/null +++ b/crates/ra_assists/src/assists/remove_dbg.rs @@ -0,0 +1,137 @@ +use crate::{Assist, AssistCtx, AssistId}; +use hir::db::HirDatabase; +use ra_syntax::{ + ast::{self, AstNode}, + TextUnit, T, +}; + +pub(crate) fn remove_dbg(mut ctx: AssistCtx) -> Option { + let macro_call = ctx.node_at_offset::()?; + + if !is_valid_macrocall(¯o_call, "dbg")? { + return None; + } + + let macro_range = macro_call.syntax().text_range(); + + // If the cursor is inside the macro call, we'll try to maintain the cursor + // position by subtracting the length of dbg!( from the start of the file + // range, otherwise we'll default to using the start of the macro call + 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 = 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().clone(); + + let text = macro_args.text(); + let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')'); + text.slice(without_parens).to_string() + }; + + ctx.add_action(AssistId("remove_dbg"), "remove dbg!()", |edit| { + edit.target(macro_call.syntax().text_range()); + edit.replace(macro_range, macro_content); + edit.set_cursor(cursor_pos); + }); + + ctx.build() +} + +/// 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-macro call, dbg followed by ! + let excl = path.syntax().next_sibling_or_token()?; + + if name_ref.text() != macro_name || excl.kind() != T![!] { + return None; + } + + let node = macro_call.token_tree()?.syntax().clone(); + let first_child = node.first_child_or_token()?; + let last_child = node.last_child_or_token()?; + + match (first_child.kind(), last_child.kind()) { + (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => Some(true), + _ => Some(false), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; + + #[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"); + } + + #[test] + fn remove_dbg_target() { + check_assist_target( + remove_dbg, + " +fn foo(n: usize) { + if let Some(_) = dbg!(n.<|>checked_sub(4)) { + // ... + } +} +", + "dbg!(n.checked_sub(4))", + ); + } +} -- cgit v1.2.3