Skip to content

Commit 7663a21

Browse files
committed
[WIP] init ra-fmt2 for issue rust-lang#1665
1 parent ed098fd commit 7663a21

File tree

10 files changed

+181
-95
lines changed

10 files changed

+181
-95
lines changed

crates/ra_fmt2/src/dsl.rs

+2-12
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::pattern::{Pattern, PatternSet};
2+
use crate::trav_util::{next_non_whitespace_sibling, prev_non_whitespace_sibling};
23
use ra_syntax::{SyntaxElement, SyntaxKind::*};
3-
use std::iter::successors;
44

55
/// `SpacingRule` describes whitespace requirements between `SyntaxElement` Note
66
/// that it doesn't handle indentation (first whitespace on a line), there's
77
/// `IndentRule` for that!
8-
#[derive(Debug)]
8+
#[derive(Debug, Clone)]
99
pub(crate) struct SpacingRule {
1010
/// An element to which this spacing rule applies
1111
pub(crate) pattern: Pattern,
@@ -196,13 +196,3 @@ impl<'a> SpacingRuleBuilder<'a> {
196196
self.dsl
197197
}
198198
}
199-
200-
pub(crate) fn prev_non_whitespace_sibling(element: &SyntaxElement) -> Option<SyntaxElement> {
201-
successors(element.prev_sibling_or_token(), |it| it.prev_sibling_or_token())
202-
.find(|it| it.kind() != WHITESPACE)
203-
}
204-
205-
pub(crate) fn next_non_whitespace_sibling(element: &SyntaxElement) -> Option<SyntaxElement> {
206-
successors(element.next_sibling_or_token(), |it| it.next_sibling_or_token())
207-
.find(|it| it.kind() != WHITESPACE)
208-
}

crates/ra_fmt2/src/edit_tree.rs

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use crate::dsl::{SpacingDsl, SpacingRule, SpaceLoc, SpaceValue};
2+
use crate::pattern::{Pattern, PatternSet};
3+
use crate::rules::spacing;
4+
use crate::trav_util::{walk, walk_nodes, walk_tokens};
5+
6+
use ra_syntax::{
7+
NodeOrToken, SmolStr, SyntaxElement,
8+
SyntaxKind::{self, *},
9+
SyntaxNode, SyntaxToken, TextRange, TextUnit, WalkEvent, T,
10+
};
11+
12+
use std::collections::{HashMap, HashSet};
13+
14+
// TODO make more like intellij's fmt model
15+
// Model holds immutable tree and mutable intermediate model to produce diff
16+
// the model will probably have to create its own tree to add the extra
17+
// info to each token/node:
18+
//
19+
// [1,2,3];
20+
// can be Brace token, ident, comma all of which knows their own rules and apply
21+
// them accordingly to produce [1, 2, 3]; ???
22+
23+
#[derive(Debug)]
24+
// this will probably be an enum that holds a struct for space/indent/ect
25+
struct AtomEdit {
26+
space_loc: SpaceLoc,
27+
val: SpaceValue,
28+
start: TextUnit,
29+
}
30+
31+
impl AtomEdit {}
32+
33+
#[derive(Debug)]
34+
pub(crate) struct SynBlock {
35+
//indent: some enum?
36+
kind: SyntaxKind,
37+
node: SyntaxNode,
38+
tokens: Vec<SyntaxToken>,
39+
range: TextRange,
40+
edits: Vec<AtomEdit>,
41+
ws_rules: Vec<SpacingRule>,
42+
}
43+
44+
#[derive(Debug)]
45+
pub(crate) struct EditTree {
46+
blocks: Vec<SynBlock>,
47+
flat_edit: Vec<SyntaxElement>,
48+
edits: Vec<AtomEdit>,
49+
}
50+
51+
// each block will have knowledge of spacing and indent,
52+
//
53+
impl SynBlock {
54+
pub(crate) fn build_block(
55+
node: SyntaxNode,
56+
// this must change when indent comes back to generic?
57+
patt: &PatternSet<&'_ SpacingRule>,
58+
) -> Self {
59+
// are there node rules?
60+
let mut ws_rules = patt.matching(NodeOrToken::Node(node.clone()))
61+
.cloned()
62+
.collect::<Vec<_>>();
63+
64+
let mut token_rules = walk_tokens(&node)
65+
.flat_map::<Vec<_>, _>(|t| patt.matching(NodeOrToken::Token(t)).collect())
66+
// TODO get rid of clone?
67+
.cloned()
68+
.collect::<Vec<SpacingRule>>();
69+
70+
ws_rules.append(&mut token_rules);
71+
//println!("{:?}", ws_rules);
72+
Self {
73+
kind: node.kind(),
74+
node: node.clone(),
75+
tokens: walk_tokens(&node).collect(),
76+
range: node.text_range(),
77+
edits: vec![],
78+
ws_rules,
79+
}
80+
}
81+
}
82+
83+
impl Default for EditTree {
84+
fn default() -> Self {
85+
Self {
86+
blocks: vec![],
87+
flat_edit: vec![],
88+
edits: vec![],
89+
}
90+
}
91+
}
92+
93+
impl EditTree {
94+
pub(crate) fn from_root(root: &SyntaxNode, patt: PatternSet<&'_ SpacingRule>) -> Self {
95+
Self::default().build_tree(root, patt)
96+
}
97+
98+
pub(crate) fn build_tree(
99+
mut self,
100+
root: &SyntaxNode,
101+
patt: PatternSet<&'_ SpacingRule>,
102+
) -> Self {
103+
self.blocks = walk_nodes(root).map(|n| SynBlock::build_block(n, &patt)).collect();
104+
self
105+
}
106+
107+
pub(crate) fn to_string(&self) -> String {
108+
let ordered = walk_tokens(&self.blocks[0].node)
109+
.map(|t| t.to_string())
110+
.collect::<String>();
111+
//let set: HashSet<SyntaxElement> = HashSet::from_iter(ordered);
112+
println!("{:?}", ordered);
113+
ordered
114+
}
115+
}

