diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index e270c5d60d..5f85f20e24 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs @@ -5,7 +5,7 @@ use ra_db::FileRange; use ra_fmt::{leading_indent, reindent}; use ra_syntax::{ algo::{self, find_covering_element, find_node_at_offset}, - AstNode, SourceFile, SyntaxElement, SyntaxNode, SyntaxToken, TextRange, TextUnit, + AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextUnit, TokenAtOffset, }; use ra_text_edit::TextEditBuilder; @@ -111,7 +111,11 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { self.source_file.syntax().token_at_offset(self.frange.range.start()) } - pub(crate) fn node_at_offset(&self) -> Option { + pub(crate) fn find_token_at_offset(&self, kind: SyntaxKind) -> Option { + self.token_at_offset().find(|it| it.kind() == kind) + } + + pub(crate) fn find_node_at_offset(&self) -> Option { find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) } pub(crate) fn covering_element(&self) -> SyntaxElement { diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs index b077acb814..d1e925b71f 100644 --- a/crates/ra_assists/src/assists/add_derive.rs +++ b/crates/ra_assists/src/assists/add_derive.rs @@ -26,7 +26,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn add_derive(mut ctx: AssistCtx) -> Option { - let nominal = ctx.node_at_offset::()?; + let nominal = ctx.find_node_at_offset::()?; let node_start = derive_insertion_offset(&nominal)?; ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { let derive_attr = nominal diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index 2903c17819..ffbdc0b629 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs @@ -22,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn add_explicit_type(mut ctx: AssistCtx) -> Option { - let stmt = ctx.node_at_offset::()?; + let stmt = ctx.find_node_at_offset::()?; let expr = stmt.initializer()?; let pat = stmt.pat()?; // Must be a binding diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs index 142777b067..fd3588d249 100644 --- a/crates/ra_assists/src/assists/add_impl.rs +++ b/crates/ra_assists/src/assists/add_impl.rs @@ -28,7 +28,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn add_impl(mut ctx: AssistCtx) -> Option { - let nominal = ctx.node_at_offset::()?; + let nominal = ctx.find_node_at_offset::()?; let name = nominal.name()?; ctx.add_action(AssistId("add_impl"), "add impl", |edit| { edit.target(nominal.syntax().text_range()); diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 4ee4d47fac..2585f30454 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs @@ -96,7 +96,7 @@ fn add_missing_impl_members_inner( assist_id: &'static str, label: &'static str, ) -> Option { - let impl_node = ctx.node_at_offset::()?; + let impl_node = ctx.find_node_at_offset::()?; let impl_item_list = impl_node.item_list()?; let trait_def = { diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs index 75144cefe2..8d5984a583 100644 --- a/crates/ra_assists/src/assists/apply_demorgan.rs +++ b/crates/ra_assists/src/assists/apply_demorgan.rs @@ -24,7 +24,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn apply_demorgan(mut ctx: AssistCtx) -> Option { - let expr = ctx.node_at_offset::()?; + let expr = ctx.find_node_at_offset::()?; let op = expr.op_kind()?; let op_range = expr.op_token()?.text_range(); let opposite_op = opposite_logic_op(op)?; diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs index 02c58e7c6d..a1c2aaa729 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/assists/auto_import.rs @@ -547,7 +547,7 @@ pub fn auto_import_text_edit( } pub(crate) fn auto_import(mut ctx: AssistCtx) -> Option { - let path: ast::Path = ctx.node_at_offset()?; + let path: ast::Path = ctx.find_node_at_offset()?; // We don't want to mess with use statements if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { return None; diff --git a/crates/ra_assists/src/assists/change_visibility.rs b/crates/ra_assists/src/assists/change_visibility.rs index bed3436778..770ea04fa3 100644 --- a/crates/ra_assists/src/assists/change_visibility.rs +++ b/crates/ra_assists/src/assists/change_visibility.rs @@ -23,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId}; // pub(crate) fn frobnicate() {} // ``` pub(crate) fn change_visibility(ctx: AssistCtx) -> Option { - if let Some(vis) = ctx.node_at_offset::() { + if let Some(vis) = ctx.find_node_at_offset::() { return change_vis(ctx, vis); } add_vis(ctx) diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 48782db422..75822dc65a 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -36,7 +36,7 @@ use crate::{ // } // ``` pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx) -> Option { - let if_expr: ast::IfExpr = ctx.node_at_offset()?; + let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let expr = if_expr.condition()?.expr()?; let then_block = if_expr.then_branch()?.block()?; if if_expr.else_branch().is_some() { diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index b6166f947d..c62c0efbef 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs @@ -32,7 +32,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn fill_match_arms(mut ctx: AssistCtx) -> Option { - let match_expr = ctx.node_at_offset::()?; + let match_expr = ctx.find_node_at_offset::()?; let match_arm_list = match_expr.match_arm_list()?; // We already have some match arms, so we don't provide any assists. diff --git a/crates/ra_assists/src/assists/flip_binexpr.rs b/crates/ra_assists/src/assists/flip_binexpr.rs index 3a1e5cbe1b..9765d5dddc 100644 --- a/crates/ra_assists/src/assists/flip_binexpr.rs +++ b/crates/ra_assists/src/assists/flip_binexpr.rs @@ -19,7 +19,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn flip_binexpr(mut ctx: AssistCtx) -> Option { - let expr = ctx.node_at_offset::()?; + let expr = ctx.find_node_at_offset::()?; let lhs = expr.lhs()?.syntax().clone(); let rhs = expr.rhs()?.syntax().clone(); let op_range = expr.op_token()?.text_range(); diff --git a/crates/ra_assists/src/assists/flip_comma.rs b/crates/ra_assists/src/assists/flip_comma.rs index d06c5a0e18..53ba8011d7 100644 --- a/crates/ra_assists/src/assists/flip_comma.rs +++ b/crates/ra_assists/src/assists/flip_comma.rs @@ -19,7 +19,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn flip_comma(mut ctx: AssistCtx) -> Option { - let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == T![,])?; + let comma = ctx.find_token_at_offset(T![,])?; let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index 1997781dbb..fe8fa2a868 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs @@ -24,7 +24,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx) -> Option { - let let_stmt = ctx.node_at_offset::()?; + let let_stmt = ctx.find_node_at_offset::()?; let bind_pat = match let_stmt.pat()? { ast::Pat::BindPat(pat) => pat, _ => return None, diff --git a/crates/ra_assists/src/assists/merge_match_arms.rs b/crates/ra_assists/src/assists/merge_match_arms.rs index f5ddd71594..b0c4ee78b5 100644 --- a/crates/ra_assists/src/assists/merge_match_arms.rs +++ b/crates/ra_assists/src/assists/merge_match_arms.rs @@ -27,7 +27,7 @@ use ra_syntax::ast::{AstNode, MatchArm}; // } // ``` pub(crate) fn merge_match_arms(mut ctx: AssistCtx) -> Option { - let current_arm = ctx.node_at_offset::()?; + let current_arm = ctx.find_node_at_offset::()?; // We check if the following match arm matches this one. We could, but don't, // compare to the previous match arm as well. diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/assists/move_bounds.rs index f96e19a9f0..edf2897c6c 100644 --- a/crates/ra_assists/src/assists/move_bounds.rs +++ b/crates/ra_assists/src/assists/move_bounds.rs @@ -23,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx) -> Option { - let type_param_list = ctx.node_at_offset::()?; + let type_param_list = ctx.find_node_at_offset::()?; let mut type_params = type_param_list.type_params(); if type_params.all(|p| p.type_bound_list().is_none()) { diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/assists/move_guard.rs index 36c95128d3..e820a73c8d 100644 --- a/crates/ra_assists/src/assists/move_guard.rs +++ b/crates/ra_assists/src/assists/move_guard.rs @@ -33,7 +33,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Option { - let match_arm = ctx.node_at_offset::()?; + let match_arm = ctx.find_node_at_offset::()?; let guard = match_arm.guard()?; let space_before_guard = guard.syntax().prev_sibling_or_token(); @@ -91,7 +91,7 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Op // } // ``` pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx) -> Option { - let match_arm: MatchArm = ctx.node_at_offset::()?; + let match_arm: MatchArm = ctx.find_node_at_offset::()?; let last_match_pat = match_arm.pats().last()?; let arm_body = match_arm.expr()?; diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 2d2e31e513..ea756d1cab 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs @@ -1,17 +1,16 @@ //! FIXME: write short doc here use hir::db::HirDatabase; -use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; +use ra_syntax::{ + SyntaxKind::{RAW_STRING, STRING}, + TextRange, TextUnit, +}; use rustc_lexer; use crate::{Assist, AssistCtx, AssistId}; pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option { - let literal = ctx.node_at_offset::()?; - if literal.token().kind() != ra_syntax::SyntaxKind::STRING { - return None; - } - let token = literal.token(); + let token = ctx.find_token_at_offset(STRING)?; let text = token.text().as_str(); let usual_string_range = find_usual_string_range(text)?; let start_of_inside = usual_string_range.start().to_usize() + 1; @@ -30,16 +29,61 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option) -> Option { + let token = ctx.find_token_at_offset(RAW_STRING)?; + let text = token.text().as_str(); + let usual_string_range = find_usual_string_range(text)?; + ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { + edit.target(token.text_range()); + // parse inside string to escape `"` + let start_of_inside = usual_string_range.start().to_usize() + 1; + let end_of_inside = usual_string_range.end().to_usize(); + let inside_str = &text[start_of_inside..end_of_inside]; + let escaped = inside_str.escape_default().to_string(); + edit.replace(token.text_range(), format!("\"{}\"", escaped)); + }); + ctx.build() +} + +pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { + let token = ctx.find_token_at_offset(RAW_STRING)?; + ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { + edit.target(token.text_range()); + edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#"); + edit.insert(token.text_range().end(), "#"); + }); + ctx.build() +} + +pub(crate) fn remove_hash(mut ctx: AssistCtx) -> Option { + let token = ctx.find_token_at_offset(RAW_STRING)?; + let text = token.text().as_str(); + if text.starts_with("r\"") { + // no hash to remove + return None; + } + ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { + edit.target(token.text_range()); + let result = &text[2..text.len() - 1]; + let result = if result.starts_with("\"") { + // no more hash, escape + let internal_str = &result[1..result.len() - 1]; + format!("\"{}\"", internal_str.escape_default().to_string()) + } else { + result.to_owned() + }; + edit.replace(token.text_range(), format!("r{}", result)); }); ctx.build() } @@ -63,65 +107,6 @@ fn find_usual_string_range(s: &str) -> Option { )) } -pub(crate) fn make_usual_string(mut ctx: AssistCtx) -> Option { - let literal = ctx.node_at_offset::()?; - if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { - return None; - } - let token = literal.token(); - let text = token.text().as_str(); - let usual_string_range = find_usual_string_range(text)?; - ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { - edit.target(literal.syntax().text_range()); - // parse inside string to escape `"` - let start_of_inside = usual_string_range.start().to_usize() + 1; - let end_of_inside = usual_string_range.end().to_usize(); - let inside_str = &text[start_of_inside..end_of_inside]; - let escaped = inside_str.escape_default().to_string(); - edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped)); - }); - ctx.build() -} - -pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { - let literal = ctx.node_at_offset::()?; - if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { - return None; - } - ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { - edit.target(literal.syntax().text_range()); - edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#"); - edit.insert(literal.syntax().text_range().end(), "#"); - }); - ctx.build() -} - -pub(crate) fn remove_hash(mut ctx: AssistCtx) -> Option { - let literal = ctx.node_at_offset::()?; - if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { - return None; - } - let token = literal.token(); - let text = token.text().as_str(); - if text.starts_with("r\"") { - // no hash to remove - return None; - } - ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { - edit.target(literal.syntax().text_range()); - let result = &text[2..text.len() - 1]; - let result = if result.starts_with("\"") { - // no more hash, escape - let internal_str = &result[1..result.len() - 1]; - format!("\"{}\"", internal_str.escape_default().to_string()) - } else { - result.to_owned() - }; - edit.replace(literal.syntax().text_range(), format!("r{}", result)); - }); - ctx.build() -} - #[cfg(test)] mod test { use super::*; @@ -158,6 +143,23 @@ string"#; ) } + #[test] + fn make_raw_string_works_inside_macros() { + check_assist( + make_raw_string, + r#" + fn f() { + format!(<|>"x = {}", 92) + } + "#, + r##" + fn f() { + format!(<|>r#"x = {}"#, 92) + } + "##, + ) + } + #[test] fn make_raw_string_hashes_inside_works() { check_assist( diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/assists/remove_dbg.rs index 1a7e2b3050..ac2c43e1ad 100644 --- a/crates/ra_assists/src/assists/remove_dbg.rs +++ b/crates/ra_assists/src/assists/remove_dbg.rs @@ -8,7 +8,7 @@ use ra_syntax::{ }; pub(crate) fn remove_dbg(mut ctx: AssistCtx) -> Option { - let macro_call = ctx.node_at_offset::()?; + let macro_call = ctx.find_node_at_offset::()?; if !is_valid_macrocall(¯o_call, "dbg")? { return None; diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/assists/replace_if_let_with_match.rs index 749ff338aa..da276e47bf 100644 --- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/assists/replace_if_let_with_match.rs @@ -8,7 +8,7 @@ use ra_syntax::{ast, AstNode}; use crate::{Assist, AssistCtx, AssistId}; pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx) -> Option { - let if_expr: ast::IfExpr = ctx.node_at_offset()?; + let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let cond = if_expr.condition()?; let pat = cond.pat()?; let expr = cond.expr()?; diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/assists/split_import.rs index fe3e64af50..09bde1b72c 100644 --- a/crates/ra_assists/src/assists/split_import.rs +++ b/crates/ra_assists/src/assists/split_import.rs @@ -8,7 +8,7 @@ use ra_syntax::{ast, AstNode, TextUnit, T}; use crate::{Assist, AssistCtx, AssistId}; pub(crate) fn split_import(mut ctx: AssistCtx) -> Option { - let colon_colon = ctx.token_at_offset().find(|leaf| leaf.kind() == T![::])?; + let colon_colon = ctx.find_token_at_offset(T![::])?; let path = ast::Path::cast(colon_colon.parent())?; let top_path = successors(Some(path), |it| it.parent_path()).last()?;