Add monospace syntax 📰
This commit is contained in:
parent
099ce71aba
commit
5de92f6d5e
@ -59,11 +59,11 @@ fn run() -> Result<(), Box<Error>> {
|
||||
("CMU-Serif-Italic.ttf", font!["Computer Modern", Italic, Serif]),
|
||||
("CMU-Serif-Bold.ttf", font!["Computer Modern", Bold, Serif]),
|
||||
("CMU-Serif-Bold-Italic.ttf", font!["Computer Modern", Bold, Italic, Serif]),
|
||||
("CMU-Typewriter-Regular.ttf", font!["Computer Modern", Regular, Monospace]),
|
||||
("CMU-Typewriter-Italic.ttf", font!["Computer Modern", Italic, Monospace]),
|
||||
("CMU-Typewriter-Bold.ttf", font!["Computer Modern", Bold, Monospace]),
|
||||
("CMU-Typewriter-Bold-Italic.ttf", font!["Computer Modern", Bold, Italic, Monospace]),
|
||||
("NotoEmoji-Regular.ttf", font!["Noto", Regular, SansSerif, Serif, Monospace]),
|
||||
("CMU-Typewriter-Regular.ttf", font!["Computer Modern", Regular, Serif, SansSerif, Monospace]),
|
||||
("CMU-Typewriter-Italic.ttf", font!["Computer Modern", Italic, Serif, SansSerif, Monospace]),
|
||||
("CMU-Typewriter-Bold.ttf", font!["Computer Modern", Bold, Serif, SansSerif, Monospace]),
|
||||
("CMU-Typewriter-Bold-Italic.ttf", font!["Computer Modern", Bold, Italic, Serif, SansSerif, Monospace]),
|
||||
("NotoEmoji-Regular.ttf", font!["Noto", Regular, Bold, Italic, SansSerif, Serif, Monospace]),
|
||||
]));
|
||||
|
||||
// Typeset the source code.
|
||||
|
11
src/func.rs
11
src/func.rs
@ -77,13 +77,12 @@ impl Scope {
|
||||
Scope { parsers: HashMap::new() }
|
||||
}
|
||||
|
||||
/// Create a new scope with the standard functions contained:
|
||||
/// - `italic`
|
||||
/// - `bold`
|
||||
/// Create a new scope with the standard functions contained.
|
||||
pub fn with_std() -> Scope {
|
||||
let mut std = Scope::new();
|
||||
std.add::<BoldFunc>("bold");
|
||||
std.add::<ItalicFunc>("italic");
|
||||
std.add::<MonospaceFunc>("mono");
|
||||
std
|
||||
}
|
||||
|
||||
@ -161,3 +160,9 @@ style_func! {
|
||||
pub struct ItalicFunc { "italic" },
|
||||
style => { style.toggle_class(FontClass::Italic) }
|
||||
}
|
||||
|
||||
style_func! {
|
||||
/// Typesets text in monospace.
|
||||
pub struct MonospaceFunc { "mono" },
|
||||
style => { style.toggle_class(FontClass::Monospace) }
|
||||
}
|
||||
|
@ -116,6 +116,7 @@ impl<'a, 'p> Layouter<'a, 'p> {
|
||||
// Toggle the text styles.
|
||||
Node::ToggleItalics => self.style.to_mut().toggle_class(FontClass::Italic),
|
||||
Node::ToggleBold => self.style.to_mut().toggle_class(FontClass::Bold),
|
||||
Node::ToggleMonospace => self.style.to_mut().toggle_class(FontClass::Monospace),
|
||||
|
||||
// Execute a function.
|
||||
Node::Func(func) => self.layout_func(func)?,
|
||||
|
25
src/lib.rs
25
src/lib.rs
@ -20,7 +20,7 @@
|
||||
//! use typeset::export::pdf::PdfExporter;
|
||||
//!
|
||||
//! // Simple example source code.
|
||||
//! let src = "Hello World from __Typeset__! 🌍";
|
||||
//! let src = "Hello World from _Typeset_! 🌍";
|
||||
//!
|
||||
//! // Create a typesetter with a font provider that provides three fonts
|
||||
//! // (two sans-serif fonts and a fallback for the emoji).
|
||||
@ -193,11 +193,11 @@ mod test {
|
||||
("CMU-Serif-Italic.ttf", font!["Computer Modern", Italic, Serif]),
|
||||
("CMU-Serif-Bold.ttf", font!["Computer Modern", Bold, Serif]),
|
||||
("CMU-Serif-Bold-Italic.ttf", font!["Computer Modern", Bold, Italic, Serif]),
|
||||
("CMU-Typewriter-Regular.ttf", font!["Computer Modern", Regular, Monospace]),
|
||||
("CMU-Typewriter-Italic.ttf", font!["Computer Modern", Italic, Monospace]),
|
||||
("CMU-Typewriter-Bold.ttf", font!["Computer Modern", Bold, Monospace]),
|
||||
("CMU-Typewriter-Bold-Italic.ttf", font!["Computer Modern", Bold, Italic, Monospace]),
|
||||
("NotoEmoji-Regular.ttf", font!["Noto", Regular, SansSerif, Serif, Monospace]),
|
||||
("CMU-Typewriter-Regular.ttf", font!["Computer Modern", Regular, Serif, SansSerif, Monospace]),
|
||||
("CMU-Typewriter-Italic.ttf", font!["Computer Modern", Italic, Serif, SansSerif, Monospace]),
|
||||
("CMU-Typewriter-Bold.ttf", font!["Computer Modern", Bold, Serif, SansSerif, Monospace]),
|
||||
("CMU-Typewriter-Bold-Italic.ttf", font!["Computer Modern", Bold, Italic, Serif, SansSerif, Monospace]),
|
||||
("NotoEmoji-Regular.ttf", font!["Noto", Regular, Bold, Italic, SansSerif, Serif, Monospace]),
|
||||
]));
|
||||
|
||||
// Typeset into document.
|
||||
@ -213,20 +213,21 @@ mod test {
|
||||
#[test]
|
||||
fn features() {
|
||||
test("features", r"
|
||||
**Features Test Page**
|
||||
*Features Test Page*
|
||||
|
||||
__Multiline:__
|
||||
_Multiline:_
|
||||
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
|
||||
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
|
||||
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
|
||||
clita kasd gubergren, no sea takimata sanctus est.
|
||||
|
||||
__Emoji:__ Hello World! 🌍
|
||||
_Emoji:_ Hello World! 🌍
|
||||
|
||||
__Styles:__ This is made **bold** and that __italic__ using the built-in syntax!
|
||||
_Styles:_ This is made *bold*, that _italic_ and this one `monospace` using the
|
||||
built-in syntax!
|
||||
|
||||
__Styles with functions:__ This is in [bold][boldface] and that is in [italic][italics]
|
||||
using library functions!
|
||||
_Styles with functions:_ This [bold][word] is made bold and [italic][that] is italic
|
||||
using the standard library functions [mono][bold] and `italic`!
|
||||
");
|
||||
}
|
||||
|
||||
|
@ -81,12 +81,12 @@ impl<'s> Iterator for Tokens<'s> {
|
||||
|
||||
/// Advance the iterator, return the next token or nothing.
|
||||
fn next(&mut self) -> Option<Token<'s>> {
|
||||
use TokensState as TS;
|
||||
use TokensState as TU;
|
||||
|
||||
// Go to the body state if the function has a body or return to the top-of-stack state.
|
||||
if self.state == TS::MaybeBody {
|
||||
if self.state == TU::MaybeBody {
|
||||
if self.chars.peek()?.1 == '[' {
|
||||
self.state = TS::Body;
|
||||
self.state = TU::Body;
|
||||
return Some(self.consumed(Token::LeftBracket));
|
||||
} else {
|
||||
self.unswitch();
|
||||
@ -100,12 +100,12 @@ impl<'s> Iterator for Tokens<'s> {
|
||||
Some(match next {
|
||||
// Functions
|
||||
'[' => {
|
||||
self.switch(TS::Function);
|
||||
self.switch(TU::Function);
|
||||
Token::LeftBracket
|
||||
},
|
||||
']' => {
|
||||
if self.state == TS::Function {
|
||||
self.state = TS::MaybeBody;
|
||||
if self.state == TU::Function {
|
||||
self.state = TU::MaybeBody;
|
||||
} else {
|
||||
self.unswitch();
|
||||
}
|
||||
@ -168,21 +168,20 @@ impl<'s> Iterator for Tokens<'s> {
|
||||
'\r' if afterwards == Some('\n') => self.consumed(Token::Newline),
|
||||
c if is_newline_char(c) => Token::Newline,
|
||||
|
||||
// Context sensitive operators in headers
|
||||
':' if self.state == TS::Function => Token::Colon,
|
||||
'=' if self.state == TS::Function => Token::Equals,
|
||||
// Star/Underscore/Backtick in bodies
|
||||
'*' if self.state == TU::Body => Token::Star,
|
||||
'_' if self.state == TU::Body => Token::Underscore,
|
||||
'`' if self.state == TU::Body => Token::Backtick,
|
||||
|
||||
// Double star/underscore in bodies
|
||||
'*' if self.state == TS::Body && afterwards == Some('*')
|
||||
=> self.consumed(Token::DoubleStar),
|
||||
'_' if self.state == TS::Body && afterwards == Some('_')
|
||||
=> self.consumed(Token::DoubleUnderscore),
|
||||
// Context sensitive operators in headers
|
||||
':' if self.state == TU::Function => Token::Colon,
|
||||
'=' if self.state == TU::Function => Token::Equals,
|
||||
|
||||
// Escaping
|
||||
'\\' => {
|
||||
if let Some((index, c)) = self.chars.peek() {
|
||||
let escapable = match c {
|
||||
'[' | ']' | '$' | '#' | '\\' | '*' | '_' | '/' => true,
|
||||
'[' | ']' | '\\' | '*' | '_' | '`' | ':' | '=' | '/' => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@ -202,13 +201,11 @@ impl<'s> Iterator for Tokens<'s> {
|
||||
while let Some((index, c)) = self.chars.peek() {
|
||||
let second = self.chars.peek_second().map(|p| p.1);
|
||||
|
||||
// Whether the next token is still from the next or not.
|
||||
// Whether the next token is still from the text or not.
|
||||
let continues = match c {
|
||||
'[' | ']' | '$' | '#' | '\\' => false,
|
||||
':' | '=' if self.state == TS::Function => false,
|
||||
|
||||
'*' if self.state == TS::Body => second != Some('*'),
|
||||
'_' if self.state == TS::Body => second != Some('_'),
|
||||
'[' | ']' | '\\' => false,
|
||||
'*' | '_' | '`' if self.state == TU::Body => false,
|
||||
':' | '=' if self.state == TU::Function => false,
|
||||
|
||||
'/' => second != Some('/') && second != Some('*'),
|
||||
'*' => second != Some('/'),
|
||||
@ -390,8 +387,9 @@ impl<'s> Parser<'s> {
|
||||
Token::RightBracket => return Err(ParseError::new("unexpected closing bracket")),
|
||||
|
||||
// Modifiers
|
||||
Token::DoubleUnderscore => self.append_consumed(Node::ToggleItalics),
|
||||
Token::DoubleStar => self.append_consumed(Node::ToggleBold),
|
||||
Token::Underscore => self.append_consumed(Node::ToggleItalics),
|
||||
Token::Star => self.append_consumed(Node::ToggleBold),
|
||||
Token::Backtick => self.append_consumed(Node::ToggleMonospace),
|
||||
|
||||
// Normal text
|
||||
Token::Text(word) => self.append_consumed(Node::Text(word.to_owned())),
|
||||
@ -675,7 +673,7 @@ error_type! {
|
||||
mod token_tests {
|
||||
use super::*;
|
||||
use Token::{Space as S, Newline as N, LeftBracket as L, RightBracket as R,
|
||||
Colon as C, Equals as E, DoubleUnderscore as DU, DoubleStar as DS,
|
||||
Colon as C, Equals as E, Underscore as TU, Star as TS, Backtick as TB,
|
||||
Text as T, LineComment as LC, BlockComment as BC, StarSlash as SS};
|
||||
|
||||
/// Test if the source code tokenizes to the tokens.
|
||||
@ -690,8 +688,9 @@ mod token_tests {
|
||||
test("Hallo", vec![T("Hallo")]);
|
||||
test("[", vec![L]);
|
||||
test("]", vec![R]);
|
||||
test("**", vec![DS]);
|
||||
test("__", vec![DU]);
|
||||
test("*", vec![TS]);
|
||||
test("_", vec![TU]);
|
||||
test("`", vec![TB]);
|
||||
test("\n", vec![N]);
|
||||
}
|
||||
|
||||
@ -711,11 +710,9 @@ mod token_tests {
|
||||
fn tokenize_escape() {
|
||||
test(r"\[", vec![T("[")]);
|
||||
test(r"\]", vec![T("]")]);
|
||||
test(r"\#", vec![T("#")]);
|
||||
test(r"\$", vec![T("$")]);
|
||||
test(r"\**", vec![T("*"), T("*")]);
|
||||
test(r"\**", vec![T("*"), TS]);
|
||||
test(r"\*", vec![T("*")]);
|
||||
test(r"\__", vec![T("_"), T("_")]);
|
||||
test(r"\__", vec![T("_"), TU]);
|
||||
test(r"\_", vec![T("_")]);
|
||||
test(r"\hello", vec![T("\\"), T("hello")]);
|
||||
}
|
||||
@ -736,12 +733,12 @@ mod token_tests {
|
||||
[page: size=A4]
|
||||
[font: size=12pt]
|
||||
|
||||
Das ist ein Beispielsatz mit **fetter** Schrift.
|
||||
Das ist ein Beispielsatz mit *fetter* Schrift.
|
||||
", vec![
|
||||
N, S, L, T("page"), C, S, T("size"), E, T("A4"), R, N, S,
|
||||
L, T("font"), C, S, T("size"), E, T("12pt"), R, N, N, S,
|
||||
T("Das"), S, T("ist"), S, T("ein"), S, T("Beispielsatz"), S, T("mit"), S,
|
||||
DS, T("fetter"), DS, S, T("Schrift."), N, S
|
||||
TS, T("fetter"), TS, S, T("Schrift."), N, S
|
||||
]);
|
||||
}
|
||||
|
||||
@ -777,12 +774,12 @@ mod token_tests {
|
||||
test("/* My /* line // */ comment */", vec![BC(" My /* line // */ comment ")])
|
||||
}
|
||||
|
||||
/// This test has a special look at the double underscore syntax.
|
||||
/// This test has a special look at the underscore syntax.
|
||||
#[test]
|
||||
fn tokenize_double_underscore() {
|
||||
test("he__llo__world_ _ __ Now this_ is__ special!",
|
||||
vec![T("he"), DU, T("llo"), DU, T("world_"), S, T("_"), S, DU, S, T("Now"), S,
|
||||
T("this_"), S, T("is"), DU, S, T("special!")]);
|
||||
fn tokenize_underscores() {
|
||||
test("he_llo_world_ __ Now this_ is_ special!",
|
||||
vec![T("he"), TU, T("llo"), TU, T("world"), TU, S, TU, TU, S, T("Now"), S,
|
||||
T("this"), TU, S, T("is"), TU, S, T("special!")]);
|
||||
}
|
||||
|
||||
/// This test is for checking if non-ASCII characters get parsed correctly.
|
||||
|
@ -24,10 +24,12 @@ pub enum Token<'s> {
|
||||
///
|
||||
/// Outside of functions headers, same as with [Colon](Token::Colon).
|
||||
Equals,
|
||||
/// Two underscores, indicating text in italics.
|
||||
DoubleUnderscore,
|
||||
/// Two stars, indicating bold text.
|
||||
DoubleStar,
|
||||
/// An underscore, indicating text in italics.
|
||||
Underscore,
|
||||
/// A star, indicating bold text.
|
||||
Star,
|
||||
/// A backtick, indicating monospace text.
|
||||
Backtick,
|
||||
/// A line comment.
|
||||
LineComment(&'s str),
|
||||
/// A block comment.
|
||||
@ -65,6 +67,8 @@ pub enum Node {
|
||||
ToggleItalics,
|
||||
/// Indicates that boldface was enabled / disabled.
|
||||
ToggleBold,
|
||||
/// Indicates that monospace was enabled / disabled.
|
||||
ToggleMonospace,
|
||||
/// Literal text.
|
||||
Text(String),
|
||||
/// A function invocation.
|
||||
|
Loading…
x
Reference in New Issue
Block a user