2023-07-18 20:51:06 -04:00
use nom ::branch ::alt ;
use nom ::bytes ::complete ::tag ;
2023-07-18 21:50:29 -04:00
use nom ::character ::complete ::alpha1 ;
use nom ::character ::complete ::anychar ;
use nom ::character ::complete ::line_ending ;
2023-07-18 22:21:52 -04:00
use nom ::character ::complete ::none_of ;
2023-07-18 21:50:29 -04:00
use nom ::character ::complete ::one_of ;
2023-07-18 20:51:06 -04:00
use nom ::character ::complete ::space0 ;
2023-07-18 21:50:29 -04:00
use nom ::combinator ::opt ;
2023-07-18 20:51:06 -04:00
use nom ::combinator ::peek ;
use nom ::combinator ::recognize ;
2023-07-18 22:21:52 -04:00
use nom ::combinator ::verify ;
2023-07-18 21:50:29 -04:00
use nom ::multi ::many_till ;
use nom ::sequence ::tuple ;
2023-07-18 20:51:06 -04:00
use super ::Context ;
2023-07-18 22:21:52 -04:00
use crate ::error ::CustomError ;
use crate ::error ::MyError ;
2023-07-18 20:51:06 -04:00
use crate ::error ::Res ;
use crate ::parser ::parser_with_context ::parser_with_context ;
2023-07-18 21:50:29 -04:00
use crate ::parser ::util ::exit_matcher_parser ;
2023-07-18 20:51:06 -04:00
use crate ::parser ::util ::get_consumed ;
2023-07-18 22:21:52 -04:00
use crate ::parser ::util ::get_one_before ;
2023-07-18 20:51:06 -04:00
use crate ::parser ::LatexFragment ;
#[ tracing::instrument(ret, level = " debug " ) ]
pub fn latex_fragment < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , LatexFragment < ' s > > {
2023-07-18 22:02:38 -04:00
let ( remaining , _ ) = alt ( (
parser_with_context! ( raw_latex_fragment ) ( context ) ,
parser_with_context! ( escaped_parenthesis_fragment ) ( context ) ,
parser_with_context! ( escaped_bracket_fragment ) ( context ) ,
2023-07-18 22:21:52 -04:00
parser_with_context! ( double_dollar_fragment ) ( context ) ,
parser_with_context! ( dollar_char_fragment ) ( context ) ,
2023-07-18 22:39:05 -04:00
parser_with_context! ( bordered_dollar_fragment ) ( context ) ,
2023-07-18 22:02:38 -04:00
) ) ( input ) ? ;
2023-07-18 21:50:29 -04:00
let ( remaining , _ ) = space0 ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , LatexFragment { source } ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn raw_latex_fragment < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
2023-07-18 20:51:06 -04:00
let ( remaining , _ ) = tag ( " \\ " ) ( input ) ? ;
2023-07-18 21:50:29 -04:00
let ( remaining , _ ) = name ( context , remaining ) ? ;
let ( remaining , _ ) = opt ( parser_with_context! ( brackets ) ( context ) ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
2023-07-18 20:51:06 -04:00
2023-07-18 21:50:29 -04:00
#[ tracing::instrument(ret, level = " debug " ) ]
fn name < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
alpha1 ( input )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn brackets < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
let ( remaining , body ) = alt ( (
recognize ( tuple ( (
tag ( " [ " ) ,
many_till (
anychar ,
peek ( alt ( (
parser_with_context! ( exit_matcher_parser ) ( context ) ,
alt ( ( recognize ( one_of ( " {}[] " ) ) , line_ending ) ) ,
) ) ) ,
) ,
tag ( " ] " ) ,
) ) ) ,
recognize ( tuple ( (
tag ( " { " ) ,
many_till (
anychar ,
peek ( alt ( (
parser_with_context! ( exit_matcher_parser ) ( context ) ,
alt ( ( recognize ( one_of ( " {} " ) ) , line_ending ) ) ,
) ) ) ,
) ,
tag ( " } " ) ,
) ) ) ,
) ) ( input ) ? ;
Ok ( ( remaining , body ) )
2023-07-18 20:51:06 -04:00
}
2023-07-18 22:02:38 -04:00
#[ tracing::instrument(ret, level = " debug " ) ]
fn escaped_parenthesis_fragment < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , & ' s str > {
let ( remaining , _ ) = tag ( " \\ ( " ) ( input ) ? ;
let ( remaining , _ ) = recognize ( many_till (
anychar ,
peek ( alt ( (
parser_with_context! ( exit_matcher_parser ) ( context ) ,
tag ( " \\ ) " ) ,
) ) ) ,
) ) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " \\ ) " ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn escaped_bracket_fragment < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , & ' s str > {
let ( remaining , _ ) = tag ( " \\ [ " ) ( input ) ? ;
let ( remaining , _ ) = recognize ( many_till (
anychar ,
peek ( alt ( (
parser_with_context! ( exit_matcher_parser ) ( context ) ,
tag ( " \\ ] " ) ,
) ) ) ,
) ) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " \\ ] " ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
2023-07-18 22:21:52 -04:00
#[ tracing::instrument(ret, level = " debug " ) ]
fn double_dollar_fragment < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , & ' s str > {
// TODO: The documentation on the dollar sign versions is incomplete. Test to figure out what the real requirements are. For example, can this span more than 3 lines and can this contain a single $ since its terminated by $$?
let ( remaining , _ ) = tag ( " $$ " ) ( input ) ? ;
let ( remaining , _ ) = recognize ( many_till (
anychar ,
peek ( alt ( (
parser_with_context! ( exit_matcher_parser ) ( context ) ,
tag ( " $ " ) ,
) ) ) ,
) ) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " $$ " ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn dollar_char_fragment < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
let ( _ , _ ) = pre ( context , input ) ? ;
let ( remaining , _ ) = tag ( " $ " ) ( input ) ? ;
let ( remaining , _ ) = verify ( none_of ( " .,?; \" " ) , | c | ! c . is_whitespace ( ) ) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " $ " ) ( remaining ) ? ;
let ( _ , _ ) = peek ( parser_with_context! ( post ) ( context ) ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
pub fn pre < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , ( ) > {
let document_root = context . get_document_root ( ) . unwrap ( ) ;
let preceding_character = get_one_before ( document_root , input )
. map ( | slice | slice . chars ( ) . next ( ) )
. flatten ( ) ;
if let Some ( '$' ) = preceding_character {
return Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
" Not a valid pre character for dollar char fragment. " ,
) ) ) ) ;
}
Ok ( ( input , ( ) ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
pub fn post < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , ( ) > {
// TODO: What about eof? Test to find out.
// TODO: Figure out which punctuation characters should be included.
let ( remaining , _ ) = alt ( ( recognize ( one_of ( " \t -.,;:!?' \" " ) ) , line_ending ) ) ( input ) ? ;
Ok ( ( remaining , ( ) ) )
}
2023-07-18 22:39:05 -04:00
#[ tracing::instrument(ret, level = " debug " ) ]
fn bordered_dollar_fragment < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , & ' s str > {
let ( _ , _ ) = pre ( context , input ) ? ;
let ( remaining , _ ) = tag ( " $ " ) ( input ) ? ;
// TODO: I'm assuming I should be peeking at the borders but the documentation is not clear. Test to figure out.
let ( _ , _ ) = peek ( parser_with_context! ( open_border ) ( context ) ) ( remaining ) ? ;
// TODO: As an optimization it would be nice to exit early upon hitting the 3rd line break
let ( remaining , _ ) = verify (
recognize ( many_till (
anychar ,
peek ( alt ( (
parser_with_context! ( exit_matcher_parser ) ( context ) ,
tag ( " $ " ) ,
) ) ) ,
) ) ,
| body : & str | body . lines ( ) . take ( 4 ) . count ( ) < = 3 ,
) ( remaining ) ? ;
let ( _ , _ ) = peek ( parser_with_context! ( close_border ) ( context ) ) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " $ " ) ( remaining ) ? ;
let ( _ , _ ) = peek ( parser_with_context! ( post ) ( context ) ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
pub fn open_border < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
recognize ( verify ( none_of ( " .,;$ " ) , | c | ! c . is_whitespace ( ) ) ) ( input )
}
#[ tracing::instrument(ret, level = " debug " ) ]
pub fn close_border < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , ( ) > {
let document_root = context . get_document_root ( ) . unwrap ( ) ;
let preceding_character = get_one_before ( document_root , input )
. map ( | slice | slice . chars ( ) . next ( ) )
. flatten ( ) ;
match preceding_character {
Some ( c ) if ! c . is_whitespace ( ) & & ! " .,;$ " . contains ( c ) = > Ok ( ( input , ( ) ) ) ,
_ = > {
return Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
" Not a valid pre character for dollar char fragment. " ,
) ) ) ) ;
}
}
}