crates/ra_fmt2/src/engine.rs

-10
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,6 @@ impl SpacingRule {
7676
}
7777
}
7878

79-
fn walk(node: &SyntaxNode) -> impl Iterator<Item = SyntaxElement> {
80-
node.preorder_with_tokens().filter_map(|event| {
81-
if let WalkEvent::Enter(ele) = event {
82-
Some(ele)
83-
} else {
84-
None
85-
}
86-
})
87-
}
88-
8979
pub fn format_pass(space_rules: &SpacingDsl, root: &SyntaxNode) {
9080
let mut fmt_root = FmtModel::new(root.clone());
9181

crates/ra_fmt2/src/fmt_diff.rs

-31
This file was deleted.

crates/ra_fmt2/src/fmt_model.rs

+4-15
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,14 @@
1+
use crate::edit_tree::EditTree;
2+
13
use ra_syntax::{
24
NodeOrToken, SmolStr,
35
SyntaxElement, TextUnit,
4-
SyntaxKind::*,
6+
SyntaxKind::{self, *},
57
SyntaxNode, SyntaxToken, T,
68
WalkEvent, TextRange,
79
};
8-
use std::collections::HashMap;
9-
10-
// TODO make more like intellij's fmt model
11-
// Model holds immutable tree and mutable intermediate model to produce diff
12-
// the model will probably have to create its own tree to add the extra
13-
// info to each token/node:
14-
//
15-
// [1,2,3];
16-
// can be Brace token, ident, comma all of which knows their own rules and apply
17-
// them accordingly to produce [1, 2, 3]; ???
1810

19-
#[derive(Debug)]
20-
struct EditTree {
21-
22-
}
11+
use std::collections::HashMap;
2312

2413
#[derive(Debug)]
2514
pub(super) struct FmtModel {

crates/ra_fmt2/src/lib.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
//! This crate provides some utilities for indenting rust code.
2-
//!
1+
//! More forgiving rust fmt ra-fmt2
2+
// TODO remove when done
3+
#![allow(dead_code)]
4+
#![allow(unused_imports)]
5+
36
mod scratch;
7+
mod edit_tree;
48
mod rules;
59
mod dsl;
610
// mod engine;
711
mod pattern;
8-
mod fmt_model;
9-
// mod trav_util;
10-
mod fmt_diff;
12+
// mod fmt_model;
13+
mod trav_util;

crates/ra_fmt2/src/pattern.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ impl Pattern {
3535
pub(crate) fn with_parent(self, parent: Pattern) -> Pattern {
3636
let Pattern { kinds, pred } = self;
3737
Pattern::new(kinds, move |element| {
38-
(pred)(element) && element.parent().map(|it| parent.matches(&it.into())) == Some(true)
38+
(pred)(element) && element.parent()
39+
.map(|it| {println!("{:?}", it); it})
40+
.map(|it| parent.matches(&it.into())) == Some(true)
3941
})
4042
}
4143

@@ -103,6 +105,7 @@ from_array!(0, 1, 2, 3, 4, 5, 6, 7, 8);
103105
///
104106
/// This is generic over `P: AsRef<Pattern>`, so it works with any type which
105107
/// contains a pattern.
108+
#[derive(Debug)]
106109
pub(crate) struct PatternSet<P> {
107110
by_kind: HashMap<SyntaxKind, Vec<P>>,
108111
unconstrained: Vec<P>,
@@ -133,7 +136,7 @@ impl<'a, P: AsRef<Pattern>> PatternSet<&'a P> {
133136
self.by_kind
134137
.get(&element.kind())
135138
.into_iter()
136-
//.inspect(|n| println!("{:?}", n)) //TODO LOOK AT PATTERN AND KIND
139+
//.inspect(|n| println!("{:?}", n)) // TODO LOOK AT PATTERN AND KIND
137140
.flat_map(|vec| vec.iter())
138141
.chain(self.unconstrained.iter())
139142
.map(|&p| p)

crates/ra_fmt2/src/rules.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
1+
use crate::dsl::SpacingDsl;
12
use itertools::Itertools;
23
use ra_syntax::{
34
ast::{self, AstNode, AstToken},
45
SmolStr, SyntaxKind,
56
SyntaxKind::*,
67
SyntaxNode, SyntaxToken, T,
78
};
8-
use crate::dsl::SpacingDsl;
99

1010
pub(crate) fn spacing() -> SpacingDsl {
1111
let mut space_dsl = SpacingDsl::default();
1212

1313
space_dsl
1414
.test("let x = [1,2,3];", "let x = [1, 2, 3];")
15-
.inside(ARRAY_EXPR).after(T![,]).single_space();
16-
// more rules to come
17-
15+
.inside(ARRAY_EXPR).after(T![,]).single_space()
16+
17+
.test("struct Test{x:usize}", "struct Test { x:usize }")
18+
.inside(NAMED_FIELD_DEF_LIST).around(T!['{']).single_space()
19+
.inside(NAMED_FIELD_DEF_LIST).before(T!['}']).single_space_or_optional_newline()
20+
21+
.test("pub(crate)struct", "pub(crate) struct")
22+
.inside(STRUCT_DEF).before(STRUCT_KW).single_space()
23+
24+
;
25+
// more rules to come
26+
1827
space_dsl
1928
}
2029

crates/ra_fmt2/src/scratch.rs

+17-11
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
use crate::edit_tree::EditTree;
2+
use crate::pattern::PatternSet;
13
/// experiment purposes
24
///
35
// use crate::engine;
4-
use crate::dsl::SpacingDsl;
6+
// use crate::dsl::SpacingDsl;
57
use crate::rules::spacing;
8+
use crate::trav_util::{walk, walk_nodes, walk_tokens};
69

710
use ra_syntax::{
811
ast::{self, AstNode, AstToken},
@@ -13,24 +16,27 @@ use ra_syntax::{
1316

1417
#[test]
1518
fn try_it() {
16-
let rs_file = "pub(crate)struct Test {
17-
x: String,
18-
}
19-
";
19+
let rs_file = "pub(crate)struct Test {x: String}";
2020

2121
let p = SourceFile::parse(&rs_file);
2222
let syn_tree = p.syntax_node();
23-
//let rules = spacing();
24-
25-
println!("{:#?}", p);
23+
// fix this, this call is not great do some other way
24+
let space = spacing();
25+
let ws_rules = PatternSet::new(space.rules.iter());
26+
// println!("{:#?}", p);
2627
syn_tree
2728
.preorder_with_tokens()
2829
.filter_map(|ev| match ev {
2930
ra_syntax::WalkEvent::Enter(el) => Some(el).filter(|t| t.kind() != WHITESPACE),
3031
ra_syntax::WalkEvent::Leave(_) => None,
3132
})
3233
.for_each(|n| println!("{:?}", n));
33-
34-
35-
//engine::format_pass(&rules, &syn_tree)
34+
println!();
35+
walk_nodes(&syn_tree).for_each(|n| {
36+
println!("Node {:?}", n);
37+
walk_tokens(&n).for_each(|t| println!(" TOK {:?}", t));
38+
});
39+
let fmt = EditTree::from_root(&syn_tree, ws_rules);
40+
println!("{:#?}", fmt);
41+
fmt.to_string();
3642
}

crates/ra_fmt2/src/trav_util.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
use ra_syntax::{
2-
SyntaxElement, SyntaxKind::*, NodeOrToken,
3-
SyntaxNode, SyntaxToken, WalkEvent,
4-
};
1+
use ra_syntax::{NodeOrToken, SyntaxElement, SyntaxKind::*, SyntaxNode, SyntaxToken, WalkEvent};
2+
use std::iter::successors;
53

64
pub(crate) fn walk(node: &SyntaxNode) -> impl Iterator<Item = SyntaxElement> {
75
node.preorder_with_tokens().filter_map(|event| match event {
@@ -21,7 +19,21 @@ pub(crate) fn walk_tokens(node: &SyntaxNode) -> impl Iterator<Item = SyntaxToken
2119
_ => None,
2220
})
2321
}
24-
22+
pub(crate) fn walk_nodes(node: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
23+
walk(node).filter_map(|element| match element {
24+
NodeOrToken::Node(node) => Some(node),
25+
_ => None,
26+
})
27+
}
2528
pub(crate) fn has_newline(node: &SyntaxNode) -> bool {
2629
walk_tokens(node).any(|it| it.text().contains('\n'))
2730
}
31+
pub(crate) fn prev_non_whitespace_sibling(element: &SyntaxElement) -> Option<SyntaxElement> {
32+
successors(element.prev_sibling_or_token(), |it| it.prev_sibling_or_token())
33+
.find(|it| it.kind() != WHITESPACE)
34+
}
35+
36+
pub(crate) fn next_non_whitespace_sibling(element: &SyntaxElement) -> Option<SyntaxElement> {
37+
successors(element.next_sibling_or_token(), |it| it.next_sibling_or_token())
38+
.find(|it| it.kind() != WHITESPACE)
39+
}

0 commit comments

Comments
 (0)