aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/handlers/reorder_fields.rs86
-rw-r--r--crates/ra_hir_def/src/body/lower.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated/nodes.rs8
-rw-r--r--xtask/src/ast_src.rs1
4 files changed, 48 insertions, 49 deletions
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs
index 1da85fcec..100e1feb1 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;
4 4
5use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; 5use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
6use ra_ide_db::RootDatabase; 6use ra_ide_db::RootDatabase;
7use ra_syntax::ast::{Name, Pat};
8use ra_syntax::{ 7use ra_syntax::{
9 ast, 8 algo, ast,
10 ast::{Path, RecordField, RecordLit, RecordPat}, 9 ast::{Name, Path, RecordLit, RecordPat},
11 AstNode, 10 AstNode, SyntaxKind, SyntaxNode,
12}; 11};
13 12
14use crate::{ 13use crate::{
15 assist_ctx::{Assist, AssistCtx}, 14 assist_ctx::{Assist, AssistCtx},
16 AssistId, 15 AssistId,
17}; 16};
17use ra_syntax::ast::{Expr, NameRef};
18 18
19pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> { 19pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> {
20 reorder_struct(ctx.clone()).or_else(|| reorder_struct_pat(ctx)) 20 reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx))
21} 21}
22 22
23fn reorder_struct(ctx: AssistCtx) -> Option<Assist> { 23fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> {
24 let record: RecordLit = ctx.find_node_at_offset()?; 24 let record = ctx.find_node_at_offset::<R>()?;
25 reorder(ctx, &record, &record.path()?, field_name) 25 let path = record.syntax().children().find_map(Path::cast)?;
26}
27
28fn field_name(r: &RecordField) -> String {
29 r.name_ref()
30 .map(|name| name.syntax().text().to_string())
31 .or_else(|| r.expr().map(|e| e.syntax().text().to_string()))
32 .unwrap_or_default()
33}
34
35fn reorder_struct_pat(ctx: AssistCtx) -> Option<Assist> {
36 let record: RecordPat = ctx.find_node_at_offset()?;
37 reorder(ctx, &record, &record.path()?, field_pat_name)
38}
39 26
40fn field_pat_name(field: &Pat) -> String { 27 let ranks = compute_fields_ranks(&path, &ctx)?;
41 field.syntax().children().find_map(Name::cast).map(|n| n.to_string()).unwrap_or_default()
42}
43 28
44fn reorder<R: AstNode, F: AstNode + Eq + Clone>( 29 let fields = get_fields(&record.syntax());
45 ctx: AssistCtx, 30 let sorted_fields = sorted_by_rank(&fields, |node| {
46 record: &R, 31 *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())
47 path: &Path, 32 });
48 field_name: fn(&F) -> String,
49) -> Option<Assist> {
50 let ranks = compute_fields_ranks(path, &ctx)?;
51 let fields: Vec<F> = get_fields(record);
52 let sorted_fields: Vec<F> =
53 sort_by_rank(&fields, |f| *ranks.get(&field_name(f)).unwrap_or(&usize::max_value()));
54 33
55 if sorted_fields == fields { 34 if sorted_fields == fields {
56 return None; 35 return None;
57 } 36 }
58 37
59 ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| { 38 ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| {
60 for (old, new) in fields.into_iter().zip(sorted_fields) { 39 for (old, new) in fields.iter().zip(&sorted_fields) {
61 edit.replace_ast(old, new); 40 algo::diff(old, new).into_text_edit(edit.text_edit_builder());
62 } 41 }
63 edit.target(record.syntax().text_range()) 42 edit.target(record.syntax().text_range())
64 }) 43 })
65} 44}
66 45
67fn get_fields<R: AstNode, F: AstNode>(record: &R) -> Vec<F> { 46fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
68 record.syntax().children().flat_map(|n1| n1.children()).filter_map(|n3| F::cast(n3)).collect() 47 use SyntaxKind::*;
48 match node.kind() {
49 RECORD_LIT => vec![RECORD_FIELD],
50 RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
51 _ => vec![],
52 }
53}
54
55fn get_field_name(node: &SyntaxNode) -> String {
56 use SyntaxKind::*;
57 match node.kind() {
58 RECORD_FIELD => {
59 if let Some(name) = node.children().find_map(NameRef::cast) {
60 return name.to_string();
61 }
62 node.children().find_map(Expr::cast).map(|expr| expr.to_string()).unwrap_or_default()
63 }
64 BIND_PAT | RECORD_FIELD_PAT => {
65 node.children().find_map(Name::cast).map(|n| n.to_string()).unwrap_or_default()
66 }
67 _ => String::new(),
68 }
69}
70
71fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> {
72 let kinds = get_fields_kind(record);
73 record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect()
69} 74}
70 75
71fn sort_by_rank<F: AstNode + Clone>(fields: &[F], get_rank: impl FnMut(&F) -> usize) -> Vec<F> { 76fn sorted_by_rank(
77 fields: &[SyntaxNode],
78 get_rank: impl Fn(&SyntaxNode) -> usize,
79) -> Vec<SyntaxNode> {
72 fields.iter().cloned().sorted_by_key(get_rank).collect() 80 fields.iter().cloned().sorted_by_key(get_rank).collect()
73} 81}
74 82
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 80492b733..e1b08d48f 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<'_> {
691 } 691 }
692 // FIXME: implement 692 // FIXME: implement
693 ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, 693 ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
694 // FIXME: implement
695 ast::Pat::RecordFieldPat(_) => Pat::Missing,
696 }; 694 };
697 let ptr = AstPtr::new(&pat); 695 let ptr = AstPtr::new(&pat);
698 self.alloc_pat(pattern, Either::Left(ptr)) 696 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 79b225622..20f663046 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 {
3256 RangePat(RangePat), 3256 RangePat(RangePat),
3257 LiteralPat(LiteralPat), 3257 LiteralPat(LiteralPat),
3258 MacroPat(MacroPat), 3258 MacroPat(MacroPat),
3259 RecordFieldPat(RecordFieldPat),
3260} 3259}
3261impl From<OrPat> for Pat { 3260impl From<OrPat> for Pat {
3262 fn from(node: OrPat) -> Pat { Pat::OrPat(node) } 3261 fn from(node: OrPat) -> Pat { Pat::OrPat(node) }
@@ -3303,15 +3302,12 @@ impl From<LiteralPat> for Pat {
3303impl From<MacroPat> for Pat { 3302impl From<MacroPat> for Pat {
3304 fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) } 3303 fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) }
3305} 3304}
3306impl From<RecordFieldPat> for Pat {
3307 fn from(node: RecordFieldPat) -> Pat { Pat::RecordFieldPat(node) }
3308}
3309impl AstNode for Pat { 3305impl AstNode for Pat {
3310 fn can_cast(kind: SyntaxKind) -> bool { 3306 fn can_cast(kind: SyntaxKind) -> bool {
3311 match kind { 3307 match kind {
3312 OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT 3308 OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT
3313 | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT 3309 | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT
3314 | LITERAL_PAT | MACRO_PAT | RECORD_FIELD_PAT => true, 3310 | LITERAL_PAT | MACRO_PAT => true,
3315 _ => false, 3311 _ => false,
3316 } 3312 }
3317 } 3313 }
@@ -3332,7 +3328,6 @@ impl AstNode for Pat {
3332 RANGE_PAT => Pat::RangePat(RangePat { syntax }), 3328 RANGE_PAT => Pat::RangePat(RangePat { syntax }),
3333 LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }), 3329 LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }),
3334 MACRO_PAT => Pat::MacroPat(MacroPat { syntax }), 3330 MACRO_PAT => Pat::MacroPat(MacroPat { syntax }),
3335 RECORD_FIELD_PAT => Pat::RecordFieldPat(RecordFieldPat { syntax }),
3336 _ => return None, 3331 _ => return None,
3337 }; 3332 };
3338 Some(res) 3333 Some(res)
@@ -3354,7 +3349,6 @@ impl AstNode for Pat {
3354 Pat::RangePat(it) => &it.syntax, 3349 Pat::RangePat(it) => &it.syntax,
3355 Pat::LiteralPat(it) => &it.syntax, 3350 Pat::LiteralPat(it) => &it.syntax,
3356 Pat::MacroPat(it) => &it.syntax, 3351 Pat::MacroPat(it) => &it.syntax,
3357 Pat::RecordFieldPat(it) => &it.syntax,
3358 } 3352 }
3359 } 3353 }
3360} 3354}
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index eb5c3abf7..bb97b13fe 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -741,7 +741,6 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
741 RangePat, 741 RangePat,
742 LiteralPat, 742 LiteralPat,
743 MacroPat, 743 MacroPat,
744 RecordFieldPat,
745 } 744 }
746 745
747 enum RecordInnerPat { 746 enum RecordInnerPat {