From fe3170dc344f73126cd4ff2f197d49a8b7f2fe1f Mon Sep 17 00:00:00 2001 From: Aleksei Sidorov Date: Thu, 3 Sep 2020 01:32:18 +0300 Subject: Initial implementation of the #5085 issue --- crates/syntax/src/ast/edit.rs | 66 +++++++++++++++++++++++++++++++++++++++++++ crates/syntax/src/ast/make.rs | 15 ++++++++++ 2 files changed, 81 insertions(+) (limited to 'crates/syntax/src/ast') diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 823475333..1ccb4de6a 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs @@ -459,6 +459,72 @@ impl ast::MatchArmList { } } +impl ast::GenericParamList { + #[must_use] + pub fn append_params(&self, params: impl IntoIterator) -> Self { + let mut res = self.clone(); + params.into_iter().for_each(|it| res = res.append_param(it)); + res + } + + #[must_use] + pub fn append_param(&self, item: ast::GenericParam) -> Self { + let is_multiline = self.syntax().text().contains_char('\n'); + let ws; + let space = if is_multiline { + ws = tokens::WsBuilder::new(&format!( + "\n{} ", + leading_indent(self.syntax()).unwrap_or_default() + )); + ws.ws() + } else { + tokens::single_space() + }; + + let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new(); + to_insert.push(space.into()); + to_insert.push(item.syntax().clone().into()); + to_insert.push(make::token(T![,]).into()); + + macro_rules! after_l_angle { + () => {{ + let anchor = match self.l_angle_token() { + Some(it) => it.into(), + None => return self.clone(), + }; + InsertPosition::After(anchor) + }}; + } + + macro_rules! after_field { + ($anchor:expr) => { + if let Some(comma) = $anchor + .syntax() + .siblings_with_tokens(Direction::Next) + .find(|it| it.kind() == T![,]) + { + InsertPosition::After(comma) + } else { + to_insert.insert(0, make::token(T![,]).into()); + InsertPosition::After($anchor.syntax().clone().into()) + } + }; + }; + + if !is_multiline { + // don't insert comma before angle + to_insert.pop(); + } + + let position = match self.generic_params().last() { + Some(it) => after_field!(it), + None => after_l_angle!(), + }; + + self.insert_children(position, to_insert) + } +} + #[must_use] pub fn remove_attrs_and_docs(node: &N) -> N { N::cast(remove_attrs_and_docs_inner(node.syntax().clone())).unwrap() diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index c2c938ad1..7329e3039 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -294,6 +294,21 @@ pub fn param_list(pats: impl IntoIterator) -> ast::ParamList ast_from_text(&format!("fn f({}) {{ }}", args)) } +pub fn generic_param(name: String, ty: Option) -> ast::GenericParam { + let bound = match ty { + Some(it) => format!(": {}", it), + None => String::new(), + }; + ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound)) +} + +pub fn generic_param_list( + pats: impl IntoIterator, +) -> ast::GenericParamList { + let args = pats.into_iter().join(", "); + ast_from_text(&format!("fn f<{}>() {{ }}", args)) +} + pub fn visibility_pub_crate() -> ast::Visibility { ast_from_text("pub(crate) struct S") } -- cgit v1.2.3