From a4635a199bc446bd103aa5821e57dc19b8a15751 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 3 Jan 2019 18:59:17 +0300 Subject: more enterprisey assists API --- crates/ra_analysis/src/imp.rs | 16 +-- crates/ra_editor/src/assists.rs | 155 ++++++++++++++++++++- crates/ra_editor/src/assists/add_derive.rs | 61 ++++---- crates/ra_editor/src/assists/add_impl.rs | 36 ++--- crates/ra_editor/src/assists/change_visibility.rs | 84 +++++------ crates/ra_editor/src/assists/flip_comma.rs | 36 ++--- crates/ra_editor/src/assists/introduce_variable.rs | 84 +++++------ crates/ra_editor/src/diagnostics.rs | 6 +- crates/ra_editor/src/typing.rs | 8 +- crates/ra_syntax/src/yellow/syntax_text.rs | 6 + crates/ra_text_edit/src/text_edit.rs | 5 +- 11 files changed, 287 insertions(+), 210 deletions(-) diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 136e7f7dc..771dad475 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -333,19 +333,9 @@ impl db::RootDatabase { pub(crate) fn assists(&self, frange: FileRange) -> Vec { let file = self.source_file(frange.file_id); - let offset = frange.range.start(); - let actions = vec![ - assists::flip_comma(&file, offset).map(|f| f()), - assists::add_derive(&file, offset).map(|f| f()), - assists::add_impl(&file, offset).map(|f| f()), - assists::change_visibility(&file, offset).map(|f| f()), - assists::introduce_variable(&file, frange.range).map(|f| f()), - ]; - actions + assists::assists(&file, frange.range) .into_iter() - .filter_map(|local_edit| { - Some(SourceChange::from_local_edit(frange.file_id, local_edit?)) - }) + .map(|local_edit| SourceChange::from_local_edit(frange.file_id, local_edit)) .collect() } @@ -440,7 +430,7 @@ impl db::RootDatabase { .map(|(file_id, text_range)| SourceFileEdit { file_id: *file_id, edit: { - let mut builder = ra_text_edit::TextEditBuilder::new(); + let mut builder = ra_text_edit::TextEditBuilder::default(); builder.replace(*text_range, new_name.into()); builder.finish() }, diff --git a/crates/ra_editor/src/assists.rs b/crates/ra_editor/src/assists.rs index b6e6dd628..cc40ee4c8 100644 --- a/crates/ra_editor/src/assists.rs +++ b/crates/ra_editor/src/assists.rs @@ -9,8 +9,13 @@ mod add_impl; mod introduce_variable; mod change_visibility; -use ra_text_edit::TextEdit; -use ra_syntax::{Direction, SyntaxNodeRef, TextUnit}; +use ra_text_edit::{TextEdit, TextEditBuilder}; +use ra_syntax::{ + Direction, SyntaxNodeRef, TextUnit, TextRange,SourceFileNode, AstNode, + algo::{find_leaf_at_offset, find_covering_node, LeafAtOffset}, +}; + +use crate::find_node_at_offset; pub use self::{ flip_comma::flip_comma, @@ -20,6 +25,21 @@ pub use self::{ change_visibility::change_visibility, }; +/// Return all the assists applicable at the given position. +pub fn assists(file: &SourceFileNode, range: TextRange) -> Vec { + let ctx = AssistCtx::new(file, range); + [ + flip_comma, + add_derive, + add_impl, + introduce_variable, + change_visibility, + ] + .iter() + .filter_map(|&assist| ctx.clone().apply(assist)) + .collect() +} + #[derive(Debug)] pub struct LocalEdit { pub label: String, @@ -32,3 +52,134 @@ fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option { + source_file: &'a SourceFileNode, + range: TextRange, + should_compute_edit: bool, +} + +#[derive(Debug)] +pub enum Assist { + Applicable, + Edit(LocalEdit), +} + +#[derive(Default)] +struct AssistBuilder { + edit: TextEditBuilder, + cursor_position: Option, +} + +impl<'a> AssistCtx<'a> { + pub fn new(source_file: &'a SourceFileNode, range: TextRange) -> AssistCtx { + AssistCtx { + source_file, + range, + should_compute_edit: false, + } + } + + pub fn apply(mut self, assist: fn(AssistCtx) -> Option) -> Option { + self.should_compute_edit = true; + match assist(self) { + None => None, + Some(Assist::Edit(e)) => Some(e), + Some(Assist::Applicable) => unreachable!(), + } + } + + pub fn check(mut self, assist: fn(AssistCtx) -> Option) -> bool { + self.should_compute_edit = false; + match assist(self) { + None => false, + Some(Assist::Edit(_)) => unreachable!(), + Some(Assist::Applicable) => true, + } + } + + fn build(self, label: impl Into, f: impl FnOnce(&mut AssistBuilder)) -> Option { + if !self.should_compute_edit { + return Some(Assist::Applicable); + } + let mut edit = AssistBuilder::default(); + f(&mut edit); + Some(Assist::Edit(LocalEdit { + label: label.into(), + edit: edit.edit.finish(), + cursor_position: edit.cursor_position, + })) + } + + pub(crate) fn leaf_at_offset(&self) -> LeafAtOffset> { + find_leaf_at_offset(self.source_file.syntax(), self.range.start()) + } + pub(crate) fn node_at_offset>(&self) -> Option { + find_node_at_offset(self.source_file.syntax(), self.range.start()) + } + pub(crate) fn covering_node(&self) -> SyntaxNodeRef<'a> { + find_covering_node(self.source_file.syntax(), self.range) + } +} + +impl AssistBuilder { + fn replace(&mut self, range: TextRange, replace_with: impl Into) { + self.edit.replace(range, replace_with.into()) + } + #[allow(unused)] + fn delete(&mut self, range: TextRange) { + self.edit.delete(range) + } + fn insert(&mut self, offset: TextUnit, text: impl Into) { + self.edit.insert(offset, text.into()) + } + fn set_cursor(&mut self, offset: TextUnit) { + self.cursor_position = Some(offset) + } +} + +#[cfg(test)] +fn check_assist(assist: fn(AssistCtx) -> Option, before: &str, after: &str) { + crate::test_utils::check_action(before, after, |file, off| { + let range = TextRange::offset_len(off, 0.into()); + AssistCtx::new(file, range).apply(assist) + }) +} + +#[cfg(test)] +fn check_assist_range(assist: fn(AssistCtx) -> Option, before: &str, after: &str) { + crate::test_utils::check_action_range(before, after, |file, range| { + AssistCtx::new(file, range).apply(assist) + }) +} diff --git a/crates/ra_editor/src/assists/add_derive.rs b/crates/ra_editor/src/assists/add_derive.rs index 33d9d2c31..1e2cd4f30 100644 --- a/crates/ra_editor/src/assists/add_derive.rs +++ b/crates/ra_editor/src/assists/add_derive.rs @@ -1,85 +1,73 @@ -use ra_text_edit::TextEditBuilder; use ra_syntax::{ ast::{self, AstNode, AttrsOwner}, - SourceFileNode, SyntaxKind::{WHITESPACE, COMMENT}, TextUnit, }; -use crate::{ - find_node_at_offset, - assists::LocalEdit, -}; +use crate::assists::{AssistCtx, Assist}; -pub fn add_derive<'a>( - file: &'a SourceFileNode, - offset: TextUnit, -) -> Option LocalEdit + 'a> { - let nominal = find_node_at_offset::(file.syntax(), offset)?; +pub fn add_derive(ctx: AssistCtx) -> Option { + let nominal = ctx.node_at_offset::()?; let node_start = derive_insertion_offset(nominal)?; - return Some(move || { + ctx.build("add `#[derive]`", |edit| { let derive_attr = nominal .attrs() .filter_map(|x| x.as_call()) .filter(|(name, _arg)| name == "derive") .map(|(_name, arg)| arg) .next(); - let mut edit = TextEditBuilder::new(); let offset = match derive_attr { None => { - edit.insert(node_start, "#[derive()]\n".to_string()); + edit.insert(node_start, "#[derive()]\n"); node_start + TextUnit::of_str("#[derive(") } Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'), }; - LocalEdit { - label: "add `#[derive]`".to_string(), - edit: edit.finish(), - cursor_position: Some(offset), - } - }); + edit.set_cursor(offset) + }) +} - // Insert `derive` after doc comments. - fn derive_insertion_offset(nominal: ast::NominalDef) -> Option { - let non_ws_child = nominal - .syntax() - .children() - .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; - Some(non_ws_child.range().start()) - } +// Insert `derive` after doc comments. +fn derive_insertion_offset(nominal: ast::NominalDef) -> Option { + let non_ws_child = nominal + .syntax() + .children() + .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; + Some(non_ws_child.range().start()) } #[cfg(test)] mod tests { use super::*; - use crate::test_utils::check_action; + use crate::assists::check_assist; #[test] fn add_derive_new() { - check_action( + check_assist( + add_derive, "struct Foo { a: i32, <|>}", "#[derive(<|>)]\nstruct Foo { a: i32, }", - |file, off| add_derive(file, off).map(|f| f()), ); - check_action( + check_assist( + add_derive, "struct Foo { <|> a: i32, }", "#[derive(<|>)]\nstruct Foo { a: i32, }", - |file, off| add_derive(file, off).map(|f| f()), ); } #[test] fn add_derive_existing() { - check_action( + check_assist( + add_derive, "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", "#[derive(Clone<|>)]\nstruct Foo { a: i32, }", - |file, off| add_derive(file, off).map(|f| f()), ); } #[test] fn add_derive_new_with_doc_comment() { - check_action( + check_assist( + add_derive, " /// `Foo` is a pretty important struct. /// It does stuff. @@ -91,7 +79,6 @@ struct Foo { a: i32<|>, } #[derive(<|>)] struct Foo { a: i32, } ", - |file, off| add_derive(file, off).map(|f| f()), ); } } diff --git a/crates/ra_editor/src/assists/add_impl.rs b/crates/ra_editor/src/assists/add_impl.rs index 50e00688e..9353e2717 100644 --- a/crates/ra_editor/src/assists/add_impl.rs +++ b/crates/ra_editor/src/assists/add_impl.rs @@ -1,23 +1,16 @@ use join_to_string::join; -use ra_text_edit::TextEditBuilder; use ra_syntax::{ ast::{self, AstNode, NameOwner, TypeParamsOwner}, - SourceFileNode, TextUnit, }; -use crate::{find_node_at_offset, assists::LocalEdit}; +use crate::assists::{AssistCtx, Assist}; -pub fn add_impl<'a>( - file: &'a SourceFileNode, - offset: TextUnit, -) -> Option LocalEdit + 'a> { - let nominal = find_node_at_offset::(file.syntax(), offset)?; +pub fn add_impl(ctx: AssistCtx) -> Option { + let nominal = ctx.node_at_offset::()?; let name = nominal.name()?; - - Some(move || { + ctx.build("add impl", |edit| { let type_params = nominal.type_param_list(); - let mut edit = TextEditBuilder::new(); let start_offset = nominal.syntax().range().end(); let mut buf = String::new(); buf.push_str("\n\nimpl"); @@ -40,38 +33,33 @@ pub fn add_impl<'a>( .to_buf(&mut buf); } buf.push_str(" {\n"); - let offset = start_offset + TextUnit::of_str(&buf); + edit.set_cursor(start_offset + TextUnit::of_str(&buf)); buf.push_str("\n}"); edit.insert(start_offset, buf); - LocalEdit { - label: "add impl".to_string(), - edit: edit.finish(), - cursor_position: Some(offset), - } }) } #[cfg(test)] mod tests { use super::*; - use crate::test_utils::check_action; + use crate::assists::check_assist; #[test] fn test_add_impl() { - check_action( + check_assist( + add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n<|>\n}\n", - |file, off| add_impl(file, off).map(|f| f()), ); - check_action( + check_assist( + add_impl, "struct Foo {<|>}", "struct Foo {}\n\nimpl Foo {\n<|>\n}", - |file, off| add_impl(file, off).map(|f| f()), ); - check_action( + check_assist( + add_impl, "struct Foo<'a, T: Foo<'a>> {<|>}", "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n<|>\n}", - |file, off| add_impl(file, off).map(|f| f()), ); } diff --git a/crates/ra_editor/src/assists/change_visibility.rs b/crates/ra_editor/src/assists/change_visibility.rs index 98c218f32..379e88d3c 100644 --- a/crates/ra_editor/src/assists/change_visibility.rs +++ b/crates/ra_editor/src/assists/change_visibility.rs @@ -1,90 +1,74 @@ -use ra_text_edit::TextEditBuilder; use ra_syntax::{ - SourceFileNode, - algo::find_leaf_at_offset, SyntaxKind::{VISIBILITY, FN_KW, MOD_KW, STRUCT_KW, ENUM_KW, TRAIT_KW, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF}, - TextUnit, }; -use crate::assists::LocalEdit; +use crate::assists::{AssistCtx, Assist}; -pub fn change_visibility<'a>( - file: &'a SourceFileNode, - offset: TextUnit, -) -> Option LocalEdit + 'a> { - let syntax = file.syntax(); - - let keyword = find_leaf_at_offset(syntax, offset).find(|leaf| match leaf.kind() { +pub fn change_visibility(ctx: AssistCtx) -> Option { + let keyword = ctx.leaf_at_offset().find(|leaf| match leaf.kind() { FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true, _ => false, })?; let parent = keyword.parent()?; let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; - let node_start = parent.range().start(); - Some(move || { - let mut edit = TextEditBuilder::new(); - - if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) - || parent.children().any(|child| child.kind() == VISIBILITY) - { - return LocalEdit { - label: "make pub crate".to_string(), - edit: edit.finish(), - cursor_position: Some(offset), - }; - } + // Parent is not a definition, can't add visibility + if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { + return None; + } + // Already have visibility, do nothing + if parent.children().any(|child| child.kind() == VISIBILITY) { + return None; + } - edit.insert(node_start, "pub(crate) ".to_string()); - LocalEdit { - label: "make pub crate".to_string(), - edit: edit.finish(), - cursor_position: Some(node_start), - } + let node_start = parent.range().start(); + ctx.build("make pub crate", |edit| { + edit.insert(node_start, "pub(crate) "); + edit.set_cursor(node_start); }) } #[cfg(test)] mod tests { use super::*; - use crate::test_utils::check_action; + use crate::assists::check_assist; #[test] fn test_change_visibility() { - check_action( + check_assist( + change_visibility, "<|>fn foo() {}", "<|>pub(crate) fn foo() {}", - |file, off| change_visibility(file, off).map(|f| f()), ); - check_action( + check_assist( + change_visibility, "f<|>n foo() {}", "<|>pub(crate) fn foo() {}", - |file, off| change_visibility(file, off).map(|f| f()), ); - check_action( + check_assist( + change_visibility, "<|>struct Foo {}", "<|>pub(crate) struct Foo {}", - |file, off| change_visibility(file, off).map(|f| f()), ); - check_action("<|>mod foo {}", "<|>pub(crate) mod foo {}", |file, off| { - change_visibility(file, off).map(|f| f()) - }); - check_action( + check_assist( + change_visibility, + "<|>mod foo {}", + "<|>pub(crate) mod foo {}", + ); + check_assist( + change_visibility, "<|>trait Foo {}", "<|>pub(crate) trait Foo {}", - |file, off| change_visibility(file, off).map(|f| f()), ); - check_action("m<|>od {}", "<|>pub(crate) mod {}", |file, off| { - change_visibility(file, off).map(|f| f()) - }); - check_action( + check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}"); + check_assist( + change_visibility, "pub(crate) f<|>n foo() {}", "pub(crate) f<|>n foo() {}", - |file, off| change_visibility(file, off).map(|f| f()), ); - check_action( + check_assist( + change_visibility, "unsafe f<|>n foo() {}", "<|>pub(crate) unsafe fn foo() {}", - |file, off| change_visibility(file, off).map(|f| f()), ); } } diff --git a/crates/ra_editor/src/assists/flip_comma.rs b/crates/ra_editor/src/assists/flip_comma.rs index d8727db0d..a343413cc 100644 --- a/crates/ra_editor/src/assists/flip_comma.rs +++ b/crates/ra_editor/src/assists/flip_comma.rs @@ -1,45 +1,31 @@ -use ra_text_edit::TextEditBuilder; use ra_syntax::{ - algo::find_leaf_at_offset, - Direction, SourceFileNode, + Direction, SyntaxKind::COMMA, - TextUnit, }; -use crate::assists::{LocalEdit, non_trivia_sibling}; +use crate::assists::{non_trivia_sibling, AssistCtx, Assist}; -pub fn flip_comma<'a>( - file: &'a SourceFileNode, - offset: TextUnit, -) -> Option LocalEdit + 'a> { - let syntax = file.syntax(); - - let comma = find_leaf_at_offset(syntax, offset).find(|leaf| leaf.kind() == COMMA)?; +pub fn flip_comma(ctx: AssistCtx) -> Option { + let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?; let prev = non_trivia_sibling(comma, Direction::Prev)?; let next = non_trivia_sibling(comma, Direction::Next)?; - Some(move || { - let mut edit = TextEditBuilder::new(); - edit.replace(prev.range(), next.text().to_string()); - edit.replace(next.range(), prev.text().to_string()); - LocalEdit { - label: "flip comma".to_string(), - edit: edit.finish(), - cursor_position: None, - } + ctx.build("flip comma", |edit| { + edit.replace(prev.range(), next.text()); + edit.replace(next.range(), prev.text()); }) } #[cfg(test)] mod tests { use super::*; - use crate::test_utils::check_action; + use crate::assists::check_assist; #[test] - fn test_swap_comma() { - check_action( + fn flip_comma_works_for_function_parameters() { + check_assist( + flip_comma, "fn foo(x: i32,<|> y: Result<(), ()>) {}", "fn foo(y: Result<(), ()>,<|> x: i32) {}", - |file, off| flip_comma(file, off).map(|f| f()), ) } } diff --git a/crates/ra_editor/src/assists/introduce_variable.rs b/crates/ra_editor/src/assists/introduce_variable.rs index 17ab521fa..782861023 100644 --- a/crates/ra_editor/src/assists/introduce_variable.rs +++ b/crates/ra_editor/src/assists/introduce_variable.rs @@ -1,19 +1,13 @@ -use ra_text_edit::TextEditBuilder; use ra_syntax::{ - algo::{find_covering_node}, ast::{self, AstNode}, - SourceFileNode, - SyntaxKind::{WHITESPACE}, - SyntaxNodeRef, TextRange, TextUnit, + SyntaxKind::WHITESPACE, + SyntaxNodeRef, TextUnit, }; -use crate::assists::LocalEdit; +use crate::assists::{AssistCtx, Assist}; -pub fn introduce_variable<'a>( - file: &'a SourceFileNode, - range: TextRange, -) -> Option LocalEdit + 'a> { - let node = find_covering_node(file.syntax(), range); +pub fn introduce_variable<'a>(ctx: AssistCtx) -> Option { + let node = ctx.covering_node(); let expr = node.ancestors().filter_map(ast::Expr::cast).next()?; let anchor_stmt = anchor_stmt(expr)?; @@ -21,9 +15,8 @@ pub fn introduce_variable<'a>( if indent.kind() != WHITESPACE { return None; } - return Some(move || { + ctx.build("introduce variable", move |edit| { let mut buf = String::new(); - let mut edit = TextEditBuilder::new(); buf.push_str("let var_name = "); expr.syntax().text().push_to(&mut buf); @@ -40,43 +33,39 @@ pub fn introduce_variable<'a>( edit.replace(expr.syntax().range(), "var_name".to_string()); edit.insert(anchor_stmt.range().start(), buf); } - let cursor_position = anchor_stmt.range().start() + TextUnit::of_str("let "); - LocalEdit { - label: "introduce variable".to_string(), - edit: edit.finish(), - cursor_position: Some(cursor_position), - } - }); + edit.set_cursor(anchor_stmt.range().start() + TextUnit::of_str("let ")); + }) +} - /// Statement or last in the block expression, which will follow - /// the freshly introduced var. - fn anchor_stmt(expr: ast::Expr) -> Option { - expr.syntax().ancestors().find(|&node| { - if ast::Stmt::cast(node).is_some() { +/// Statement or last in the block expression, which will follow +/// the freshly introduced var. +fn anchor_stmt(expr: ast::Expr) -> Option { + expr.syntax().ancestors().find(|&node| { + if ast::Stmt::cast(node).is_some() { + return true; + } + if let Some(expr) = node + .parent() + .and_then(ast::Block::cast) + .and_then(|it| it.expr()) + { + if expr.syntax() == node { return true; } - if let Some(expr) = node - .parent() - .and_then(ast::Block::cast) - .and_then(|it| it.expr()) - { - if expr.syntax() == node { - return true; - } - } - false - }) - } + } + false + }) } #[cfg(test)] mod tests { use super::*; - use crate::test_utils::check_action_range; + use crate::assists::check_assist_range; #[test] fn test_introduce_var_simple() { - check_action_range( + check_assist_range( + introduce_variable, " fn foo() { foo(<|>1 + 1<|>); @@ -86,13 +75,13 @@ fn foo() { let <|>var_name = 1 + 1; foo(var_name); }", - |file, range| introduce_variable(file, range).map(|f| f()), ); } #[test] fn test_introduce_var_expr_stmt() { - check_action_range( + check_assist_range( + introduce_variable, " fn foo() { <|>1 + 1<|>; @@ -101,13 +90,13 @@ fn foo() { fn foo() { let <|>var_name = 1 + 1; }", - |file, range| introduce_variable(file, range).map(|f| f()), ); } #[test] fn test_introduce_var_part_of_expr_stmt() { - check_action_range( + check_assist_range( + introduce_variable, " fn foo() { <|>1<|> + 1; @@ -117,13 +106,13 @@ fn foo() { let <|>var_name = 1; var_name + 1; }", - |file, range| introduce_variable(file, range).map(|f| f()), ); } #[test] fn test_introduce_var_last_expr() { - check_action_range( + check_assist_range( + introduce_variable, " fn foo() { bar(<|>1 + 1<|>) @@ -133,13 +122,13 @@ fn foo() { let <|>var_name = 1 + 1; bar(var_name) }", - |file, range| introduce_variable(file, range).map(|f| f()), ); } #[test] fn test_introduce_var_last_full_expr() { - check_action_range( + check_assist_range( + introduce_variable, " fn foo() { <|>bar(1 + 1)<|> @@ -149,7 +138,6 @@ fn foo() { let <|>var_name = bar(1 + 1); var_name }", - |file, range| introduce_variable(file, range).map(|f| f()), ); } diff --git a/crates/ra_editor/src/diagnostics.rs b/crates/ra_editor/src/diagnostics.rs index 1b336cfe2..199b0e502 100644 --- a/crates/ra_editor/src/diagnostics.rs +++ b/crates/ra_editor/src/diagnostics.rs @@ -57,7 +57,7 @@ fn check_unnecessary_braces_in_use_statement( text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(single_use_tree) .unwrap_or_else(|| { let to_replace = single_use_tree.syntax().text().to_string(); - let mut edit_builder = TextEditBuilder::new(); + let mut edit_builder = TextEditBuilder::default(); edit_builder.delete(range); edit_builder.insert(range.start(), to_replace); edit_builder.finish() @@ -93,7 +93,7 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( let start = use_tree_list_node.prev_sibling()?.range().start(); let end = use_tree_list_node.range().end(); let range = TextRange::from_to(start, end); - let mut edit_builder = TextEditBuilder::new(); + let mut edit_builder = TextEditBuilder::default(); edit_builder.delete(range); return Some(edit_builder.finish()); } @@ -111,7 +111,7 @@ fn check_struct_shorthand_initialization( let field_name = name_ref.syntax().text().to_string(); let field_expr = expr.syntax().text().to_string(); if field_name == field_expr { - let mut edit_builder = TextEditBuilder::new(); + let mut edit_builder = TextEditBuilder::default(); edit_builder.delete(named_field.syntax().range()); edit_builder.insert(named_field.syntax().range().start(), field_name); let edit = edit_builder.finish(); diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs index 21d068a7b..dd3d0f260 100644 --- a/crates/ra_editor/src/typing.rs +++ b/crates/ra_editor/src/typing.rs @@ -21,7 +21,7 @@ pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit { None => { return LocalEdit { label: "join lines".to_string(), - edit: TextEditBuilder::new().finish(), + edit: TextEditBuilder::default().finish(), cursor_position: None, }; } @@ -33,7 +33,7 @@ pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit { }; let node = find_covering_node(file.syntax(), range); - let mut edit = TextEditBuilder::new(); + let mut edit = TextEditBuilder::default(); for node in node.descendants() { let text = match node.leaf_text() { Some(text) => text, @@ -76,7 +76,7 @@ pub fn on_enter(file: &SourceFileNode, offset: TextUnit) -> Option { let indent = node_indent(file, comment.syntax())?; let inserted = format!("\n{}{} ", indent, prefix); let cursor_position = offset + TextUnit::of_str(&inserted); - let mut edit = TextEditBuilder::new(); + let mut edit = TextEditBuilder::default(); edit.insert(offset, inserted); Some(LocalEdit { label: "on enter".to_string(), @@ -127,7 +127,7 @@ pub fn on_eq_typed(file: &SourceFileNode, offset: TextUnit) -> Option return None; } let offset = let_stmt.syntax().range().end(); - let mut edit = TextEditBuilder::new(); + let mut edit = TextEditBuilder::default(); edit.insert(offset, ";".to_string()); Some(LocalEdit { label: "add semicolon".to_string(), diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/yellow/syntax_text.rs index 46bde9a08..783dca214 100644 --- a/crates/ra_syntax/src/yellow/syntax_text.rs +++ b/crates/ra_syntax/src/yellow/syntax_text.rs @@ -119,3 +119,9 @@ impl SyntaxTextSlice for ops::Range { TextRange::from_to(self.start, self.end).restrict(range) } } + +impl From> for String { + fn from(text: SyntaxText) -> String { + text.to_string() + } +} diff --git a/crates/ra_text_edit/src/text_edit.rs b/crates/ra_text_edit/src/text_edit.rs index 0881f3e1c..a288a990d 100644 --- a/crates/ra_text_edit/src/text_edit.rs +++ b/crates/ra_text_edit/src/text_edit.rs @@ -7,15 +7,12 @@ pub struct TextEdit { atoms: Vec, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct TextEditBuilder { atoms: Vec, } impl TextEditBuilder { - pub fn new() -> TextEditBuilder { - TextEditBuilder { atoms: Vec::new() } - } pub fn replace(&mut self, range: TextRange, replace_with: String) { self.atoms.push(AtomTextEdit::replace(range, replace_with)) } -- cgit v1.2.3