feat: support line breaks
This commit is contained in:
parent
6598095a9f
commit
58dfb022c2
10 changed files with 199 additions and 60 deletions
|
|
@ -260,6 +260,10 @@ const nodes = [
|
|||
struct: "Entity",
|
||||
kind: ["ENTITY"],
|
||||
},
|
||||
{
|
||||
struct: "LineBreak",
|
||||
kind: ["LINE_BREAK"],
|
||||
},
|
||||
];
|
||||
|
||||
let content = `//! generated file, do not modify it directly
|
||||
|
|
|
|||
|
|
@ -1691,3 +1691,28 @@ impl Entity {
|
|||
self.syntax.text_range().end().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct LineBreak {
|
||||
pub(crate) syntax: SyntaxNode,
|
||||
}
|
||||
impl AstNode for LineBreak {
|
||||
type Language = OrgLanguage;
|
||||
fn can_cast(kind: SyntaxKind) -> bool {
|
||||
kind == LINE_BREAK
|
||||
}
|
||||
fn cast(node: SyntaxNode) -> Option<LineBreak> {
|
||||
Self::can_cast(node.kind()).then(|| LineBreak { syntax: node })
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode {
|
||||
&self.syntax
|
||||
}
|
||||
}
|
||||
impl LineBreak {
|
||||
pub fn begin(&self) -> u32 {
|
||||
self.syntax.text_range().start().into()
|
||||
}
|
||||
pub fn end(&self) -> u32 {
|
||||
self.syntax.text_range().end().into()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
/// special_block quote_block center_block verse_block comment_block example_block export_block
|
||||
/// source_block babel_call clock cookie radio_target drawer dyn_block fn_def fn_ref macros
|
||||
/// snippet timestamp target fixed_width org_table org_table_row org_table_cell latex_fragment
|
||||
/// latex_environment entity
|
||||
/// latex_environment entity line_break
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
|
|
@ -200,6 +200,9 @@ macro_rules! forward_handler {
|
|||
(@method $handler:ty, entity) => {
|
||||
forward_handler!(@method $handler, entity, WalkEvent<&$crate::ast::Entity>);
|
||||
};
|
||||
(@method $handler:ty, line_break) => {
|
||||
forward_handler!(@method $handler, line_break, WalkEvent<&$crate::ast::LineBreak>);
|
||||
};
|
||||
(@method $handler:ty, $x:ident) => {
|
||||
std::compile_error!(std::concat!(std::stringify!($x), " is not a method"));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -510,4 +510,12 @@ impl Traverser for HtmlExport {
|
|||
ctx.skip();
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self, ctx))]
|
||||
fn line_break(&mut self, event: WalkEvent<&LineBreak>, ctx: &mut TraversalContext) {
|
||||
if let WalkEvent::Enter(_) = event {
|
||||
self.output += "<br/>";
|
||||
ctx.skip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ pub trait Traverser {
|
|||
LATEX_FRAGMENT => traverse!(LatexFragment, latex_fragment),
|
||||
LATEX_ENVIRONMENT => traverse!(LatexEnvironment, latex_environment),
|
||||
ENTITY => traverse!(Entity, entity),
|
||||
LINE_BREAK => traverse!(LineBreak, line_break),
|
||||
|
||||
BLOCK_CONTENT | LIST_ITEM_CONTENT => traverse_children!(node),
|
||||
|
||||
|
|
@ -156,97 +157,99 @@ pub trait Traverser {
|
|||
}
|
||||
|
||||
/// Called when visiting `Text` token
|
||||
fn text(&mut self, _token: SyntaxToken, _ctx: &mut TraversalContext);
|
||||
fn text(&mut self, token: SyntaxToken, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Document` node
|
||||
fn document(&mut self, _event: WalkEvent<&Document>, _ctx: &mut TraversalContext);
|
||||
fn document(&mut self, event: WalkEvent<&Document>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Headline` node
|
||||
fn headline(&mut self, _event: WalkEvent<&Headline>, _ctx: &mut TraversalContext);
|
||||
fn headline(&mut self, event: WalkEvent<&Headline>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Paragraph` node
|
||||
fn paragraph(&mut self, _event: WalkEvent<&Paragraph>, _ctx: &mut TraversalContext);
|
||||
fn paragraph(&mut self, event: WalkEvent<&Paragraph>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Section` node
|
||||
fn section(&mut self, _event: WalkEvent<&Section>, _ctx: &mut TraversalContext);
|
||||
fn section(&mut self, event: WalkEvent<&Section>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Rule` node
|
||||
fn rule(&mut self, _event: WalkEvent<&Rule>, _ctx: &mut TraversalContext);
|
||||
fn rule(&mut self, event: WalkEvent<&Rule>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Comment` node
|
||||
fn comment(&mut self, _event: WalkEvent<&Comment>, _ctx: &mut TraversalContext);
|
||||
fn comment(&mut self, event: WalkEvent<&Comment>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `InlineSrc` node
|
||||
fn inline_src(&mut self, _event: WalkEvent<&InlineSrc>, _ctx: &mut TraversalContext);
|
||||
fn inline_src(&mut self, event: WalkEvent<&InlineSrc>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `InlineCall` node
|
||||
fn inline_call(&mut self, _event: WalkEvent<&InlineCall>, _ctx: &mut TraversalContext);
|
||||
fn inline_call(&mut self, event: WalkEvent<&InlineCall>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Code` node
|
||||
fn code(&mut self, _event: WalkEvent<&Code>, _ctx: &mut TraversalContext);
|
||||
fn code(&mut self, event: WalkEvent<&Code>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Bold` node
|
||||
fn bold(&mut self, _event: WalkEvent<&Bold>, _ctx: &mut TraversalContext);
|
||||
fn bold(&mut self, event: WalkEvent<&Bold>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Verbatim` node
|
||||
fn verbatim(&mut self, _event: WalkEvent<&Verbatim>, _ctx: &mut TraversalContext);
|
||||
fn verbatim(&mut self, event: WalkEvent<&Verbatim>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Italic` node
|
||||
fn italic(&mut self, _event: WalkEvent<&Italic>, _ctx: &mut TraversalContext);
|
||||
fn italic(&mut self, event: WalkEvent<&Italic>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Strike` node
|
||||
fn strike(&mut self, _event: WalkEvent<&Strike>, _ctx: &mut TraversalContext);
|
||||
fn strike(&mut self, event: WalkEvent<&Strike>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Underline` node
|
||||
fn underline(&mut self, _event: WalkEvent<&Underline>, _ctx: &mut TraversalContext);
|
||||
fn underline(&mut self, event: WalkEvent<&Underline>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `List` node
|
||||
fn list(&mut self, _event: WalkEvent<&List>, _ctx: &mut TraversalContext);
|
||||
fn list(&mut self, event: WalkEvent<&List>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `ListItem` node
|
||||
fn list_item(&mut self, _event: WalkEvent<&ListItem>, _ctx: &mut TraversalContext);
|
||||
fn list_item(&mut self, event: WalkEvent<&ListItem>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `SpecialBlock` node
|
||||
fn special_block(&mut self, _event: WalkEvent<&SpecialBlock>, _ctx: &mut TraversalContext);
|
||||
fn special_block(&mut self, event: WalkEvent<&SpecialBlock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `QuoteBlock` node
|
||||
fn quote_block(&mut self, _event: WalkEvent<&QuoteBlock>, _ctx: &mut TraversalContext);
|
||||
fn quote_block(&mut self, event: WalkEvent<&QuoteBlock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `CenterBlock` node
|
||||
fn center_block(&mut self, _event: WalkEvent<&CenterBlock>, _ctx: &mut TraversalContext);
|
||||
fn center_block(&mut self, event: WalkEvent<&CenterBlock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `VerseBlock` node
|
||||
fn verse_block(&mut self, _event: WalkEvent<&VerseBlock>, _ctx: &mut TraversalContext);
|
||||
fn verse_block(&mut self, event: WalkEvent<&VerseBlock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `CommentBlock` node
|
||||
fn comment_block(&mut self, _event: WalkEvent<&CommentBlock>, _ctx: &mut TraversalContext);
|
||||
fn comment_block(&mut self, event: WalkEvent<&CommentBlock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `ExampleBlock` node
|
||||
fn example_block(&mut self, _event: WalkEvent<&ExampleBlock>, _ctx: &mut TraversalContext);
|
||||
fn example_block(&mut self, event: WalkEvent<&ExampleBlock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `ExportBlock` node
|
||||
fn export_block(&mut self, _event: WalkEvent<&ExportBlock>, _ctx: &mut TraversalContext);
|
||||
fn export_block(&mut self, event: WalkEvent<&ExportBlock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `SourceBlock` node
|
||||
fn source_block(&mut self, _event: WalkEvent<&SourceBlock>, _ctx: &mut TraversalContext);
|
||||
fn source_block(&mut self, event: WalkEvent<&SourceBlock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `BabelCall` node
|
||||
fn babel_call(&mut self, _event: WalkEvent<&BabelCall>, _ctx: &mut TraversalContext);
|
||||
fn babel_call(&mut self, event: WalkEvent<&BabelCall>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Clock` node
|
||||
fn clock(&mut self, _event: WalkEvent<&Clock>, _ctx: &mut TraversalContext);
|
||||
fn clock(&mut self, event: WalkEvent<&Clock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Cookie` node
|
||||
fn cookie(&mut self, _event: WalkEvent<&Cookie>, _ctx: &mut TraversalContext);
|
||||
fn cookie(&mut self, event: WalkEvent<&Cookie>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `RadioTarget` node
|
||||
fn radio_target(&mut self, _event: WalkEvent<&RadioTarget>, _ctx: &mut TraversalContext);
|
||||
fn radio_target(&mut self, event: WalkEvent<&RadioTarget>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Drawer` node
|
||||
fn drawer(&mut self, _event: WalkEvent<&Drawer>, _ctx: &mut TraversalContext);
|
||||
fn drawer(&mut self, event: WalkEvent<&Drawer>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `DynBlock` node
|
||||
fn dyn_block(&mut self, _event: WalkEvent<&DynBlock>, _ctx: &mut TraversalContext);
|
||||
fn dyn_block(&mut self, event: WalkEvent<&DynBlock>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `FnDef` node
|
||||
fn fn_def(&mut self, _event: WalkEvent<&FnDef>, _ctx: &mut TraversalContext);
|
||||
fn fn_def(&mut self, event: WalkEvent<&FnDef>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `FnRef` node
|
||||
fn fn_ref(&mut self, _event: WalkEvent<&FnRef>, _ctx: &mut TraversalContext);
|
||||
fn fn_ref(&mut self, event: WalkEvent<&FnRef>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Macros` node
|
||||
fn macros(&mut self, _event: WalkEvent<&Macros>, _ctx: &mut TraversalContext);
|
||||
fn macros(&mut self, event: WalkEvent<&Macros>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Snippet` node
|
||||
fn snippet(&mut self, _event: WalkEvent<&Snippet>, _ctx: &mut TraversalContext);
|
||||
fn snippet(&mut self, event: WalkEvent<&Snippet>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Timestamp` node
|
||||
fn timestamp(&mut self, _event: WalkEvent<&Timestamp>, _ctx: &mut TraversalContext);
|
||||
fn timestamp(&mut self, event: WalkEvent<&Timestamp>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Target` node
|
||||
fn target(&mut self, _event: WalkEvent<&Target>, _ctx: &mut TraversalContext);
|
||||
fn target(&mut self, event: WalkEvent<&Target>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `FixedWidth` node
|
||||
fn fixed_width(&mut self, _event: WalkEvent<&FixedWidth>, _ctx: &mut TraversalContext);
|
||||
fn fixed_width(&mut self, event: WalkEvent<&FixedWidth>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `OrgTable` node
|
||||
fn org_table(&mut self, _event: WalkEvent<&OrgTable>, _ctx: &mut TraversalContext);
|
||||
fn org_table(&mut self, event: WalkEvent<&OrgTable>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `OrgTableRow` node
|
||||
fn org_table_row(&mut self, _event: WalkEvent<&OrgTableRow>, _ctx: &mut TraversalContext);
|
||||
fn org_table_row(&mut self, event: WalkEvent<&OrgTableRow>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `OrgTableCell` node
|
||||
fn org_table_cell(&mut self, _event: WalkEvent<&OrgTableCell>, _ctx: &mut TraversalContext);
|
||||
fn org_table_cell(&mut self, event: WalkEvent<&OrgTableCell>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `Link` node
|
||||
fn link(&mut self, _event: WalkEvent<&Link>, _ctx: &mut TraversalContext);
|
||||
fn link(&mut self, event: WalkEvent<&Link>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `LatexFragment` node
|
||||
fn latex_fragment(&mut self, _event: WalkEvent<&LatexFragment>, _ctx: &mut TraversalContext);
|
||||
fn latex_fragment(&mut self, event: WalkEvent<&LatexFragment>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `LatexEnvironment` node
|
||||
fn latex_environment(
|
||||
&mut self,
|
||||
_event: WalkEvent<&LatexEnvironment>,
|
||||
_ctx: &mut TraversalContext,
|
||||
event: WalkEvent<&LatexEnvironment>,
|
||||
ctx: &mut TraversalContext,
|
||||
);
|
||||
/// Called when entering or leaving `Entity` node
|
||||
fn entity(&mut self, _event: WalkEvent<&Entity>, _ctx: &mut TraversalContext);
|
||||
fn entity(&mut self, event: WalkEvent<&Entity>, ctx: &mut TraversalContext);
|
||||
/// Called when entering or leaving `LineBreak` node
|
||||
fn line_break(&mut self, event: WalkEvent<&LineBreak>, ctx: &mut TraversalContext);
|
||||
}
|
||||
|
|
|
|||
82
src/syntax/line_break.rs
Normal file
82
src/syntax/line_break.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
use nom::{
|
||||
branch::alt,
|
||||
character::complete::{line_ending, space0},
|
||||
combinator::{eof, map},
|
||||
sequence::tuple,
|
||||
IResult,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
syntax::combinator::{backslash_token, node},
|
||||
SyntaxKind,
|
||||
};
|
||||
|
||||
use super::{combinator::GreenElement, input::Input};
|
||||
|
||||
pub fn line_break_node(input: Input) -> IResult<Input, GreenElement, ()> {
|
||||
debug_assert!(input.s.starts_with('\\'));
|
||||
let mut parser = map(
|
||||
tuple((
|
||||
backslash_token,
|
||||
backslash_token,
|
||||
space0,
|
||||
alt((line_ending, eof)),
|
||||
)),
|
||||
|(b1, b2, ws, nl)| {
|
||||
node(
|
||||
SyntaxKind::LINE_BREAK,
|
||||
[b1, b2, ws.ws_token(), nl.nl_token()],
|
||||
)
|
||||
},
|
||||
);
|
||||
crate::lossless_parser!(parser, input)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse() {
|
||||
use crate::ast::LineBreak;
|
||||
use crate::tests::to_ast;
|
||||
|
||||
let to_line_break = to_ast::<LineBreak>(line_break_node);
|
||||
|
||||
insta::assert_debug_snapshot!(
|
||||
to_line_break("\\\\\n").syntax,
|
||||
@r###"
|
||||
LINE_BREAK@0..3
|
||||
BACKSLASH@0..1 "\\"
|
||||
BACKSLASH@1..2 "\\"
|
||||
WHITESPACE@2..2 ""
|
||||
NEW_LINE@2..3 "\n"
|
||||
"###
|
||||
);
|
||||
insta::assert_debug_snapshot!(
|
||||
to_line_break("\\\\ \n").syntax,
|
||||
@r###"
|
||||
LINE_BREAK@0..6
|
||||
BACKSLASH@0..1 "\\"
|
||||
BACKSLASH@1..2 "\\"
|
||||
WHITESPACE@2..5 " "
|
||||
NEW_LINE@5..6 "\n"
|
||||
"###
|
||||
);
|
||||
insta::assert_debug_snapshot!(
|
||||
to_line_break("\\\\\r\n").syntax,
|
||||
@r###"
|
||||
LINE_BREAK@0..4
|
||||
BACKSLASH@0..1 "\\"
|
||||
BACKSLASH@1..2 "\\"
|
||||
WHITESPACE@2..2 ""
|
||||
NEW_LINE@2..4 "\r\n"
|
||||
"###
|
||||
);
|
||||
insta::assert_debug_snapshot!(
|
||||
to_line_break("\\\\ ").syntax,
|
||||
@r###"
|
||||
LINE_BREAK@0..6
|
||||
BACKSLASH@0..1 "\\"
|
||||
BACKSLASH@1..2 "\\"
|
||||
WHITESPACE@2..6 " "
|
||||
NEW_LINE@6..6 ""
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ pub mod input;
|
|||
pub mod keyword;
|
||||
pub mod latex_environment;
|
||||
pub mod latex_fragment;
|
||||
pub mod line_break;
|
||||
pub mod link;
|
||||
pub mod list;
|
||||
pub mod macros;
|
||||
|
|
@ -184,6 +185,7 @@ pub enum SyntaxKind {
|
|||
INLINE_SRC,
|
||||
LINK,
|
||||
LINK_PATH,
|
||||
LINE_BREAK,
|
||||
COOKIE,
|
||||
RADIO_TARGET,
|
||||
FN_REF,
|
||||
|
|
@ -234,6 +236,7 @@ impl SyntaxKind {
|
|||
| SyntaxKind::FN_REF
|
||||
| SyntaxKind::INLINE_CALL
|
||||
| SyntaxKind::INLINE_SRC
|
||||
| SyntaxKind::LINE_BREAK
|
||||
| SyntaxKind::LINK
|
||||
| SyntaxKind::MACROS
|
||||
| SyntaxKind::RADIO_TARGET
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use super::{
|
|||
inline_src::inline_src_node,
|
||||
input::Input,
|
||||
latex_fragment::latex_fragment_node,
|
||||
line_break::line_break_node,
|
||||
link::link_node,
|
||||
macros::macros_node,
|
||||
radio_target::radio_target_node,
|
||||
|
|
@ -110,10 +111,10 @@ impl<'a> Iterator for ObjectPositions<'a> {
|
|||
/// - Statistics Cookies
|
||||
/// - Timestamps
|
||||
/// - Text Markup (bold code strike verbatim underline italic)
|
||||
/// - Line Breaks
|
||||
///
|
||||
/// // todo:
|
||||
/// - Citations
|
||||
/// - Line Breaks
|
||||
/// - Subscript and Superscript
|
||||
pub fn object_nodes(input: Input) -> Vec<GreenElement> {
|
||||
// TODO:
|
||||
|
|
@ -124,11 +125,6 @@ pub fn object_nodes(input: Input) -> Vec<GreenElement> {
|
|||
|
||||
'l: while !i.is_empty() {
|
||||
for (input, head) in ObjectPositions::standard(i) {
|
||||
debug_assert!(
|
||||
input.s.len() >= 2,
|
||||
"object must have at least two characters: {:?}",
|
||||
input.s
|
||||
);
|
||||
if let Ok((input, node)) = standard_object_node(input) {
|
||||
if !head.is_empty() {
|
||||
nodes.push(head.text_token())
|
||||
|
|
@ -170,11 +166,6 @@ pub fn minimal_object_nodes(input: Input) -> Vec<GreenElement> {
|
|||
|
||||
'l: while !i.is_empty() {
|
||||
for (input, head) in ObjectPositions::minimal(i) {
|
||||
debug_assert!(
|
||||
input.s.len() >= 2,
|
||||
"object must have at least two characters: {:?}",
|
||||
input.s
|
||||
);
|
||||
if let Ok((input, node)) = minimal_object_node(input) {
|
||||
if !head.is_empty() {
|
||||
nodes.push(head.text_token())
|
||||
|
|
@ -205,6 +196,12 @@ pub fn minimal_object_nodes(input: Input) -> Vec<GreenElement> {
|
|||
|
||||
/// parse an object from standard sets
|
||||
fn standard_object_node(i: Input) -> IResult<Input, GreenElement, ()> {
|
||||
debug_assert!(
|
||||
i.s.len() >= 2,
|
||||
"object must have at least two characters: {:?}",
|
||||
i.s
|
||||
);
|
||||
|
||||
match &i.as_bytes()[0] {
|
||||
b'*' => bold_node(i),
|
||||
b'+' => strike_node(i),
|
||||
|
|
@ -225,7 +222,13 @@ fn standard_object_node(i: Input) -> IResult<Input, GreenElement, ()> {
|
|||
b'c' => inline_call_node(i),
|
||||
b's' => inline_src_node(i),
|
||||
b'$' => latex_fragment_node(i),
|
||||
b'\\' => entity_node(i).or_else(|_| latex_fragment_node(i)),
|
||||
b'\\' => {
|
||||
if i.as_bytes()[1] == b'\\' {
|
||||
line_break_node(i)
|
||||
} else {
|
||||
entity_node(i).or_else(|_| latex_fragment_node(i))
|
||||
}
|
||||
}
|
||||
_ => Err(nom::Err::Error(())),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue