From 8d82d1551ee09faa5d46a58c17c40c2515d3f3b9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 22 Aug 2018 19:02:37 +0300 Subject: Extend add impl --- crates/libeditor/src/code_actions.rs | 68 ++++++++++++++++++++++++--------- crates/libeditor/tests/test.rs | 10 ++--- crates/libsyntax2/src/ast/generated.rs | 25 +++++++++++- crates/libsyntax2/src/grammar.ron | 3 +- crates/server/src/main_loop/handlers.rs | 4 ++ 5 files changed, 85 insertions(+), 25 deletions(-) diff --git a/crates/libeditor/src/code_actions.rs b/crates/libeditor/src/code_actions.rs index 1e20c0f48..6c41923dd 100644 --- a/crates/libeditor/src/code_actions.rs +++ b/crates/libeditor/src/code_actions.rs @@ -1,4 +1,7 @@ -use {TextUnit, EditBuilder, Edit}; +use std::{ + fmt::{self, Write}, +}; + use libsyntax2::{ ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner, ParsedFile}, SyntaxKind::COMMA, @@ -9,6 +12,8 @@ use libsyntax2::{ }, }; +use {TextUnit, EditBuilder, Edit}; + pub struct ActionResult { pub edit: Edit, pub cursor_position: Option, @@ -63,27 +68,31 @@ pub fn add_impl<'a>(file: &'a ParsedFile, offset: TextUnit) -> Option String::new(), - // Some(params) => { - // let mut buf = String::new(); - // } - // }; + let type_params = nominal.type_param_list(); let mut edit = EditBuilder::new(); let start_offset = nominal.syntax().range().end(); - edit.insert( - start_offset, - format!( - "\n\nimpl {} {{\n\n}}", - name.text(), - ) - ); + let mut buf = String::new(); + buf.push_str("\n\nimpl"); + if let Some(type_params) = type_params { + buf.push_display(&type_params.syntax().text()); + } + buf.push_str(" "); + buf.push_str(name.text().as_str()); + if let Some(type_params) = type_params { + comma_list( + &mut buf, "<", ">", + type_params.type_params() + .filter_map(|it| it.name()) + .map(|it| it.text()) + ); + } + buf.push_str(" {\n"); + let offset = start_offset + TextUnit::of_str(&buf); + buf.push_str("\n}"); + edit.insert(start_offset, buf); ActionResult { edit: edit.finish(), - cursor_position: Some( - start_offset + TextUnit::of_str("\n\nimpl {\n") + name.syntax().range().len() - ), + cursor_position: Some(offset), } }) } @@ -104,3 +113,26 @@ pub fn find_node<'a, N: AstNode<'a>>(syntax: SyntaxNodeRef<'a>, offset: TextUnit .next() } +fn comma_list(buf: &mut String, bra: &str, ket: &str, items: impl Iterator) { + buf.push_str(bra); + let mut first = true; + for item in items { + if !first { + first = false; + buf.push_str(", "); + } + write!(buf, "{}", item).unwrap(); + } + buf.push_str(ket); +} + +trait PushDisplay { + fn push_display(&mut self, item: &T); +} + +impl PushDisplay for String { + fn push_display(&mut self, item: &T) { + use std::fmt::Write; + write!(self, "{}", item).unwrap() + } +} diff --git a/crates/libeditor/tests/test.rs b/crates/libeditor/tests/test.rs index 3b0ec78eb..42926ffc8 100644 --- a/crates/libeditor/tests/test.rs +++ b/crates/libeditor/tests/test.rs @@ -151,11 +151,11 @@ fn test_add_impl() { "struct Foo {}\n\nimpl Foo {\n<|>\n}\n", |file, off| add_impl(file, off).map(|f| f()), ); - // check_action( - // "struct Foo {<|>}", - // "struct Foo {}\nimpl Foo {\n<|>\n}", - // |file, off| add_impl(file, off).map(|f| f()), - // ); + check_action( + "struct Foo {<|>}", + "struct Foo {}\n\nimpl Foo {\n<|>\n}", + |file, off| add_impl(file, off).map(|f| f()), + ); } #[test] diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs index 6df1d2311..5edb9faaa 100644 --- a/crates/libsyntax2/src/ast/generated.rs +++ b/crates/libsyntax2/src/ast/generated.rs @@ -580,6 +580,25 @@ impl<'a> ast::TypeParamsOwner<'a> for TypeDef<'a> {} impl<'a> ast::AttrsOwner<'a> for TypeDef<'a> {} impl<'a> TypeDef<'a> {} +// TypeParam +#[derive(Debug, Clone, Copy)] +pub struct TypeParam<'a> { + syntax: SyntaxNodeRef<'a>, +} + +impl<'a> AstNode<'a> for TypeParam<'a> { + fn cast(syntax: SyntaxNodeRef<'a>) -> Option { + match syntax.kind() { + TYPE_PARAM => Some(TypeParam { syntax }), + _ => None, + } + } + fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } +} + +impl<'a> ast::NameOwner<'a> for TypeParam<'a> {} +impl<'a> TypeParam<'a> {} + // TypeParamList #[derive(Debug, Clone, Copy)] pub struct TypeParamList<'a> { @@ -596,7 +615,11 @@ impl<'a> AstNode<'a> for TypeParamList<'a> { fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } } -impl<'a> TypeParamList<'a> {} +impl<'a> TypeParamList<'a> { + pub fn type_params(self) -> impl Iterator> + 'a { + super::children(self) + } +} // TypeRef #[derive(Debug, Clone, Copy)] diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron index e56496be1..daf80dde3 100644 --- a/crates/libsyntax2/src/grammar.ron +++ b/crates/libsyntax2/src/grammar.ron @@ -310,7 +310,8 @@ Grammar( "NameRef": (), "Attr": ( options: [ ["value", "TokenTree"] ] ), "TokenTree": (), - "TypeParamList": (), + "TypeParamList": ( collections: [ ["type_params", "TypeParam" ] ]), + "TypeParam": ( traits: ["NameOwner"]), "WhereClause": (), }, ) diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 9ff821a8b..b47cbc0fc 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs @@ -110,6 +110,7 @@ pub fn handle_code_action( let actions = &[ (ActionId::FlipComma, libeditor::flip_comma(&file, offset).is_some()), (ActionId::AddDerive, libeditor::add_derive(&file, offset).is_some()), + (ActionId::AddImpl, libeditor::add_impl(&file, offset).is_some()), ]; for (id, edit) in actions { @@ -218,6 +219,7 @@ pub fn handle_execute_command( let action_result = match arg.id { ActionId::FlipComma => libeditor::flip_comma(&file, arg.offset).map(|f| f()), ActionId::AddDerive => libeditor::add_derive(&file, arg.offset).map(|f| f()), + ActionId::AddImpl => libeditor::add_impl(&file, arg.offset).map(|f| f()), }.ok_or_else(|| format_err!("command not applicable"))?; let line_index = world.analysis().file_line_index(file_id)?; let mut changes = HashMap::new(); @@ -259,6 +261,7 @@ fn apply_code_action_cmd(id: ActionId, doc: TextDocumentIdentifier, offset: Text enum ActionId { FlipComma, AddDerive, + AddImpl, } impl ActionId { @@ -266,6 +269,7 @@ impl ActionId { match *self { ActionId::FlipComma => "Flip `,`", ActionId::AddDerive => "Add `#[derive]`", + ActionId::AddImpl => "Add impl", } } } -- cgit v1.2.3