2023-10-05 16:32:40 -04:00
use nom ::branch ::alt ;
2023-10-05 16:27:36 -04:00
use nom ::bytes ::complete ::tag ;
use nom ::bytes ::complete ::tag_no_case ;
use nom ::character ::complete ::anychar ;
2023-10-05 16:32:40 -04:00
use nom ::character ::complete ::one_of ;
2023-10-05 16:27:36 -04:00
use nom ::character ::complete ::space0 ;
2023-10-05 16:32:40 -04:00
use nom ::combinator ::opt ;
2023-10-05 16:27:36 -04:00
use nom ::combinator ::peek ;
use nom ::combinator ::recognize ;
2023-10-05 16:32:40 -04:00
use nom ::combinator ::verify ;
2023-10-05 16:27:36 -04:00
use nom ::multi ::many_till ;
use nom ::sequence ::tuple ;
use nom ::InputTake ;
2023-10-11 14:44:25 -04:00
use super ::affiliated_keyword ::parse_affiliated_keywords ;
2023-10-05 19:19:27 -04:00
use super ::org_source ::BracketDepth ;
2023-10-06 11:45:15 -04:00
use super ::util ::maybe_consume_trailing_whitespace_if_not_exiting ;
2023-10-05 16:32:40 -04:00
use super ::util ::start_of_line ;
2023-10-05 16:27:36 -04:00
use super ::OrgSource ;
2023-10-05 19:19:27 -04:00
use crate ::context ::Matcher ;
2023-10-05 16:27:36 -04:00
use crate ::context ::RefContext ;
2023-10-05 19:19:27 -04:00
use crate ::error ::CustomError ;
2023-10-05 16:27:36 -04:00
use crate ::error ::Res ;
use crate ::parser ::util ::get_consumed ;
use crate ::parser ::util ::org_line_ending ;
use crate ::types ::BabelCall ;
2023-10-12 17:12:55 -04:00
use crate ::types ::Keyword ;
2023-10-05 16:27:36 -04:00
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
2023-10-14 19:02:35 -04:00
tracing ::instrument ( ret , level = " debug " , skip ( context , affiliated_keywords ) )
2023-10-09 18:00:48 -04:00
) ]
2023-10-12 17:12:55 -04:00
pub ( crate ) fn babel_call < ' b , ' g , ' r , ' s , AK > (
affiliated_keywords : AK ,
remaining : OrgSource < ' s > ,
2023-10-06 11:45:15 -04:00
context : RefContext < ' b , ' g , ' r , ' s > ,
2023-10-05 16:27:36 -04:00
input : OrgSource < ' s > ,
2023-10-12 17:12:55 -04:00
) -> Res < OrgSource < ' s > , BabelCall < ' s > >
where
AK : IntoIterator < Item = Keyword < ' s > > ,
{
2023-10-06 11:45:15 -04:00
start_of_line ( remaining ) ? ;
let ( remaining , _ ) = tuple ( ( space0 , tag ( " #+ " ) , tag_no_case ( " call " ) , tag ( " : " ) ) ) ( remaining ) ? ;
2023-10-05 16:27:36 -04:00
let ( remaining , _ws ) = space0 ( remaining ) ? ;
2023-12-15 10:16:33 -05:00
let ( remaining , babel_call_value ) = babel_call_value ( remaining ) ? ;
2023-10-05 16:27:36 -04:00
2023-12-15 10:16:33 -05:00
let ( remaining , post_blank ) =
2023-10-06 11:45:15 -04:00
maybe_consume_trailing_whitespace_if_not_exiting ( context , remaining ) ? ;
2023-10-05 16:27:36 -04:00
let source = get_consumed ( input , remaining ) ;
Ok ( (
remaining ,
BabelCall {
source : Into ::< & str > ::into ( source ) ,
2023-10-11 14:44:25 -04:00
affiliated_keywords : parse_affiliated_keywords (
context . get_global_settings ( ) ,
affiliated_keywords ,
) ,
2023-12-15 10:16:33 -05:00
value : Into ::< & str > ::into ( babel_call_value . value ) ,
2023-10-16 18:29:21 -04:00
call : babel_call_value . call . map ( Into ::< & str > ::into ) ,
inside_header : babel_call_value . inside_header . map ( Into ::< & str > ::into ) ,
arguments : babel_call_value . arguments . map ( Into ::< & str > ::into ) ,
end_header : babel_call_value . end_header . map ( Into ::< & str > ::into ) ,
2023-12-15 10:16:33 -05:00
post_blank : post_blank . map ( Into ::< & str > ::into ) ,
2023-10-05 16:27:36 -04:00
} ,
) )
}
2023-10-05 16:32:40 -04:00
2023-10-16 18:29:21 -04:00
#[ derive(Debug) ]
struct BabelCallValue < ' s > {
2023-12-15 10:16:33 -05:00
/// The entire string to the right of "#+call: " without the trailing line break.
value : OrgSource < ' s > ,
/// The function name which may contain a line break if there are no headers/arguments.
2023-10-16 18:29:21 -04:00
call : Option < OrgSource < ' s > > ,
inside_header : Option < OrgSource < ' s > > ,
arguments : Option < OrgSource < ' s > > ,
end_header : Option < OrgSource < ' s > > ,
}
2023-10-05 16:32:40 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-10-16 18:29:21 -04:00
fn babel_call_value < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , BabelCallValue < ' s > > {
2023-12-15 10:16:33 -05:00
alt ( (
babel_call_value_without_headers ,
babel_call_value_with_headers ,
) ) ( input )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn babel_call_value_without_headers < ' s > (
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , BabelCallValue < ' s > > {
let ( remaining , value ) = babel_call_call_with_headers ( input ) ? ;
let ( remaining , _ws ) = tuple ( ( space0 , org_line_ending ) ) ( remaining ) ? ;
let call = get_consumed ( input , remaining ) ;
Ok ( (
remaining ,
BabelCallValue {
value ,
call : Some ( call ) ,
inside_header : None ,
arguments : None ,
end_header : None ,
} ,
) )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn babel_call_value_with_headers < ' s > (
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , BabelCallValue < ' s > > {
let ( remaining , call ) = opt ( babel_call_call_with_headers ) ( input ) ? ;
2023-10-05 16:32:40 -04:00
let ( remaining , inside_header ) = opt ( inside_header ) ( remaining ) ? ;
let ( remaining , arguments ) = opt ( arguments ) ( remaining ) ? ;
let ( remaining , end_header ) = opt ( end_header ) ( remaining ) ? ;
2023-12-15 10:16:33 -05:00
let value = get_consumed ( input , remaining ) ;
let ( remaining , _ws ) = tuple ( ( space0 , org_line_ending ) ) ( remaining ) ? ;
2023-10-05 16:32:40 -04:00
Ok ( (
remaining ,
2023-10-16 18:29:21 -04:00
BabelCallValue {
2023-12-15 10:16:33 -05:00
value ,
2023-10-16 18:29:21 -04:00
call ,
inside_header ,
arguments : arguments . flatten ( ) ,
end_header ,
} ,
2023-10-05 16:32:40 -04:00
) )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-12-15 10:16:33 -05:00
fn babel_call_call_with_headers < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
// When babel call contains no arguments or headers (for example: "#+call: lorem ipsum\n") then the trailing line break is part of the call. Otherwise, it is not.
2023-10-05 16:32:40 -04:00
verify (
recognize ( many_till (
anychar ,
2023-12-15 10:16:33 -05:00
peek ( alt ( (
recognize ( one_of ( " [( " ) ) ,
2023-10-05 16:32:40 -04:00
recognize ( tuple ( ( space0 , org_line_ending ) ) ) ,
2023-12-15 10:16:33 -05:00
) ) ) ,
2023-10-05 16:32:40 -04:00
) ) ,
| s | s . len ( ) > 0 ,
) ( input )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn inside_header < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-10-05 19:49:07 -04:00
let ( remaining , contents ) = balanced_bracket (
| i | tag ( " [ " ) ( i ) ,
| i | peek ( tag ( " ] " ) ) ( i ) ,
| i | recognize ( tuple ( ( space0 , org_line_ending ) ) ) ( i ) ,
| i | tag ( " ] " ) ( i ) ,
| s | s . get_bracket_depth ( ) ,
) ( input ) ? ;
let ( contents_start , _ ) = tag ( " [ " ) ( input ) ? ;
2023-10-05 16:32:40 -04:00
Ok ( ( remaining , contents . unwrap_or ( contents_start . take ( 0 ) ) ) )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn arguments < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , Option < OrgSource < ' s > > > {
2023-10-05 19:19:27 -04:00
balanced_bracket (
| i | tag ( " ( " ) ( i ) ,
| i | peek ( tag ( " ) " ) ) ( i ) ,
| i | recognize ( tuple ( ( space0 , org_line_ending ) ) ) ( i ) ,
| i | tag ( " ) " ) ( i ) ,
| s | s . get_parenthesis_depth ( ) ,
) ( input )
2023-10-05 16:32:40 -04:00
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn end_header < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
let ( remaining , _ ) = space0 ( input ) ? ;
verify (
recognize ( many_till ( anychar , peek ( tuple ( ( space0 , org_line_ending ) ) ) ) ) ,
| s | s . len ( ) > 0 ,
) ( remaining )
}
2023-10-05 19:19:27 -04:00
fn balanced_bracket <
O : Matcher ,
S : Matcher ,
F : Matcher ,
E : Matcher ,
D : for < ' ss > Fn ( OrgSource < ' ss > ) -> BracketDepth ,
> (
opening_parser : O ,
stop_parser : S ,
fail_parser : F ,
end_parser : E ,
depth_function : D ,
) -> impl for < ' s > Fn ( OrgSource < ' s > ) -> Res < OrgSource < ' s > , Option < OrgSource < ' s > > > {
move | input | {
impl_balanced_bracket ::< & O , & S , & F , & E , & D > (
input ,
& opening_parser ,
& stop_parser ,
& fail_parser ,
& end_parser ,
& depth_function ,
)
}
}
fn impl_balanced_bracket <
' s ,
O : Matcher ,
S : Matcher ,
F : Matcher ,
E : Matcher ,
D : for < ' ss > Fn ( OrgSource < ' ss > ) -> BracketDepth ,
> (
input : OrgSource < ' s > ,
opening_parser : O ,
stop_parser : S ,
fail_parser : F ,
end_parser : E ,
depth_function : D ,
) -> Res < OrgSource < ' s > , Option < OrgSource < ' s > > > {
let ( mut remaining , _ ) = opening_parser ( input ) ? ;
let contents_start = remaining ;
let original_depth = depth_function ( remaining ) ;
loop {
let bracket_depth = depth_function ( remaining ) ;
if bracket_depth = = original_depth {
let ( remain , stop_result ) = opt ( & stop_parser ) ( remaining ) ? ;
remaining = remain ;
if stop_result . is_some ( ) {
break ;
}
}
if fail_parser ( remaining ) . is_ok ( ) {
2023-10-17 10:09:37 -04:00
return Err ( nom ::Err ::Error ( CustomError ::Static ( " Fail parser matched. " ) ) ) ;
2023-10-05 19:19:27 -04:00
}
let ( remain , _ ) = anychar ( remaining ) ? ;
remaining = remain ;
}
let contents_end = remaining ;
let ( remaining , _ ) = end_parser ( remaining ) ? ;
2023-10-31 16:25:52 -04:00
let contents = if Into ::< & str > ::into ( contents_start ) ! = Into ::< & str > ::into ( contents_end ) {
2023-10-05 19:19:27 -04:00
Some ( contents_start . get_until ( contents_end ) )
} else {
None
} ;
Ok ( ( remaining , contents ) )
}