2023-04-22 02:33:10 +00:00
use nom ::branch ::alt ;
2023-04-22 02:36:21 +00:00
use nom ::bytes ::complete ::is_not ;
2023-04-22 02:33:10 +00:00
use nom ::bytes ::complete ::tag ;
2023-04-22 02:49:00 +00:00
use nom ::bytes ::complete ::tag_no_case ;
2023-08-29 21:01:35 +00:00
use nom ::bytes ::complete ::take_while1 ;
2023-08-29 20:56:07 +00:00
use nom ::character ::complete ::anychar ;
2023-04-22 02:33:10 +00:00
use nom ::character ::complete ::line_ending ;
2023-09-09 02:17:10 +00:00
use nom ::character ::complete ::one_of ;
2023-04-22 02:33:10 +00:00
use nom ::character ::complete ::space0 ;
2023-09-04 23:17:23 +00:00
use nom ::combinator ::consumed ;
2023-04-22 02:33:10 +00:00
use nom ::combinator ::eof ;
2023-04-22 02:49:00 +00:00
use nom ::combinator ::not ;
use nom ::combinator ::peek ;
2023-04-22 02:33:10 +00:00
use nom ::combinator ::recognize ;
2023-08-29 20:56:07 +00:00
use nom ::multi ::many_till ;
2023-04-22 02:33:10 +00:00
use nom ::sequence ::tuple ;
2023-08-29 20:56:07 +00:00
use super ::org_source ::BracketDepth ;
2023-08-23 04:30:26 +00:00
use super ::org_source ::OrgSource ;
2023-09-04 23:17:23 +00:00
use crate ::context ::Matcher ;
2023-09-03 16:23:18 +00:00
use crate ::context ::RefContext ;
2023-08-29 20:56:07 +00:00
use crate ::error ::CustomError ;
use crate ::error ::MyError ;
2023-04-22 02:33:10 +00:00
use crate ::error ::Res ;
use crate ::parser ::util ::start_of_line ;
2023-09-03 16:23:18 +00:00
use crate ::types ::Keyword ;
2023-04-22 02:33:10 +00:00
2023-08-29 20:56:07 +00:00
const ORG_ELEMENT_AFFILIATED_KEYWORDS : [ & 'static str ; 13 ] = [
2023-09-06 21:26:10 +00:00
" caption " , " data " , " headers " , " header " , " label " , " name " , " plot " , " resname " , " results " ,
" result " , " source " , " srcname " , " tblname " ,
2023-08-29 20:56:07 +00:00
] ;
const ORG_ELEMENT_DUAL_KEYWORDS : [ & 'static str ; 2 ] = [ " caption " , " results " ] ;
2023-09-04 23:17:23 +00:00
pub fn filtered_keyword < F : Matcher > (
key_parser : F ,
) -> impl for < ' s > Fn ( OrgSource < ' s > ) -> Res < OrgSource < ' s > , Keyword < ' s > > {
move | input | _filtered_keyword ( & key_parser , input )
}
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( key_parser ) )
) ]
fn _filtered_keyword < ' s , F : Matcher > (
key_parser : F ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Keyword < ' s > > {
2023-08-24 23:29:00 +00:00
start_of_line ( input ) ? ;
2023-04-22 02:36:21 +00:00
// TODO: When key is a member of org-element-parsed-keywords, value can contain the standard set objects, excluding footnote references.
2023-09-05 01:46:40 +00:00
let ( remaining , ( consumed_input , ( _ , _ , parsed_key , _ ) ) ) =
consumed ( tuple ( ( space0 , tag ( " #+ " ) , key_parser , tag ( " : " ) ) ) ) ( input ) ? ;
2023-09-05 02:15:43 +00:00
match tuple ( (
space0 ::< OrgSource < '_ > , CustomError < OrgSource < '_ > > > ,
alt ( ( line_ending , eof ) ) ,
) ) ( remaining )
{
2023-09-05 01:46:40 +00:00
Ok ( ( remaining , _ ) ) = > {
return Ok ( (
remaining ,
Keyword {
source : consumed_input . into ( ) ,
key : parsed_key . into ( ) ,
value : " " . into ( ) ,
} ,
) ) ;
}
2023-09-05 02:15:43 +00:00
Err ( _ ) = > { }
2023-09-05 01:46:40 +00:00
} ;
2023-09-09 02:17:10 +00:00
let ( remaining , _ws ) = space0 ( remaining ) ? ;
2023-09-05 02:15:43 +00:00
let ( remaining , parsed_value ) = recognize ( many_till (
anychar ,
peek ( tuple ( ( space0 , alt ( ( line_ending , eof ) ) ) ) ) ,
) ) ( remaining ) ? ;
2023-09-05 01:46:40 +00:00
let ( remaining , _ws ) = tuple ( ( space0 , alt ( ( line_ending , eof ) ) ) ) ( remaining ) ? ;
2023-08-23 04:30:26 +00:00
Ok ( (
remaining ,
Keyword {
2023-09-04 23:17:23 +00:00
source : consumed_input . into ( ) ,
key : parsed_key . into ( ) ,
value : parsed_value . into ( ) ,
2023-08-23 04:30:26 +00:00
} ,
) )
2023-04-22 02:33:10 +00:00
}
2023-08-29 20:56:07 +00:00
2023-09-04 23:17:23 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
pub fn keyword < ' b , ' g , ' r , ' s > (
_context : RefContext < ' b , ' g , ' r , ' s > ,
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Keyword < ' s > > {
filtered_keyword ( regular_keyword_key ) ( input )
}
2023-08-29 20:56:07 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-09-03 19:44:18 +00:00
pub fn affiliated_keyword < ' b , ' g , ' r , ' s > (
_context : RefContext < ' b , ' g , ' r , ' s > ,
2023-08-29 20:56:07 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Keyword < ' s > > {
2023-09-04 23:17:23 +00:00
filtered_keyword ( affiliated_key ) ( input )
}
2023-08-29 20:56:07 +00:00
2023-09-06 22:04:53 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
pub fn babel_call_keyword < ' b , ' g , ' r , ' s > (
_context : RefContext < ' b , ' g , ' r , ' s > ,
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Keyword < ' s > > {
filtered_keyword ( babel_call_key ) ( input )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn babel_call_key < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
tag_no_case ( " call " ) ( input )
}
2023-09-04 23:17:23 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn regular_keyword_key < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-09-09 02:17:10 +00:00
not ( peek ( alt ( ( tag_no_case ( " call " ) , tag_no_case ( " begin " ) ) ) ) ) ( input ) ? ;
recognize ( many_till (
anychar ,
peek ( alt ( (
recognize ( one_of ( " \t \r \n " ) ) , // Give up if we hit whitespace
recognize ( tuple ( ( tag ( " : " ) , one_of ( " \t \r \n " ) ) ) ) , // Stop if we see a colon followed by whitespace
recognize ( tuple ( ( tag ( " : " ) , is_not ( " \t \r \n : " ) , not ( tag ( " : " ) ) ) ) ) , // Stop if we see a colon that is the last colon before whitespace. This is for keywords like "#+foo:bar:baz: lorem: ipsum" which would have the key "foo:bar:baz".
) ) ) ,
) ) ( input )
2023-08-29 20:56:07 +00:00
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn affiliated_key < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
alt ( (
recognize ( tuple ( ( dual_affiliated_key , tag ( " [ " ) , optval , tag ( " ] " ) ) ) ) ,
plain_affiliated_key ,
2023-08-29 21:19:13 +00:00
export_keyword ,
2023-08-29 20:56:07 +00:00
) ) ( input )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn plain_affiliated_key < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
for keyword in ORG_ELEMENT_AFFILIATED_KEYWORDS {
let result = tag_no_case ::< _ , _ , CustomError < _ > > ( keyword ) ( input ) ;
match result {
Ok ( ( remaining , ent ) ) = > {
return Ok ( ( remaining , ent ) ) ;
}
Err ( _ ) = > { }
}
}
Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
" NoKeywordKey " . into ( ) ,
) ) ) )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn dual_affiliated_key < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
for keyword in ORG_ELEMENT_DUAL_KEYWORDS {
let result = tag_no_case ::< _ , _ , CustomError < _ > > ( keyword ) ( input ) ;
match result {
Ok ( ( remaining , ent ) ) = > {
return Ok ( ( remaining , ent ) ) ;
}
Err ( _ ) = > { }
}
}
Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
" NoKeywordKey " . into ( ) ,
) ) ) )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn optval < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
recognize ( many_till (
anychar ,
peek ( optval_end ( input . get_bracket_depth ( ) ) ) ,
) ) ( input )
}
const fn optval_end (
starting_bracket_depth : BracketDepth ,
) -> impl for < ' s > Fn ( OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
move | input : OrgSource < '_ > | _optval_end ( input , starting_bracket_depth )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn _optval_end < ' s > (
input : OrgSource < ' s > ,
starting_bracket_depth : BracketDepth ,
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
let current_depth = input . get_bracket_depth ( ) - starting_bracket_depth ;
if current_depth < 0 {
// This shouldn't be possible because if depth is 0 then a closing bracket should end the opval.
unreachable! ( " Exceeded optval bracket depth. " )
}
if current_depth = = 0 {
2023-08-29 21:19:13 +00:00
let close_bracket = tag ::< _ , _ , CustomError < _ > > ( " ] " ) ( input ) ;
2023-08-29 20:56:07 +00:00
if close_bracket . is_ok ( ) {
return close_bracket ;
}
}
tag ( " \n " ) ( input )
}
2023-08-29 21:01:35 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn export_keyword < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-08-29 21:19:13 +00:00
recognize ( tuple ( (
tag_no_case ( " attr_ " ) ,
take_while1 ( | c : char | c . is_alphanumeric ( ) | | " -_ " . contains ( c ) ) ,
) ) ) ( input )
2023-08-29 21:01:35 +00:00
}