Merge branch 'master' into stable
This commit is contained in:
commit
c50a87cf79
|
@ -0,0 +1,15 @@
|
|||
|
||||
<a name="v0.2.0"></a>
|
||||
## [v0.2.0](https://github.com/Kogia-sima/sailfish/compare/v0.1.3...v0.2.0) (2020-07-17)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Remove Buffer::set_len method
|
||||
* Syntactically disallow invalid filter expression
|
||||
* remove runtime::Context API
|
||||
* Remove register_escape_fn API
|
||||
|
||||
### Features
|
||||
|
||||
* Implement Compiler::compile_str() function
|
||||
* Implement filters
|
|
@ -27,14 +27,22 @@ name = "glob"
|
|||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "integration-tests"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sailfish 0.2.0",
|
||||
"sailfish-compiler 0.2.0",
|
||||
"sailfish-macros 0.2.0",
|
||||
"sailfish 0.2.1",
|
||||
"sailfish-compiler 0.2.1",
|
||||
"sailfish-macros 0.2.1",
|
||||
"trybuild 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -105,7 +113,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "sailfish"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"itoap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -114,8 +122,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sailfish-compiler"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"home 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -126,10 +135,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sailfish-macros"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sailfish-compiler 0.2.0",
|
||||
"sailfish-compiler 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -249,6 +258,7 @@ dependencies = [
|
|||
"checksum ctor 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cf6b25ee9ac1995c54d7adb2eff8cfffb7260bc774fb63c601ec65467f43cd9d"
|
||||
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
"checksum home 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
|
||||
"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||
"checksum itoap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e804a5759b475f44377998918a7e3be9da3767056f5e77751ef7803893db0e9"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
|
21
Cargo.toml
21
Cargo.toml
|
@ -10,24 +10,3 @@ exclude = [
|
|||
"benches",
|
||||
"examples"
|
||||
]
|
||||
|
||||
[profile.dev.package.syn]
|
||||
opt-level = 0
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
overflow-checks = false
|
||||
incremental = true
|
||||
|
||||
[profile.test.package.syn]
|
||||
opt-level = 0
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
overflow-checks = false
|
||||
incremental = true
|
||||
|
||||
[profile.release.package.syn]
|
||||
opt-level = 0
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
overflow-checks = false
|
||||
incremental = true
|
||||
|
|
|
@ -30,8 +30,8 @@ Dependencies:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
sailfish = "0.2.0"
|
||||
sailfish-macros = "0.2.0"
|
||||
sailfish = "0.2.1"
|
||||
sailfish-macros = "0.2.1"
|
||||
```
|
||||
|
||||
Template file (templates/hello.stpl):
|
||||
|
|
|
@ -188,7 +188,7 @@ checksum = "474a626a67200bd107d44179bb3d4fc61891172d11696609264589be6a0e6a43"
|
|||
|
||||
[[package]]
|
||||
name = "benches"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"askama",
|
||||
"bytes",
|
||||
|
@ -845,6 +845,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "horrorshow"
|
||||
version = "0.8.3"
|
||||
|
@ -1810,7 +1819,7 @@ checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
|
|||
|
||||
[[package]]
|
||||
name = "sailfish"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"itoap",
|
||||
"ryu",
|
||||
|
@ -1819,8 +1828,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sailfish-compiler"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"home",
|
||||
"memchr",
|
||||
"proc-macro2 1.0.18",
|
||||
"quote 1.0.7",
|
||||
|
@ -1830,7 +1840,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sailfish-macros"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18",
|
||||
"sailfish-compiler",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "benches"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Dirkjan Ochtman <dirkjan@ochtman.nl>", "Ryohei Machida <orcinus4627@gmail.com>"]
|
||||
build = "src/build.rs"
|
||||
edition = "2018"
|
||||
|
|
|
@ -51,8 +51,8 @@ And render the data with `render_once()` method.
|
|||
```rust
|
||||
fn main() {
|
||||
let ctx = HelloTemplate {
|
||||
messages: vec![String::from("foo"), String::from("bar")];
|
||||
}
|
||||
messages: vec![String::from("foo"), String::from("bar")],
|
||||
};
|
||||
|
||||
// Now render templates with given data
|
||||
println!("{}", ctx.render_once().unwrap());
|
||||
|
|
|
@ -4,8 +4,8 @@ In order to use sailfish templates, you have add two dependencies in your `Cargo
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
sailfish = "0.2.0"
|
||||
sailfish-macros = "0.2.0"
|
||||
sailfish = "0.2.1"
|
||||
sailfish-macros = "0.2.1"
|
||||
```
|
||||
|
||||
`sailfish` crate contains runtime for rendering contents, and `sailfish-macros` serves you derive macros to compile and import the template files.
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# Filters
|
||||
|
||||
Filters are used to format the rendered contents.
|
||||
|
||||
Example:
|
||||
|
||||
```ejs
|
||||
message: <%= "foo\nbar" | dbg %>
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```html
|
||||
message: "foo\nbar"
|
||||
```
|
||||
|
||||
!!! Note
|
||||
Since `dbg` filter accepts '<T: std::fmt::Debug>' types, that type isn't required to implement [`Render`](https://docs.rs/sailfish/latest/sailfish/runtime/trait.Render.html) trait. That means you can pass the type which doen't implement `Render` trait.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
- Apply filter and HTML escaping
|
||||
|
||||
```ejs
|
||||
<%= expression | filter %>
|
||||
```
|
||||
|
||||
- Apply filter only
|
||||
|
||||
```ejs
|
||||
<%- expression | filter %>
|
||||
```
|
||||
|
||||
## Built-In Filters
|
||||
|
||||
Built-In filters can be found in [`sailfish::runtime::filter`](https://docs.rs/sailfish/latest/sailfish/runtime/filter/index.html) module.
|
|
@ -32,6 +32,15 @@
|
|||
|
||||
Unlike EJS, you cannot omit the file extension.
|
||||
|
||||
## Helpers
|
||||
## Filters
|
||||
|
||||
(Work in progress)
|
||||
```ejs
|
||||
<%= message | upper %>
|
||||
```
|
||||
|
||||
```ejs
|
||||
{
|
||||
"id": <%= id %>
|
||||
"comment": <%- comment | dbg %>
|
||||
}
|
||||
```
|
||||
|
|
|
@ -50,3 +50,4 @@ nav:
|
|||
- 'Overview': 'syntax/overview.md'
|
||||
- 'Tags': 'syntax/tags.md'
|
||||
- 'Includes': 'syntax/includes.md'
|
||||
- 'Filters': 'syntax/filters.md'
|
||||
|
|
|
@ -651,6 +651,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.3.1"
|
||||
|
@ -1121,7 +1130,7 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
|||
|
||||
[[package]]
|
||||
name = "sailfish"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"itoap",
|
||||
"ryu",
|
||||
|
@ -1130,8 +1139,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sailfish-compiler"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"home",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1141,7 +1151,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sailfish-examples"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"actix-rt",
|
||||
"actix-web",
|
||||
|
@ -1151,7 +1161,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sailfish-macros"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"sailfish-compiler",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "sailfish-examples"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "sailfish-compiler"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
||||
description = "Really fast, intuitive template engine for Rust"
|
||||
homepage = "https://github.com/Kogia-sima/sailfish"
|
||||
|
@ -25,6 +25,7 @@ config = ["yaml-rust"]
|
|||
memchr = "2.3.3"
|
||||
quote = { version = "1.0.6", default-features = false }
|
||||
yaml-rust = { version = "0.4.4", optional = true }
|
||||
home = "0.5.3"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "1.0.21"
|
||||
|
@ -32,7 +33,7 @@ default-features = false
|
|||
features = ["parsing", "full", "visit-mut", "printing", "clone-impls", "extra-traits"]
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = ">=1.0.11, <=1.0.18"
|
||||
version = ">=1.0.11, <=1.0.19"
|
||||
default-features = false
|
||||
features = ["span-locations"]
|
||||
|
||||
|
|
|
@ -274,13 +274,15 @@ fn derive_template_impl(tokens: TokenStream) -> Result<TokenStream, syn::Error>
|
|||
|
||||
static SIZE_HINT: __sf_rt::SizeHint = __sf_rt::SizeHint::new();
|
||||
|
||||
let mut __sf_buf = __sf_rt::Buffer::from(std::mem::take(buf));
|
||||
let mut __sf_buf = __sf_rt::Buffer::from(buf.as_str());
|
||||
__sf_buf.reserve(SIZE_HINT.get());
|
||||
|
||||
let __sf_old_len = __sf_buf.len();
|
||||
|
||||
let #name { #field_names } = self;
|
||||
include!(#output_file_string);
|
||||
|
||||
SIZE_HINT.update(__sf_buf.len());
|
||||
SIZE_HINT.update(__sf_buf.len() - __sf_old_len);
|
||||
*buf = __sf_buf.into_string();
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
pub fn read_to_string(path: &Path) -> io::Result<String> {
|
||||
|
@ -16,13 +17,38 @@ pub fn read_to_string(path: &Path) -> io::Result<String> {
|
|||
Ok(content)
|
||||
}
|
||||
|
||||
fn find_rustfmt() -> io::Result<Option<PathBuf>> {
|
||||
let mut toolchain_dir = home::rustup_home()?;
|
||||
toolchain_dir.push("toolchains");
|
||||
for e in fs::read_dir(toolchain_dir)? {
|
||||
let mut path = e?.path();
|
||||
path.push("bin");
|
||||
path.push("rustfmt");
|
||||
if path.exists() {
|
||||
return Ok(Some(path));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Format block expression using `rustfmt` command
|
||||
pub fn rustfmt_block(source: &str) -> io::Result<String> {
|
||||
let rustfmt = match find_rustfmt()? {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"rustfmt command not found",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let mut new_source = String::with_capacity(source.len() + 11);
|
||||
new_source.push_str("fn render()");
|
||||
new_source.push_str(source);
|
||||
|
||||
let mut child = Command::new("rustfmt")
|
||||
let mut child = Command::new(rustfmt)
|
||||
.args(&["--emit", "stdout", "--color", "never", "--quiet"])
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "sailfish-macros"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
||||
description = "Really fast, intuitive template engine for Rust"
|
||||
homepage = "https://github.com/Kogia-sima/sailfish"
|
||||
|
@ -29,6 +29,6 @@ proc-macro2 = "1.0.11"
|
|||
|
||||
[dependencies.sailfish-compiler]
|
||||
path = "../sailfish-compiler"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
default-features = false
|
||||
features = ["procmacro"]
|
||||
|
|
|
@ -62,7 +62,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fuzzing-tests"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"afl",
|
||||
"sailfish",
|
||||
|
@ -78,6 +78,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoap"
|
||||
version = "0.1.0"
|
||||
|
@ -137,7 +146,7 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
|||
|
||||
[[package]]
|
||||
name = "sailfish"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"itoap",
|
||||
"ryu",
|
||||
|
@ -146,8 +155,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sailfish-compiler"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"home",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "fuzzing-tests"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "integration-tests"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Kogia-sima <orcinus4627@gmail.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<table>
|
||||
<tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr>
|
||||
<tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr><tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr>
|
||||
</table>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>2015</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CSL 2015</h1>
|
||||
<ul>
|
||||
<li class="champion"><b>Jiangsu</b>: 43</li><li class=""><b>Beijing</b>: 27</li><li class=""><b>Guangzhou</b>: 22</li><li class=""><b>Shandong</b>: 12</li>
|
||||
</ul>
|
||||
</body>
|
||||
<head>
|
||||
<title>2015</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CSL 2015</h1>
|
||||
<ul>
|
||||
<li class="champion"><b>Jiangsu</b>: 43</li><li class=""><b>Beijing</b>: 27</li><li class=""><b>Guangzhou</b>: 22</li><li class=""><b>Shandong</b>: 12</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -104,7 +104,7 @@ fn test_include() {
|
|||
}
|
||||
|
||||
#[derive(TemplateOnce)]
|
||||
#[template(path = "big-table.stpl")]
|
||||
#[template(path = "big-table.stpl", rm_whitespace = true)]
|
||||
struct BigTable {
|
||||
table: Vec<Vec<usize>>,
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ fn test_big_table() {
|
|||
}
|
||||
|
||||
#[derive(TemplateOnce)]
|
||||
#[template(path = "teams.stpl")]
|
||||
#[template(path = "teams.stpl", rm_whitespace = true)]
|
||||
struct Teams {
|
||||
year: u16,
|
||||
teams: Vec<Team>,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "sailfish"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Ryohei Machida <orcinus4627@gmail.com>"]
|
||||
description = "Really fast, intuitive template engine for Rust"
|
||||
homepage = "https://github.com/Kogia-sima/sailfish"
|
||||
|
|
|
@ -47,6 +47,7 @@ pub trait TemplateOnce: Sized {
|
|||
/// This method never returns `Err`, unless you explicitly return RenderError
|
||||
/// inside templates
|
||||
#[inline]
|
||||
#[allow(deprecated)]
|
||||
fn render_once(self) -> runtime::RenderResult {
|
||||
let mut buf = String::new();
|
||||
self.render_once_to_string(&mut buf)?;
|
||||
|
@ -57,6 +58,10 @@ pub trait TemplateOnce: Sized {
|
|||
///
|
||||
/// This method never returns `Err`, unless you explicitly return RenderError
|
||||
/// inside templates
|
||||
#[deprecated(
|
||||
since = "0.2.1",
|
||||
note = "This function may be removed in the future due to performance issue"
|
||||
)]
|
||||
fn render_once_to_string(self, buf: &mut String) -> Result<(), RenderError>;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,14 +30,8 @@ impl Buffer {
|
|||
if unlikely!(n == 0) {
|
||||
Self::new()
|
||||
} else {
|
||||
let layout = Layout::from_size_align_unchecked(n, 1);
|
||||
let data = alloc(layout);
|
||||
if data.is_null() {
|
||||
handle_alloc_error(layout);
|
||||
}
|
||||
|
||||
Self {
|
||||
data,
|
||||
data: safe_alloc(n),
|
||||
len: 0,
|
||||
capacity: n,
|
||||
}
|
||||
|
@ -148,6 +142,17 @@ impl Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn safe_alloc(capacity: usize) -> *mut u8 {
|
||||
assert!(capacity <= std::usize::MAX / 2, "capacity is too large");
|
||||
let layout = Layout::from_size_align_unchecked(capacity, 1);
|
||||
let data = alloc(layout);
|
||||
if data.is_null() {
|
||||
handle_alloc_error(layout);
|
||||
}
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
#[cold]
|
||||
unsafe fn safe_realloc(
|
||||
ptr: *mut u8,
|
||||
|
@ -178,14 +183,8 @@ impl Clone for Buffer {
|
|||
if self.capacity == 0 {
|
||||
Self::new()
|
||||
} else {
|
||||
let layout = Layout::from_size_align_unchecked(self.len, 1);
|
||||
let data = alloc(layout);
|
||||
if data.is_null() {
|
||||
handle_alloc_error(layout);
|
||||
}
|
||||
|
||||
let buf = Self {
|
||||
data,
|
||||
data: safe_alloc(self.len),
|
||||
len: self.len,
|
||||
capacity: self.len,
|
||||
};
|
||||
|
@ -223,13 +222,17 @@ impl fmt::Write for Buffer {
|
|||
}
|
||||
|
||||
impl From<String> for Buffer {
|
||||
/// Shrink the data and pass raw pointer directory to buffer
|
||||
///
|
||||
/// This operation is `O(1)`
|
||||
#[inline]
|
||||
fn from(other: String) -> Buffer {
|
||||
let mut other = ManuallyDrop::new(other);
|
||||
let bs = other.into_boxed_str();
|
||||
let data = unsafe { &mut *Box::into_raw(bs) };
|
||||
Buffer {
|
||||
data: other.as_mut_ptr(),
|
||||
len: other.len(),
|
||||
capacity: other.capacity(),
|
||||
data: data.as_mut_ptr(),
|
||||
len: data.len(),
|
||||
capacity: data.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -237,7 +240,12 @@ impl From<String> for Buffer {
|
|||
impl From<&str> for Buffer {
|
||||
#[inline]
|
||||
fn from(other: &str) -> Buffer {
|
||||
Buffer::from(other.to_owned())
|
||||
let mut buf = Buffer::with_capacity(other.len());
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(other.as_ptr(), buf.as_mut_ptr(), other.len());
|
||||
buf.advance(other.len());
|
||||
}
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,11 +60,10 @@ pub(super) unsafe fn escape_small(feed: &str, mut buf: *mut u8) -> usize {
|
|||
if unlikely!(idx < ESCAPED_LEN) {
|
||||
let escaped = ESCAPED.get_unchecked(idx);
|
||||
if ptr > start_ptr {
|
||||
let slc =
|
||||
slice::from_raw_parts(start_ptr, ptr as usize - start_ptr as usize);
|
||||
let len = ptr as usize - start_ptr as usize;
|
||||
|
||||
memcpy_16(slc.as_ptr(), buf, slc.len());
|
||||
buf = buf.add(slc.len());
|
||||
memcpy_16(start_ptr, buf, len);
|
||||
buf = buf.add(len);
|
||||
}
|
||||
memcpy_16(escaped.as_ptr(), buf, escaped.len());
|
||||
buf = buf.add(escaped.len());
|
||||
|
@ -77,9 +76,9 @@ pub(super) unsafe fn escape_small(feed: &str, mut buf: *mut u8) -> usize {
|
|||
debug_assert!(start_ptr <= ptr);
|
||||
|
||||
if likely!(end_ptr > start_ptr) {
|
||||
let slc = slice::from_raw_parts(start_ptr, end_ptr as usize - start_ptr as usize);
|
||||
memcpy_16(slc.as_ptr(), buf, slc.len());
|
||||
buf = buf.add(slc.len());
|
||||
let len = end_ptr as usize - start_ptr as usize;
|
||||
memcpy_16(start_ptr, buf, len);
|
||||
buf = buf.add(len);
|
||||
}
|
||||
|
||||
buf as usize - buf_begin as usize
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
//! Build-in filters
|
||||
|
||||
// TODO: performance improvement
|
||||
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
|
||||
use super::{Buffer, Render, RenderError};
|
||||
|
||||
|
@ -86,6 +89,60 @@ pub fn lower<T: Render>(expr: &T) -> Lower<T> {
|
|||
Lower(expr)
|
||||
}
|
||||
|
||||
pub struct Trim<'a, T>(&'a T);
|
||||
|
||||
impl<'a, T: Render> Render for Trim<'a, T> {
|
||||
#[inline]
|
||||
fn render(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
||||
let old_len = b.len();
|
||||
self.0.render(b)?;
|
||||
trim_impl(b, old_len);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn render_escaped(&self, b: &mut Buffer) -> Result<(), RenderError> {
|
||||
let old_len = b.len();
|
||||
self.0.render_escaped(b)?;
|
||||
trim_impl(b, old_len);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn trim_impl(b: &mut Buffer, old_len: usize) {
|
||||
debug_assert!(b.len() >= old_len);
|
||||
let new_contents = &b.as_str()[old_len..];
|
||||
let trimmed = new_contents.trim();
|
||||
let trimmed_len = trimmed.len();
|
||||
|
||||
if new_contents.len() != trimmed_len {
|
||||
// performs inplace trimming
|
||||
|
||||
if new_contents.as_ptr() != trimmed.as_ptr() {
|
||||
debug_assert!(new_contents.as_ptr() < trimmed.as_ptr());
|
||||
let offset = trimmed.as_ptr() as usize - new_contents.as_ptr() as usize;
|
||||
unsafe {
|
||||
ptr::copy(
|
||||
b.as_mut_ptr().add(old_len + offset),
|
||||
b.as_mut_ptr().add(old_len),
|
||||
trimmed_len,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
debug_assert!(b.capacity() >= old_len + trimmed_len);
|
||||
unsafe {
|
||||
b._set_len(old_len + trimmed_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// convert the rendered contents to lowercase
|
||||
#[inline]
|
||||
pub fn trim<T: Render>(expr: &T) -> Trim<T> {
|
||||
Trim(expr)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -104,4 +161,23 @@ mod tests {
|
|||
lower(&"<h1>TITLE</h1>").render_escaped(&mut buf).unwrap();
|
||||
assert_eq!(buf.as_str(), "<h1>title</h1>");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trim_test() {
|
||||
let mut buf = Buffer::new();
|
||||
trim(&" hello ").render(&mut buf).unwrap();
|
||||
trim(&"hello ").render(&mut buf).unwrap();
|
||||
trim(&" hello").render(&mut buf).unwrap();
|
||||
assert_eq!(buf.as_str(), "hellohellohello");
|
||||
|
||||
let mut buf = Buffer::new();
|
||||
trim(&"hello ").render(&mut buf).unwrap();
|
||||
trim(&" hello").render(&mut buf).unwrap();
|
||||
trim(&"hello").render(&mut buf).unwrap();
|
||||
assert_eq!(buf.as_str(), "hellohellohello");
|
||||
|
||||
let mut buf = Buffer::new();
|
||||
trim(&" hello").render(&mut buf).unwrap();
|
||||
assert_eq!(buf.as_str(), "hello");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ impl SizeHint {
|
|||
/// as the value passed on update()
|
||||
#[inline]
|
||||
pub fn update(&self, mut value: usize) {
|
||||
value = value + value / 4;
|
||||
value = value + value / 8 + 75;
|
||||
if unlikely!(self.get() < value) {
|
||||
self.value.store(value, Ordering::Release);
|
||||
}
|
||||
|
|
|
@ -3,15 +3,19 @@ unlet b:current_syntax
|
|||
|
||||
syn include @rustSyntax syntax/rust.vim
|
||||
|
||||
syn region sailfishCodeBlock matchgroup=sailfishTag start=/<%/ keepend end=/%>/ contains=@rustSyntax
|
||||
syn region sailfishBufferBlock matchgroup=sailfishTag start=/<%=/ keepend end=/%>/ contains=@rustSyntax
|
||||
syn region sailfishCodeBlock contained matchgroup=sailfishTag start=/<%/ keepend end=/%>/ contains=@rustSyntax
|
||||
syn region sailfishBufferBlock contained matchgroup=sailfishTag start=/<%=/ keepend end=/%>/ contains=@rustSyntax
|
||||
syn region sailfishCommentBlock start=/<%#/ end=/%>/
|
||||
|
||||
" Redefine htmlTag so that it can contain jspExpr
|
||||
syn clear htmlString
|
||||
syn region htmlString contained start=+"+ end=+"+ contains=htmlSpecialChar,javaScriptExpression,@htmlPreproc,sailfishCodeBlock,sailfishBufferBlock
|
||||
syn region htmlString contained start=+'+ end=+'+ contains=htmlSpecialChar,javaScriptExpression,@htmlPreproc,sailfishCodeBlock,sailfishBufferBlock
|
||||
|
||||
syn clear htmlTag
|
||||
syn region htmlTag start=+<[^/%]+ end=+>+ fold contains=htmlTagN,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent,htmlCssDefinition,@htmlPreproc,@htmlArgCluster,sailfishBufferBlock
|
||||
|
||||
hi default link sailfishTag htmlTag
|
||||
hi default link sailfishTag htmlPreProc
|
||||
hi default link sailfishCommentBlock htmlComment
|
||||
|
||||
let b:current_syntax = "sailfish"
|
||||
|
|
Loading…
Reference in New Issue