mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-04 05:35:55 +00:00 
			
		
		
		
	Migrate wrap_unwrap_cfg_attr assist to use SyntaxEditor
				
					
				
			Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
This commit is contained in:
		
							parent
							
								
									aa16885e62
								
							
						
					
					
						commit
						0b7ad9cd0f
					
				
					 2 changed files with 85 additions and 42 deletions
				
			
		| 
						 | 
					@ -2,8 +2,7 @@ use ide_db::source_change::SourceChangeBuilder;
 | 
				
			||||||
use itertools::Itertools;
 | 
					use itertools::Itertools;
 | 
				
			||||||
use syntax::{
 | 
					use syntax::{
 | 
				
			||||||
    NodeOrToken, SyntaxToken, T, TextRange, algo,
 | 
					    NodeOrToken, SyntaxToken, T, TextRange, algo,
 | 
				
			||||||
    ast::{self, AstNode, make},
 | 
					    ast::{self, AstNode, make, syntax_factory::SyntaxFactory},
 | 
				
			||||||
    ted::{self, Position},
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{AssistContext, AssistId, Assists};
 | 
					use crate::{AssistContext, AssistId, Assists};
 | 
				
			||||||
| 
						 | 
					@ -173,40 +172,45 @@ fn wrap_derive(
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let handle_source_change = |edit: &mut SourceChangeBuilder| {
 | 
					    let handle_source_change = |edit: &mut SourceChangeBuilder| {
 | 
				
			||||||
        let new_derive = make::attr_outer(make::meta_token_tree(
 | 
					        let make = SyntaxFactory::with_mappings();
 | 
				
			||||||
            make::ext::ident_path("derive"),
 | 
					        let mut editor = edit.make_editor(attr.syntax());
 | 
				
			||||||
            make::token_tree(T!['('], new_derive),
 | 
					        let new_derive = make.attr_outer(
 | 
				
			||||||
        ))
 | 
					            make.meta_token_tree(make.ident_path("derive"), make.token_tree(T!['('], new_derive)),
 | 
				
			||||||
        .clone_for_update();
 | 
					        );
 | 
				
			||||||
        let meta = make::meta_token_tree(
 | 
					        let meta = make.meta_token_tree(
 | 
				
			||||||
            make::ext::ident_path("cfg_attr"),
 | 
					            make.ident_path("cfg_attr"),
 | 
				
			||||||
            make::token_tree(
 | 
					            make.token_tree(
 | 
				
			||||||
                T!['('],
 | 
					                T!['('],
 | 
				
			||||||
                vec![
 | 
					                vec![
 | 
				
			||||||
                    NodeOrToken::Token(make::token(T![,])),
 | 
					                    NodeOrToken::Token(make.token(T![,])),
 | 
				
			||||||
                    NodeOrToken::Token(make::tokens::whitespace(" ")),
 | 
					                    NodeOrToken::Token(make.whitespace(" ")),
 | 
				
			||||||
                    NodeOrToken::Token(make::tokens::ident("derive")),
 | 
					                    NodeOrToken::Token(make.ident("derive")),
 | 
				
			||||||
                    NodeOrToken::Node(make::token_tree(T!['('], cfg_derive_tokens)),
 | 
					                    NodeOrToken::Node(make.token_tree(T!['('], cfg_derive_tokens)),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        // Remove the derive attribute
 | 
					 | 
				
			||||||
        let edit_attr = edit.make_syntax_mut(attr.syntax().clone());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ted::replace(edit_attr, new_derive.syntax().clone());
 | 
					        let cfg_attr = make.attr_outer(meta);
 | 
				
			||||||
        let cfg_attr = make::attr_outer(meta).clone_for_update();
 | 
					        editor.replace_with_many(
 | 
				
			||||||
 | 
					            attr.syntax(),
 | 
				
			||||||
        ted::insert_all_raw(
 | 
					            vec![
 | 
				
			||||||
            Position::after(new_derive.syntax().clone()),
 | 
					                new_derive.syntax().clone().into(),
 | 
				
			||||||
            vec![make::tokens::whitespace("\n").into(), cfg_attr.syntax().clone().into()],
 | 
					                make.whitespace("\n").into(),
 | 
				
			||||||
 | 
					                cfg_attr.syntax().clone().into(),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(snippet_cap) = ctx.config.snippet_cap {
 | 
					        if let Some(snippet_cap) = ctx.config.snippet_cap {
 | 
				
			||||||
            if let Some(first_meta) =
 | 
					            if let Some(first_meta) =
 | 
				
			||||||
                cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
 | 
					                cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                edit.add_tabstop_after_token(snippet_cap, first_meta)
 | 
					                let tabstop = edit.make_tabstop_after(snippet_cap);
 | 
				
			||||||
 | 
					                editor.add_annotation(first_meta, tabstop);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        editor.add_mappings(make.finish_with_mappings());
 | 
				
			||||||
 | 
					        edit.add_file_edits(ctx.vfs_file_id(), editor);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    acc.add(
 | 
					    acc.add(
 | 
				
			||||||
| 
						 | 
					@ -221,10 +225,10 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) ->
 | 
				
			||||||
    let range = attr.syntax().text_range();
 | 
					    let range = attr.syntax().text_range();
 | 
				
			||||||
    let path = attr.path()?;
 | 
					    let path = attr.path()?;
 | 
				
			||||||
    let handle_source_change = |edit: &mut SourceChangeBuilder| {
 | 
					    let handle_source_change = |edit: &mut SourceChangeBuilder| {
 | 
				
			||||||
        let mut raw_tokens = vec![
 | 
					        let make = SyntaxFactory::with_mappings();
 | 
				
			||||||
            NodeOrToken::Token(make::token(T![,])),
 | 
					        let mut editor = edit.make_editor(attr.syntax());
 | 
				
			||||||
            NodeOrToken::Token(make::tokens::whitespace(" ")),
 | 
					        let mut raw_tokens =
 | 
				
			||||||
        ];
 | 
					            vec![NodeOrToken::Token(make.token(T![,])), NodeOrToken::Token(make.whitespace(" "))];
 | 
				
			||||||
        path.syntax().descendants_with_tokens().for_each(|it| {
 | 
					        path.syntax().descendants_with_tokens().for_each(|it| {
 | 
				
			||||||
            if let NodeOrToken::Token(token) = it {
 | 
					            if let NodeOrToken::Token(token) = it {
 | 
				
			||||||
                raw_tokens.push(NodeOrToken::Token(token));
 | 
					                raw_tokens.push(NodeOrToken::Token(token));
 | 
				
			||||||
| 
						 | 
					@ -232,9 +236,9 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) ->
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        if let Some(meta) = attr.meta() {
 | 
					        if let Some(meta) = attr.meta() {
 | 
				
			||||||
            if let (Some(eq), Some(expr)) = (meta.eq_token(), meta.expr()) {
 | 
					            if let (Some(eq), Some(expr)) = (meta.eq_token(), meta.expr()) {
 | 
				
			||||||
                raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" ")));
 | 
					                raw_tokens.push(NodeOrToken::Token(make.whitespace(" ")));
 | 
				
			||||||
                raw_tokens.push(NodeOrToken::Token(eq));
 | 
					                raw_tokens.push(NodeOrToken::Token(eq));
 | 
				
			||||||
                raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" ")));
 | 
					                raw_tokens.push(NodeOrToken::Token(make.whitespace(" ")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                expr.syntax().descendants_with_tokens().for_each(|it| {
 | 
					                expr.syntax().descendants_with_tokens().for_each(|it| {
 | 
				
			||||||
                    if let NodeOrToken::Token(token) = it {
 | 
					                    if let NodeOrToken::Token(token) = it {
 | 
				
			||||||
| 
						 | 
					@ -245,26 +249,24 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) ->
 | 
				
			||||||
                raw_tokens.extend(tt.token_trees_and_tokens());
 | 
					                raw_tokens.extend(tt.token_trees_and_tokens());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let meta = make::meta_token_tree(
 | 
					        let meta =
 | 
				
			||||||
            make::ext::ident_path("cfg_attr"),
 | 
					            make.meta_token_tree(make.ident_path("cfg_attr"), make.token_tree(T!['('], raw_tokens));
 | 
				
			||||||
            make::token_tree(T!['('], raw_tokens),
 | 
					        let cfg_attr =
 | 
				
			||||||
        );
 | 
					            if attr.excl_token().is_some() { make.attr_inner(meta) } else { make.attr_outer(meta) };
 | 
				
			||||||
        let cfg_attr = if attr.excl_token().is_some() {
 | 
					
 | 
				
			||||||
            make::attr_inner(meta)
 | 
					        editor.replace(attr.syntax(), cfg_attr.syntax());
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            make::attr_outer(meta)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        .clone_for_update();
 | 
					 | 
				
			||||||
        let attr_syntax = edit.make_syntax_mut(attr.syntax().clone());
 | 
					 | 
				
			||||||
        ted::replace(attr_syntax, cfg_attr.syntax());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(snippet_cap) = ctx.config.snippet_cap {
 | 
					        if let Some(snippet_cap) = ctx.config.snippet_cap {
 | 
				
			||||||
            if let Some(first_meta) =
 | 
					            if let Some(first_meta) =
 | 
				
			||||||
                cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
 | 
					                cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                edit.add_tabstop_after_token(snippet_cap, first_meta)
 | 
					                let tabstop = edit.make_tabstop_after(snippet_cap);
 | 
				
			||||||
 | 
					                editor.add_annotation(first_meta, tabstop);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        editor.add_mappings(make.finish_with_mappings());
 | 
				
			||||||
 | 
					        edit.add_file_edits(ctx.vfs_file_id(), editor);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    acc.add(
 | 
					    acc.add(
 | 
				
			||||||
        AssistId::refactor("wrap_unwrap_cfg_attr"),
 | 
					        AssistId::refactor("wrap_unwrap_cfg_attr"),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1212,6 +1212,43 @@ impl SyntaxFactory {
 | 
				
			||||||
        ast
 | 
					        ast
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn attr_outer(&self, meta: ast::Meta) -> ast::Attr {
 | 
				
			||||||
 | 
					        let ast = make::attr_outer(meta.clone()).clone_for_update();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(mut mapping) = self.mappings() {
 | 
				
			||||||
 | 
					            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
 | 
				
			||||||
 | 
					            builder.map_node(meta.syntax().clone(), ast.meta().unwrap().syntax().clone());
 | 
				
			||||||
 | 
					            builder.finish(&mut mapping);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ast
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn attr_inner(&self, meta: ast::Meta) -> ast::Attr {
 | 
				
			||||||
 | 
					        let ast = make::attr_inner(meta.clone()).clone_for_update();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(mut mapping) = self.mappings() {
 | 
				
			||||||
 | 
					            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
 | 
				
			||||||
 | 
					            builder.map_node(meta.syntax().clone(), ast.meta().unwrap().syntax().clone());
 | 
				
			||||||
 | 
					            builder.finish(&mut mapping);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ast
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn meta_token_tree(&self, path: ast::Path, tt: ast::TokenTree) -> ast::Meta {
 | 
				
			||||||
 | 
					        let ast = make::meta_token_tree(path.clone(), tt.clone()).clone_for_update();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(mut mapping) = self.mappings() {
 | 
				
			||||||
 | 
					            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
 | 
				
			||||||
 | 
					            builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone());
 | 
				
			||||||
 | 
					            builder.map_node(tt.syntax().clone(), ast.token_tree().unwrap().syntax().clone());
 | 
				
			||||||
 | 
					            builder.finish(&mut mapping);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ast
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn token_tree(
 | 
					    pub fn token_tree(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        delimiter: SyntaxKind,
 | 
					        delimiter: SyntaxKind,
 | 
				
			||||||
| 
						 | 
					@ -1242,6 +1279,10 @@ impl SyntaxFactory {
 | 
				
			||||||
    pub fn whitespace(&self, text: &str) -> SyntaxToken {
 | 
					    pub fn whitespace(&self, text: &str) -> SyntaxToken {
 | 
				
			||||||
        make::tokens::whitespace(text)
 | 
					        make::tokens::whitespace(text)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn ident(&self, text: &str) -> SyntaxToken {
 | 
				
			||||||
 | 
					        make::tokens::ident(text)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// `ext` constructors
 | 
					// `ext` constructors
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue