2023-07-19 20:52:09 -04:00
use nom ::branch ::alt ;
use nom ::bytes ::complete ::tag ;
use nom ::bytes ::complete ::tag_no_case ;
2023-07-19 23:40:26 -04:00
use nom ::character ::complete ::space0 ;
2023-07-19 21:14:09 -04:00
use nom ::combinator ::verify ;
use nom ::multi ::many_till ;
2023-07-19 20:52:09 -04:00
use super ::parser_context ::ContextElement ;
2023-07-19 18:56:46 -04:00
use super ::Context ;
2023-07-19 20:52:09 -04:00
use crate ::error ::CustomError ;
use crate ::error ::MyError ;
2023-07-19 18:56:46 -04:00
use crate ::error ::Res ;
2023-07-19 23:40:26 -04:00
use crate ::parser ::exiting ::ExitClass ;
2023-07-19 21:32:08 -04:00
use crate ::parser ::footnote_definition ::label ;
2023-07-19 21:14:09 -04:00
use crate ::parser ::object_parser ::standard_set_object ;
2023-07-19 23:40:26 -04:00
use crate ::parser ::parser_context ::ExitMatcherNode ;
2023-07-19 20:52:09 -04:00
use crate ::parser ::parser_context ::FootnoteReferenceDefinition ;
use crate ::parser ::parser_with_context ::parser_with_context ;
2023-07-19 21:14:09 -04:00
use crate ::parser ::util ::exit_matcher_parser ;
2023-07-19 20:52:09 -04:00
use crate ::parser ::util ::get_consumed ;
use crate ::parser ::FootnoteReference ;
use crate ::parser ::Object ;
2023-07-19 18:56:46 -04:00
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-19 18:56:46 -04:00
pub fn footnote_reference < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , FootnoteReference < ' s > > {
2023-07-19 23:40:26 -04:00
alt ( (
parser_with_context! ( anonymous_footnote ) ( context ) ,
parser_with_context! ( footnote_reference_only ) ( context ) ,
parser_with_context! ( inline_footnote ) ( context ) ,
) ) ( input )
2023-07-19 20:52:09 -04:00
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-19 21:32:08 -04:00
fn anonymous_footnote < ' r , ' s > (
2023-07-19 20:52:09 -04:00
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , FootnoteReference < ' s > > {
let ( remaining , _ ) = tag_no_case ( " [fn:: " ) ( input ) ? ;
2023-07-19 23:40:26 -04:00
let parser_context = context
. with_additional_node ( ContextElement ::FootnoteReferenceDefinition (
FootnoteReferenceDefinition {
position : remaining ,
depth : 0 ,
} ,
) )
. with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Beta ,
exit_matcher : & footnote_definition_end ,
} ) ) ;
2023-07-19 23:20:17 -04:00
// TODO: I could insert FootnoteReferenceDefinition entries in the context after each matched object to reduce the scanning done for counting brackets which should be more efficient.
2023-07-19 21:14:09 -04:00
let ( remaining , ( children , _exit_contents ) ) = verify (
many_till (
parser_with_context! ( standard_set_object ) ( & parser_context ) ,
parser_with_context! ( exit_matcher_parser ) ( & parser_context ) ,
) ,
2023-07-19 23:40:26 -04:00
| ( children , _exit_contents ) | ! children . is_empty ( ) ,
2023-07-19 21:14:09 -04:00
) ( remaining ) ? ;
2023-07-19 23:40:26 -04:00
let ( remaining , _ ) = tag ( " ] " ) ( remaining ) ? ;
2023-07-19 20:52:09 -04:00
2023-07-19 23:40:26 -04:00
let ( remaining , _ ) = space0 ( remaining ) ? ;
2023-07-19 21:14:09 -04:00
let source = get_consumed ( input , remaining ) ;
Ok ( (
remaining ,
FootnoteReference {
source ,
label : None ,
definition : children ,
} ,
) )
2023-07-19 18:56:46 -04:00
}
2023-07-19 20:52:09 -04:00
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-19 21:32:08 -04:00
fn inline_footnote < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , FootnoteReference < ' s > > {
2023-07-19 23:20:17 -04:00
let ( remaining , _ ) = tag_no_case ( " [fn: " ) ( input ) ? ;
let ( remaining , label_contents ) = label ( remaining ) ? ;
let ( remaining , _ ) = tag ( " : " ) ( remaining ) ? ;
2023-07-19 23:40:26 -04:00
let parser_context = context
. with_additional_node ( ContextElement ::FootnoteReferenceDefinition (
FootnoteReferenceDefinition {
position : remaining ,
depth : 0 ,
} ,
) )
. with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Beta ,
exit_matcher : & footnote_definition_end ,
} ) ) ;
2023-07-19 23:20:17 -04:00
// TODO: I could insert FootnoteReferenceDefinition entries in the context after each matched object to reduce the scanning done for counting brackets which should be more efficient.
let ( remaining , ( children , _exit_contents ) ) = verify (
many_till (
parser_with_context! ( standard_set_object ) ( & parser_context ) ,
parser_with_context! ( exit_matcher_parser ) ( & parser_context ) ,
) ,
2023-07-19 23:40:26 -04:00
| ( children , _exit_contents ) | ! children . is_empty ( ) ,
2023-07-19 23:20:17 -04:00
) ( remaining ) ? ;
2023-07-19 23:40:26 -04:00
let ( remaining , _ ) = tag ( " ] " ) ( remaining ) ? ;
2023-07-19 23:20:17 -04:00
2023-07-19 23:40:26 -04:00
let ( remaining , _ ) = space0 ( remaining ) ? ;
2023-07-19 23:20:17 -04:00
let source = get_consumed ( input , remaining ) ;
Ok ( (
remaining ,
FootnoteReference {
source ,
label : Some ( label_contents ) ,
definition : children ,
} ,
) )
2023-07-19 21:32:08 -04:00
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-19 21:32:08 -04:00
fn footnote_reference_only < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , FootnoteReference < ' s > > {
let ( remaining , _ ) = tag_no_case ( " [fn: " ) ( input ) ? ;
let ( remaining , label_contents ) = label ( remaining ) ? ;
let ( remaining , _ ) = tag ( " ] " ) ( remaining ) ? ;
2023-07-19 23:40:26 -04:00
let ( remaining , _ ) = space0 ( remaining ) ? ;
2023-07-19 21:32:08 -04:00
let source = get_consumed ( input , remaining ) ;
Ok ( (
remaining ,
FootnoteReference {
source ,
label : Some ( label_contents ) ,
definition : Vec ::with_capacity ( 0 ) ,
} ,
) )
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-19 20:52:09 -04:00
fn definition < ' s > ( input : & ' s str ) -> Res < & ' s str , Vec < Object < ' s > > > {
Ok ( ( input , vec! [ ] ) )
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-19 20:52:09 -04:00
fn footnote_definition_end < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , & ' s str > {
2023-07-19 21:14:09 -04:00
let context_depth = get_bracket_depth ( context )
. expect ( " This function should only be called from inside a footnote definition. " ) ;
2023-07-19 20:52:09 -04:00
let text_since_context_entry = get_consumed ( context_depth . position , input ) ;
let mut current_depth = context_depth . depth ;
for c in text_since_context_entry . chars ( ) {
match c {
2023-07-19 21:14:09 -04:00
'[' = > {
current_depth + = 1 ;
}
2023-07-19 20:52:09 -04:00
']' if current_depth = = 0 = > {
panic! ( " Exceeded footnote reference definition bracket depth. " )
2023-07-19 21:14:09 -04:00
}
2023-07-19 20:52:09 -04:00
']' if current_depth > 0 = > {
current_depth - = 1 ;
2023-07-19 21:14:09 -04:00
}
2023-07-19 20:52:09 -04:00
_ = > { }
}
}
if current_depth > 0 {
// Its impossible for the next character to end the footnote reference definition if we're any amount of brackets deep
2023-07-19 21:14:09 -04:00
return Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
" NoFootnoteReferenceDefinitionEnd " ,
) ) ) ) ;
2023-07-19 20:52:09 -04:00
}
tag ( " ] " ) ( input )
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-19 20:52:09 -04:00
fn get_bracket_depth < ' r , ' s > (
context : Context < ' r , ' s > ,
) -> Option < & ' r FootnoteReferenceDefinition < ' s > > {
for node in context . iter ( ) {
match node . get_data ( ) {
ContextElement ::FootnoteReferenceDefinition ( depth ) = > return Some ( depth ) ,
_ = > { }
}
}
None
}