Skip to content

Commit 3b9e0d1

Browse files
committed
moved to ra_fmt2
1 parent 0dd12ad commit 3b9e0d1

File tree

10 files changed

+215
-102
lines changed

10 files changed

+215
-102
lines changed

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_fmt/src/lib.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
//! This crate provides some utilities for indenting rust code.
2-
//!
3-
mod scratch;
4-
mod rules;
5-
mod dsl;
6-
mod engine;
7-
mod pattern;
82
93
use itertools::Itertools;
104
use ra_syntax::{

crates/ra_fmt/src/rules.rs

Lines changed: 0 additions & 90 deletions
This file was deleted.

crates/ra_fmt2/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
edition = "2018"
3+
name = "ra_fmt2"
4+
version = "0.1.0"
5+
authors = ["rust-analyzer developers"]
6+
publish = false
7+
8+
[dependencies]
9+
itertools = "0.8.0"
10+
11+
ra_syntax = { path = "../ra_syntax" }

crates/ra_fmt/src/dsl.rs renamed to crates/ra_fmt2/src/dsl.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{pattern::{Pattern, PatternSet}};
2-
use ra_syntax::{SyntaxElement,};
2+
use ra_syntax::{SyntaxElement, SyntaxKind::*,};
33
use std::iter::successors;
44

55
/// `SpacingRule` describes whitespace requirements between `SyntaxElement` Note
@@ -69,7 +69,7 @@ pub(crate) struct SpacingDsl {
6969
}
7070

7171
impl SpacingDsl {
72-
pub(crate) fn rule(&mut self, rule: SpacingRule) -> &mut SpacingDsl {
72+
pub(crate) fn rule(&mut self, rule: SpacingRule) -> &mut Self {
7373
self.rules.push(rule);
7474
self
7575
}
@@ -83,6 +83,15 @@ impl SpacingDsl {
8383
loc: None,
8484
}
8585
}
86+
87+
pub(crate) fn test(&mut self, before: &'static str, after: &'static str) -> &mut Self {
88+
#[cfg(test)]
89+
{
90+
self.tests.push((before, after));
91+
}
92+
let _ = (before, after);
93+
self
94+
}
8695
}
8796
/// A builder to conveniently specify a single rule.
8897
pub(crate) struct SpacingRuleBuilder<'a> {
@@ -147,7 +156,8 @@ impl<'a> SpacingRuleBuilder<'a> {
147156
pub(crate) fn single_space_or_newline(self) -> &'a mut SpacingDsl {
148157
self.finish(SpaceValue::SingleOrNewline)
149158
}
150-
/// Enforce a absence of whitespace or a newline character.
159+
/// Enforce an
160+
/// absence of whitespace or a newline character.
151161
pub(crate) fn no_space_or_newline(self) -> &'a mut SpacingDsl {
152162
self.finish(SpaceValue::NoneOrNewline)
153163
}
@@ -189,10 +199,10 @@ impl<'a> SpacingRuleBuilder<'a> {
189199

190200
pub(crate) fn prev_non_whitespace_sibling(element: &SyntaxElement) -> Option<SyntaxElement> {
191201
successors(element.prev_sibling_or_token(), |it| it.prev_sibling_or_token())
192-
.find(|it| it.kind() != TOKEN_WHITESPACE)
202+
.find(|it| it.kind() != WHITESPACE)
193203
}
194204

195205
pub(crate) fn next_non_whitespace_sibling(element: &SyntaxElement) -> Option<SyntaxElement> {
196206
successors(element.next_sibling_or_token(), |it| it.next_sibling_or_token())
197-
.find(|it| it.kind() != TOKEN_WHITESPACE)
207+
.find(|it| it.kind() != WHITESPACE)
198208
}
File renamed without changes.

crates/ra_fmt2/src/lib.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//! This crate provides some utilities for indenting rust code.
2+
//!
3+
mod scratch;
4+
mod rules;
5+
mod dsl;
6+
mod engine;
7+
mod pattern;
8+
9+
use itertools::Itertools;
10+
use ra_syntax::{
11+
ast::{self, AstNode, AstToken},
12+
SmolStr, SyntaxKind,
13+
SyntaxKind::*,
14+
SyntaxNode, SyntaxToken, T,
15+
};
16+
use std::iter::successors;
17+
18+
pub fn reindent(text: &str, indent: &str) -> String {
19+
let indent = format!("\n{}", indent);
20+
text.lines().intersperse(&indent).collect()
21+
}
22+
23+
/// If the node is on the beginning of the line, calculate indent.
24+
pub fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> {
25+
for token in prev_tokens(node.first_token()?) {
26+
if let Some(ws) = ast::Whitespace::cast(token.clone()) {
27+
let ws_text = ws.text();
28+
if let Some(pos) = ws_text.rfind('\n') {
29+
return Some(ws_text[pos + 1..].into());
30+
}
31+
}
32+
if token.text().contains('\n') {
33+
break;
34+
}
35+
}
36+
None
37+
}
38+
39+
fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
40+
successors(token.prev_token(), |token| token.prev_token())
41+
}
42+
43+
pub fn extract_trivial_expression(block: &ast::Block) -> Option<ast::Expr> {
44+
let expr = block.expr()?;
45+
if expr.syntax().text().contains_char('\n') {
46+
return None;
47+
}
48+
let non_trivial_children = block.syntax().children().filter(|it| match it.kind() {
49+
WHITESPACE | T!['{'] | T!['}'] => false,
50+
_ => it != expr.syntax(),
51+
});
52+
if non_trivial_children.count() > 0 {
53+
return None;
54+
}
55+
Some(expr)
56+
}
57+
58+
pub fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str {
59+
match left {
60+
T!['('] | T!['['] => return "",
61+
T!['{'] => {
62+
if let USE_TREE = right {
63+
return "";
64+
}
65+
}
66+
_ => (),
67+
}
68+
match right {
69+
T![')'] | T![']'] => return "",
70+
T!['}'] => {
71+
if let USE_TREE = left {
72+
return "";
73+
}
74+
}
75+
T![.] => return "",
76+
_ => (),
77+
}
78+
" "
79+
}

