diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index 1da85fcecc..100e1feb1d 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs @@ -4,71 +4,79 @@ use itertools::Itertools; use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; use ra_ide_db::RootDatabase; -use ra_syntax::ast::{Name, Pat}; use ra_syntax::{ - ast, - ast::{Path, RecordField, RecordLit, RecordPat}, - AstNode, + algo, ast, + ast::{Name, Path, RecordLit, RecordPat}, + AstNode, SyntaxKind, SyntaxNode, }; use crate::{ assist_ctx::{Assist, AssistCtx}, AssistId, }; +use ra_syntax::ast::{Expr, NameRef}; pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option { - reorder_struct(ctx.clone()).or_else(|| reorder_struct_pat(ctx)) + reorder::(ctx.clone()).or_else(|| reorder::(ctx)) } -fn reorder_struct(ctx: AssistCtx) -> Option { - let record: RecordLit = ctx.find_node_at_offset()?; - reorder(ctx, &record, &record.path()?, field_name) -} +fn reorder(ctx: AssistCtx) -> Option { + let record = ctx.find_node_at_offset::()?; + let path = record.syntax().children().find_map(Path::cast)?; -fn field_name(r: &RecordField) -> String { - r.name_ref() - .map(|name| name.syntax().text().to_string()) - .or_else(|| r.expr().map(|e| e.syntax().text().to_string())) - .unwrap_or_default() -} + let ranks = compute_fields_ranks(&path, &ctx)?; -fn reorder_struct_pat(ctx: AssistCtx) -> Option { - let record: RecordPat = ctx.find_node_at_offset()?; - reorder(ctx, &record, &record.path()?, field_pat_name) -} - -fn field_pat_name(field: &Pat) -> String { - field.syntax().children().find_map(Name::cast).map(|n| n.to_string()).unwrap_or_default() -} - -fn reorder( - ctx: AssistCtx, - record: &R, - path: &Path, - field_name: fn(&F) -> String, -) -> Option { - let ranks = compute_fields_ranks(path, &ctx)?; - let fields: Vec = get_fields(record); - let sorted_fields: Vec = - sort_by_rank(&fields, |f| *ranks.get(&field_name(f)).unwrap_or(&usize::max_value())); + let fields = get_fields(&record.syntax()); + let sorted_fields = sorted_by_rank(&fields, |node| { + *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value()) + }); if sorted_fields == fields { return None; } ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| { - for (old, new) in fields.into_iter().zip(sorted_fields) { - edit.replace_ast(old, new); + for (old, new) in fields.iter().zip(&sorted_fields) { + algo::diff(old, new).into_text_edit(edit.text_edit_builder()); } edit.target(record.syntax().text_range()) }) } -fn get_fields(record: &R) -> Vec { - record.syntax().children().flat_map(|n1| n1.children()).filter_map(|n3| F::cast(n3)).collect() +fn get_fields_kind(node: &SyntaxNode) -> Vec { + use SyntaxKind::*; + match node.kind() { + RECORD_LIT => vec![RECORD_FIELD], + RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT], + _ => vec![], + } } -fn sort_by_rank(fields: &[F], get_rank: impl FnMut(&F) -> usize) -> Vec { +fn get_field_name(node: &SyntaxNode) -> String { + use SyntaxKind::*; + match node.kind() { + RECORD_FIELD => { + if let Some(name) = node.children().find_map(NameRef::cast) { + return name.to_string(); + } + node.children().find_map(Expr::cast).map(|expr| expr.to_string()).unwrap_or_default() + } + BIND_PAT | RECORD_FIELD_PAT => { + node.children().find_map(Name::cast).map(|n| n.to_string()).unwrap_or_default() + } + _ => String::new(), + } +} + +fn get_fields(record: &SyntaxNode) -> Vec { + let kinds = get_fields_kind(record); + record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect() +} + +fn sorted_by_rank( + fields: &[SyntaxNode], + get_rank: impl Fn(&SyntaxNode) -> usize, +) -> Vec { fields.iter().cloned().sorted_by_key(get_rank).collect() } diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 80492b733b..e1b08d48fb 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -691,8 +691,6 @@ impl ExprCollector<'_> { } // FIXME: implement ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, - // FIXME: implement - ast::Pat::RecordFieldPat(_) => Pat::Missing, }; let ptr = AstPtr::new(&pat); self.alloc_pat(pattern, Either::Left(ptr)) diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index 79b2256227..20f6630467 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs @@ -3256,7 +3256,6 @@ pub enum Pat { RangePat(RangePat), LiteralPat(LiteralPat), MacroPat(MacroPat), - RecordFieldPat(RecordFieldPat), } impl From for Pat { fn from(node: OrPat) -> Pat { Pat::OrPat(node) } @@ -3303,15 +3302,12 @@ impl From for Pat { impl From for Pat { fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) } } -impl From for Pat { - fn from(node: RecordFieldPat) -> Pat { Pat::RecordFieldPat(node) } -} impl AstNode for Pat { fn can_cast(kind: SyntaxKind) -> bool { match kind { OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT - | LITERAL_PAT | MACRO_PAT | RECORD_FIELD_PAT => true, + | LITERAL_PAT | MACRO_PAT => true, _ => false, } } @@ -3332,7 +3328,6 @@ impl AstNode for Pat { RANGE_PAT => Pat::RangePat(RangePat { syntax }), LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }), MACRO_PAT => Pat::MacroPat(MacroPat { syntax }), - RECORD_FIELD_PAT => Pat::RecordFieldPat(RecordFieldPat { syntax }), _ => return None, }; Some(res) @@ -3354,7 +3349,6 @@ impl AstNode for Pat { Pat::RangePat(it) => &it.syntax, Pat::LiteralPat(it) => &it.syntax, Pat::MacroPat(it) => &it.syntax, - Pat::RecordFieldPat(it) => &it.syntax, } } } diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index eb5c3abf75..bb97b13fe5 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs @@ -741,7 +741,6 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { RangePat, LiteralPat, MacroPat, - RecordFieldPat, } enum RecordInnerPat {