Skip to content

Commit

Permalink
Implement @whitespace setter.
Browse files Browse the repository at this point in the history
As suggested in #29.  A keyword `@whitespace` can be used to switch
whitespace handling between the tree modes `as-is`, `compact`, and
`removed`.

- [x] Implment the functionality.  Set default mode to `compact` and
  update tests.
- [ ] Decide on the exact syntax; should some keyword change?  Should
  `@ws` be allowed as an alias for `@whitespace`?  Should the
  `removed` alternative be called `trim`?  Or some other word change?
- [ ] Add documentation and more tests / examples.
- [ ] Anything else?
  • Loading branch information
kaj committed Jan 25, 2019
1 parent 41dec32 commit f7eb3b9
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 39 deletions.
14 changes: 7 additions & 7 deletions examples/ed2018/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ fn main() {
fn test_page_w_static() {
assert_eq!(
r2s(|o| page(o)),
"<html>\n \
<head>\n \
<title>Example with stylesheet</title>\n \
"<html>\n\
<head>\n\
<title>Example with stylesheet</title>\n\
<link rel=\"stylesheet\" href=\"/static/style-BeQlLiwh.css\" \
type=\"text/css\"/>\n \
</head>\n \
<body>\n \
Hello world!\n \
type=\"text/css\"/>\n\
</head>\n\
<body>\n\
Hello world!\n\
</body>\n\
</html>\n"
);
Expand Down
29 changes: 14 additions & 15 deletions examples/simple/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ fn test_if_let_destructure() {
fn test_list() {
assert_eq!(
r2s(|o| list(o, &["foo", "bar"])),
"\n<ul>\n \n <li>foo</li>\n \n <li>bar</li>\n </ul>\n\n"
"\n<ul>\n\n<li>foo</li>\n\n<li>bar</li>\n</ul>\n\n"
);
}

Expand All @@ -85,16 +85,16 @@ fn test_list_empty() {
fn test_list_destructure() {
assert_eq!(
r2s(|o| list_destructure(o, &["foo", "bar"])),
"<ul>\n \n <li>0: foo</li>\n \n \
<li>1: bar</li>\n </ul>\n"
"<ul>\n\n<li>0: foo</li>\n\n\
<li>1: bar</li>\n</ul>\n"
);
}

#[test]
fn test_list_destructure_2() {
assert_eq!(
r2s(|o| list_destructure_2(o)),
"\n <p>Rasmus is 44 years old.</p>\n\n \
"\n<p>Rasmus is 44 years old.</p>\n\n\
<p>Mike is 36 years old.</p>\n"
);
}
Expand All @@ -104,8 +104,8 @@ fn test_uselist() {
assert_eq!(
r2s(|o| uselist(o)),
"<h1>Two items</h1>\n\n\
<ul>\n \n <li>foo</li>\n \
\n <li>bar</li>\n </ul>\n\n\n\
<ul>\n\n<li>foo</li>\n\
\n<li>bar</li>\n</ul>\n\n\n\
<h2>No items</h2>\n\n\
<p>No items</p>\n\n\n"
);
Expand Down Expand Up @@ -190,8 +190,7 @@ fn test_hello_code() {
fn test_for_loop() {
assert_eq!(
r2s(|o| for_loop(o, &vec!["Hello", "World"])),
"<h1>Looped paragraphs</h1>\n\n \
<p>Hello</p>\n\n <p>World</p>\n"
"<h1>Looped paragraphs</h1>\n\n<p>Hello</p>\n\n<p>World</p>\n"
);
}

Expand Down Expand Up @@ -238,15 +237,15 @@ fn test_page_with_base() {
r2s(|o| page::page(o, "World")),
"<!doctype html>\
\n<html>\
\n <head><title>Hello World!</title>\
\n <meta property=\"og:description\" content=\"A simple example\"/>\
\n<head><title>Hello World!</title>\
\n<meta property=\"og:description\" content=\"A simple example\"/>\
\n</head>\
\n <body>\
\n <h1>Hello World!</h1>\
\n \
\n <p>This is page content for World</p>\
\n<body>\
\n<h1>Hello World!</h1>\
\n\
\n </body>\
\n<p>This is page content for World</p>\
\n\
\n</body>\
\n</html>\n\n"
);
}
14 changes: 7 additions & 7 deletions examples/static-sass/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ mod test {
fn page_w_static() {
assert_eq!(
r2s(|o| page(o)),
"<html>\n \
<head>\n \
<title>Example with stylesheet</title>\n \
"<html>\n\
<head>\n\
<title>Example with stylesheet</title>\n\
<link rel=\"stylesheet\" \
href=\"/static/style-uNrEkqKN.css\" \
type=\"text/css\"/>\n \
</head>\n \
<body>\n \
Hello world!\n \
type=\"text/css\"/>\n\
</head>\n\
<body>\n\
Hello world!\n\
</body>\n\
</html>\n"
);
Expand Down
14 changes: 7 additions & 7 deletions examples/statics/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ fn main() {
fn test_page_w_static() {
assert_eq!(
r2s(|o| page(o)),
"<html>\n \
<head>\n \
<title>Example with stylesheet</title>\n \
"<html>\n\
<head>\n\
<title>Example with stylesheet</title>\n\
<link rel=\"stylesheet\" href=\"/static/style-o2rFo1lI.css\" \
type=\"text/css\"/>\n \
</head>\n \
<body>\n \
Hello world!\n \
type=\"text/css\"/>\n\
</head>\n\
<body>\n\
Hello world!\n\
</body>\n\
</html>\n"
);
Expand Down
6 changes: 4 additions & 2 deletions src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use itertools::Itertools;
use nom::types::CompleteByteSlice as Input;
use spacelike::spacelike;
use std::io::{self, Write};
use templateexpression::{template_expression, TemplateExpression};
use templateexpression::{
apply_spacemode, template_expression, SpaceMode, TemplateExpression,
};

#[derive(Debug, PartialEq, Eq)]
pub struct Template {
Expand Down Expand Up @@ -70,7 +72,7 @@ named!(
template_expression),
call!(end_of_file))
),
|((), preamble, args, body)| Template { preamble, args, body: body.0 }
|((), preamble, args, body)| Template { preamble, args, body: apply_spacemode(body.0, SpaceMode::Compact) }
)
);

Expand Down
161 changes: 160 additions & 1 deletion src/templateexpression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ pub enum TemplateExpression {
name: String,
args: Vec<TemplateArgument>,
},
/// The actual mode is allreay applied, this variant is just to ensure
/// that outer space mode changes don't descend into this group.
SpaceMode(Vec<TemplateExpression>),
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SpaceMode {
AsIs,
Compact,
Removed,
}

#[derive(Debug, PartialEq, Eq)]
Expand All @@ -37,6 +47,17 @@ pub enum TemplateArgument {
Body(Vec<TemplateExpression>),
}

impl TemplateArgument {
pub fn apply_spacemode(self, mode: SpaceMode) -> Self {
match self {
TemplateArgument::Rust(s) => TemplateArgument::Rust(s),
TemplateArgument::Body(v) => {
TemplateArgument::Body(apply_spacemode(v, mode))
}
}
}
}

impl Display for TemplateArgument {
fn fmt(&self, out: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Expand All @@ -53,12 +74,64 @@ impl Display for TemplateArgument {
}
}

pub fn apply_spacemode(
v: Vec<TemplateExpression>,
mode: SpaceMode,
) -> Vec<TemplateExpression> {
v.into_iter().map(|b| b.apply_spacemode(mode)).collect()
}

impl TemplateExpression {
pub fn text(text: &str) -> Self {
TemplateExpression::Text {
text: text.to_string(),
}
}
pub fn apply_spacemode(self, mode: SpaceMode) -> Self {
match self {
TemplateExpression::Comment => TemplateExpression::Comment,
TemplateExpression::Text { text } => TemplateExpression::Text {
text: match mode {
SpaceMode::AsIs => text,
SpaceMode::Compact => compactify(&text),
SpaceMode::Removed => {
compactify(&text).trim().to_string()
}
},
},
TemplateExpression::Expression { expr } => {
TemplateExpression::Expression { expr }
}
TemplateExpression::ForLoop { name, expr, body } => {
TemplateExpression::ForLoop {
name,
expr,
body: apply_spacemode(body, mode),
}
}
TemplateExpression::IfBlock {
expr,
body,
else_body,
} => TemplateExpression::IfBlock {
expr,
body: apply_spacemode(body, mode),
else_body: else_body.map(|eb| apply_spacemode(eb, mode)),
},
TemplateExpression::CallTemplate { name, args } => {
TemplateExpression::CallTemplate {
name,
args: args
.into_iter()
.map(|b| b.apply_spacemode(mode))
.collect(),
}
}
TemplateExpression::SpaceMode(body) => {
TemplateExpression::SpaceMode(body)
}
}
}
pub fn code(&self) -> String {
match *self {
TemplateExpression::Comment => String::new(),
Expand Down Expand Up @@ -104,8 +177,47 @@ impl TemplateExpression {
))),
)
}
TemplateExpression::SpaceMode(ref body) => {
body.iter().map(|b| b.code()).format("").to_string()
}
}
}
}

fn compactify(s: &str) -> String {
let mut space = false;
let mut newline = false;
let mut result = String::new();
for c in s.chars() {
match c {
'\n' => newline = true,
' ' => space = true,
c => {
if newline {
result.push('\n');
} else if space {
result.push(' ');
}
result.push(c);
newline = false;
space = false;
}
}
}
if newline {
result.push('\n');
} else if space {
result.push(' ');
}
result
}

#[test]
fn t_compactify() {
assert_eq!(
compactify(" hello world \n \n This is nice.\n\n\n"),
" hello world\nThis is nice.\n"
)
}

named!(
Expand All @@ -117,7 +229,7 @@ named!(
alt!(tag!("*") | tag!(":") | tag!("@") |
tag!("{") | tag!("}") |
terminated!(
alt!(tag!("if") | tag!("for")),
alt!(tag!("if") | tag!("for") | tag!("whitespace")),
tag!(" ")) |
value!(Input(&b""[..]))))),
Some(Input(b":")) => map!(
Expand Down Expand Up @@ -168,6 +280,24 @@ named!(
expr: expr.to_string(),
body,
}) |
Some(Input(b"whitespace")) => map!(
tuple!(
delimited!(tag!("("),
alt!(
value!(SpaceMode::AsIs, tag!("as-is")) |
value!(SpaceMode::Compact, tag!("compact")) |
value!(SpaceMode::Removed, tag!("removed"))
),
terminated!(tag!(")"), spacelike)),
template_block
),
|(mode, body)| {
eprintln!("TODO: Apply {:?} to {:?}", mode, body);
TemplateExpression::SpaceMode(
body.into_iter().map(|b| b.apply_spacemode(mode)).collect()
)
}
) |
Some(Input(b"")) => map!(
expression,
|expr| TemplateExpression::Expression{ expr: expr.to_string() }
Expand Down Expand Up @@ -489,6 +619,35 @@ mod test {
)
}

#[test]
fn skip_ws() {
assert_eq!(
template_expression(Input(
b"@whitespace (removed) {\
\n @if something {\
\n construct with\
\n inner space\
\n }\
\n}\
",
)),
Ok((
Input(&b""[..]),
TemplateExpression::SpaceMode(vec![
TemplateExpression::text(""),
TemplateExpression::IfBlock {
expr: "something".to_string(),
body: vec![TemplateExpression::text(
"construct with\ninner space"
)],
else_body: None,
},
TemplateExpression::text(""),
]),
))
)
}

#[test]
fn for_missing_in() {
// TODO The second part of this message isn't really helpful.
Expand Down

0 comments on commit f7eb3b9

Please sign in to comment.