crates/ra_fmt/src/pattern.rs renamed to crates/ra_fmt2/src/pattern.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub(crate) struct Pattern {
1414

1515
impl fmt::Debug for Pattern {
1616
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17-
write!(f, "Pattern { ... }")
17+
write!(f, "Pattern {:?}", self.kinds)
1818
}
1919
}
2020

@@ -50,6 +50,19 @@ impl Pattern {
5050
}
5151
}
5252

53+
impl ops::BitAnd for Pattern {
54+
type Output = Self;
55+
fn bitand(self, other: Pattern) -> Pattern {
56+
let kinds = match (self.kinds, other.kinds) {
57+
(Some(lhs), Some(rhs)) => Some(lhs.intersection(&rhs).cloned().collect::<HashSet<_>>()),
58+
(Some(k), None) | (None, Some(k)) => Some(k),
59+
(None, None) => None,
60+
};
61+
let (p1, p2) = (self.pred, other.pred);
62+
Pattern::new(kinds, move |ele| p1(ele) && p2(ele))
63+
}
64+
}
65+
5366
/// Construct pattern from closure.
5467
impl<F> From<F> for Pattern
5568
where

crates/ra_fmt2/src/rules.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use itertools::Itertools;
2+
use ra_syntax::{
3+
ast::{self, AstNode, AstToken},
4+
SmolStr, SyntaxKind,
5+
SyntaxKind::*,
6+
SyntaxNode, SyntaxToken, T,
7+
};
8+
use crate::dsl::SpacingDsl;
9+
10+
pub(crate) fn spacing() -> SpacingDsl {
11+
let mut space_dsl = SpacingDsl::default();
12+
13+
space_dsl
14+
.test("struct Test{x:usize}", "struct Test { x: usize }")
15+
.inside(STRUCT_DEF).before(T!['{']).single_space();
16+
.inside(STRUCT_DEF).after(T!['{']).single_space_or_optional_newline()
17+
.inside(STRUCT_DEF).before(T!['}']).single_space_or_optional_newline();
18+
19+
// more rules to come
20+
21+
space_dsl
22+
}
23+
24+
#[cfg(test)]
25+
mod tests {
26+
27+
use std::{
28+
fs,
29+
path::{Path, PathBuf},
30+
};
31+
32+
use crate::{
33+
reformat_string,
34+
rules::{spacing},
35+
};
36+
37+
#[test]
38+
fn indent() {
39+
TestCase {
40+
name: None,
41+
before: "struct Test{x: u8}".into(),
42+
after: "struct Test { x: u8 }".into(),
43+
}
44+
.run()
45+
.map_err(|e| panic!(e))
46+
.unwrap();
47+
}
48+
49+
#[derive(Debug)]
50+
struct TestCase {
51+
name: Option<String>,
52+
before: String,
53+
after: String,
54+
}
55+
56+
impl TestCase {
57+
fn from_before_after(before: String, after: String) -> TestCase {
58+
TestCase { name: None, before, after }
59+
}
60+
61+
fn run(&self) -> Result<(), String> {
62+
let name = self.name.as_ref().map(|it| it.as_str()).unwrap_or("");
63+
let expected = &self.after;
64+
let actual = &reformat_string(&self.before);
65+
if expected != actual {
66+
return Err(format!(
67+
"\n\nAssertion failed: wrong formatting\
68+
\nTest: {}\n\
69+
\nBefore:\n{}\n\
70+
\nAfter:\n{}\n\
71+
\nExpected:\n{}\n",
72+
name, self.before, actual, self.after,
73+
));
74+
}
75+
let second_round = &reformat_string(actual);
76+
if actual != second_round {
77+
return Err(format!(
78+
"\n\nAssertion failed: formatting is not idempotent\
79+
\nTest: {}\n\
80+
\nBefore:\n{}\n\
81+
\nAfter:\n{}\n",
82+
name, actual, second_round,
83+
));
84+
}
85+
Ok(())
86+
}
87+
}
88+
}
File renamed without changes.

0 commit comments

Comments
 (0)