Skip to content

Commit c4156bd

Browse files
authored
Treat tab as text, not whitespace (#312)
Add pub(crate) parser::matches_fluent_ws helper function
1 parent 78978eb commit c4156bd

File tree

5 files changed

+73
-5
lines changed

5 files changed

+73
-5
lines changed

fluent-syntax/src/parser/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ mod slice;
7979

8080
use crate::ast;
8181
pub use errors::{ErrorKind, ParserError};
82+
pub(crate) use slice::matches_fluent_ws;
8283
pub use slice::Slice;
8384

8485
/// Parser result always returns an AST representation of the input,

fluent-syntax/src/parser/slice.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
use std::ops::Range;
2+
3+
pub(crate) fn matches_fluent_ws(c: char) -> bool {
4+
c == ' ' || c == '\r' || c == '\n'
5+
}
6+
27
pub trait Slice<'s>: AsRef<str> + Clone + PartialEq {
38
fn slice(&self, range: Range<usize>) -> Self;
49
fn trim(&mut self);
@@ -10,7 +15,7 @@ impl<'s> Slice<'s> for String {
1015
}
1116

1217
fn trim(&mut self) {
13-
*self = self.trim_end().to_string();
18+
*self = self.trim_end_matches(matches_fluent_ws).to_string();
1419
}
1520
}
1621

@@ -20,6 +25,6 @@ impl<'s> Slice<'s> for &'s str {
2025
}
2126

2227
fn trim(&mut self) {
23-
*self = self.trim_end();
28+
*self = self.trim_end_matches(matches_fluent_ws);
2429
}
2530
}

fluent-syntax/src/serializer.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
//! assert_eq!(ftl, serialized);
2222
//! ```
2323
24-
use crate::{ast::*, parser::Slice};
24+
use crate::{ast::*, parser::Slice, parser::matches_fluent_ws};
2525
use std::fmt::Write;
2626

2727
/// Serializes an abstract syntax tree representing a Fluent Translation List into a
@@ -118,7 +118,11 @@ impl Serializer {
118118
for line in &comment.content {
119119
self.writer.write_literal(prefix);
120120

121-
if !line.as_ref().trim().is_empty() {
121+
if !line
122+
.as_ref()
123+
.trim_matches(matches_fluent_ws)
124+
.is_empty()
125+
{
122126
self.writer.write_literal(" ");
123127
self.writer.write_literal(line.as_ref());
124128
}

fluent-syntax/tests/fixtures/tab.ftl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,10 @@ key03 =
1212
key04 =
1313
This line is indented by 4 spaces,
1414
whereas this line by 1 tab.
15+
16+
# OK (value is a single tab)
17+
key05 =
18+
19+
# OK (attribute value is two tabs)
20+
key06 =
21+
.attr =

fluent-syntax/tests/fixtures/tab.json

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,58 @@
6464
{
6565
"type": "Junk",
6666
"annotations": [],
67-
"content": "\twhereas this line by 1 tab.\n"
67+
"content": "\twhereas this line by 1 tab.\n\n"
68+
},
69+
{
70+
"type": "Message",
71+
"id": {
72+
"type": "Identifier",
73+
"name": "key05"
74+
},
75+
"value": {
76+
"type": "Pattern",
77+
"elements": [
78+
{
79+
"type": "TextElement",
80+
"value": "\t"
81+
}
82+
]
83+
},
84+
"attributes": [],
85+
"comment": {
86+
"type": "Comment",
87+
"content": "OK (value is a single tab)"
88+
}
89+
},
90+
{
91+
"type": "Message",
92+
"id": {
93+
"type": "Identifier",
94+
"name": "key06"
95+
},
96+
"value": null,
97+
"attributes": [
98+
{
99+
"type": "Attribute",
100+
"id": {
101+
"type": "Identifier",
102+
"name": "attr"
103+
},
104+
"value": {
105+
"type": "Pattern",
106+
"elements": [
107+
{
108+
"type": "TextElement",
109+
"value": "\t\t"
110+
}
111+
]
112+
}
113+
}
114+
],
115+
"comment": {
116+
"type": "Comment",
117+
"content": "OK (attribute value is two tabs)"
118+
}
68119
}
69120
]
70121
}

0 commit comments

Comments
 (0)