2023-04-22 23:06:48 +00:00
use nom ::branch ::alt ;
use nom ::bytes ::complete ::tag ;
2023-04-23 00:57:30 +00:00
use nom ::character ::complete ::anychar ;
2023-04-23 00:02:51 +00:00
use nom ::character ::complete ::line_ending ;
2023-04-23 02:34:37 +00:00
use nom ::character ::complete ::multispace1 ;
2023-04-23 00:02:51 +00:00
use nom ::character ::complete ::one_of ;
use nom ::character ::complete ::space0 ;
2023-04-23 00:48:01 +00:00
use nom ::combinator ::map ;
2023-04-23 02:34:37 +00:00
use nom ::combinator ::not ;
2023-04-22 23:34:13 +00:00
use nom ::combinator ::peek ;
2023-04-23 00:02:51 +00:00
use nom ::combinator ::recognize ;
2023-04-22 23:34:13 +00:00
use nom ::combinator ::verify ;
use nom ::multi ::many_till ;
use nom ::sequence ::terminated ;
2023-08-11 00:04:59 +00:00
#[ cfg(feature = " tracing " ) ]
2023-04-24 21:16:07 +00:00
use tracing ::span ;
2023-04-22 23:06:48 +00:00
2023-07-14 21:37:46 +00:00
use super ::radio_link ::RematchObject ;
2023-04-22 22:54:19 +00:00
use super ::Context ;
2023-04-22 23:06:48 +00:00
use crate ::error ::CustomError ;
use crate ::error ::MyError ;
2023-04-22 22:54:19 +00:00
use crate ::error ::Res ;
2023-04-22 23:34:13 +00:00
use crate ::parser ::exiting ::ExitClass ;
use crate ::parser ::object_parser ::standard_set_object ;
use crate ::parser ::parser_context ::ContextElement ;
use crate ::parser ::parser_context ::ExitMatcherNode ;
use crate ::parser ::parser_with_context ::parser_with_context ;
2023-07-14 21:37:46 +00:00
use crate ::parser ::radio_link ::rematch_target ;
2023-04-22 23:34:13 +00:00
use crate ::parser ::util ::exit_matcher_parser ;
use crate ::parser ::util ::get_consumed ;
2023-04-22 23:06:48 +00:00
use crate ::parser ::util ::get_one_before ;
2023-04-24 20:19:48 +00:00
use crate ::parser ::util ::preceded_by_whitespace ;
2023-04-23 00:48:01 +00:00
use crate ::parser ::Bold ;
2023-04-23 00:57:30 +00:00
use crate ::parser ::Code ;
2023-04-23 00:48:01 +00:00
use crate ::parser ::Italic ;
use crate ::parser ::Object ;
use crate ::parser ::StrikeThrough ;
use crate ::parser ::Underline ;
2023-04-23 00:57:30 +00:00
use crate ::parser ::Verbatim ;
2023-04-22 22:54:19 +00:00
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-23 00:48:01 +00:00
pub fn text_markup < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , Object < ' s > > {
alt ( (
map ( parser_with_context! ( bold ) ( context ) , Object ::Bold ) ,
map ( parser_with_context! ( italic ) ( context ) , Object ::Italic ) ,
map ( parser_with_context! ( underline ) ( context ) , Object ::Underline ) ,
map (
parser_with_context! ( strike_through ) ( context ) ,
Object ::StrikeThrough ,
) ,
2023-04-23 00:57:30 +00:00
map ( parser_with_context! ( verbatim ) ( context ) , Object ::Verbatim ) ,
map ( parser_with_context! ( code ) ( context ) , Object ::Code ) ,
2023-04-23 00:48:01 +00:00
) ) ( input )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-23 00:48:01 +00:00
pub fn bold < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , Bold < ' s > > {
let text_markup_object_specialized = text_markup_object ( " * " ) ;
let ( remaining , children ) = text_markup_object_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Bold { source , children } ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-23 00:48:01 +00:00
pub fn italic < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , Italic < ' s > > {
let text_markup_object_specialized = text_markup_object ( " / " ) ;
let ( remaining , children ) = text_markup_object_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Italic { source , children } ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-23 00:48:01 +00:00
pub fn underline < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , Underline < ' s > > {
let text_markup_object_specialized = text_markup_object ( " _ " ) ;
let ( remaining , children ) = text_markup_object_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Underline { source , children } ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-23 00:48:01 +00:00
pub fn strike_through < ' r , ' s > (
2023-04-22 22:54:19 +00:00
context : Context < ' r , ' s > ,
input : & ' s str ,
2023-04-23 00:48:01 +00:00
) -> Res < & ' s str , StrikeThrough < ' s > > {
let text_markup_object_specialized = text_markup_object ( " + " ) ;
let ( remaining , children ) = text_markup_object_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , StrikeThrough { source , children } ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-23 00:57:30 +00:00
pub fn verbatim < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , Verbatim < ' s > > {
2023-04-23 01:01:29 +00:00
let text_markup_string_specialized = text_markup_string ( " = " ) ;
2023-04-23 00:57:30 +00:00
let ( remaining , contents ) = text_markup_string_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Verbatim { source , contents } ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-23 00:57:30 +00:00
pub fn code < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , Code < ' s > > {
2023-04-23 01:01:29 +00:00
let text_markup_string_specialized = text_markup_string ( " ~ " ) ;
2023-04-23 00:57:30 +00:00
let ( remaining , contents ) = text_markup_string_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Code { source , contents } ) )
}
2023-04-23 00:48:01 +00:00
fn text_markup_object (
marker_symbol : & str ,
) -> impl for < ' r , ' s > Fn ( Context < ' r , ' s > , & ' s str ) -> Res < & ' s str , Vec < Object < ' s > > > {
let marker_symbol = marker_symbol . to_owned ( ) ;
move | context : Context , input : & str | _text_markup_object ( context , input , marker_symbol . as_str ( ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-23 00:48:01 +00:00
fn _text_markup_object < ' r , ' s , ' x > (
context : Context < ' r , ' s > ,
input : & ' s str ,
marker_symbol : & ' x str ,
) -> Res < & ' s str , Vec < Object < ' s > > > {
2023-04-22 23:06:48 +00:00
let ( remaining , _ ) = pre ( context , input ) ? ;
2023-04-23 01:01:29 +00:00
let ( remaining , open ) = tag ( marker_symbol ) ( remaining ) ? ;
2023-04-23 02:34:37 +00:00
let ( remaining , _peek_not_whitespace ) = peek ( not ( multispace1 ) ) ( remaining ) ? ;
2023-04-22 23:34:13 +00:00
let text_markup_end_specialized = text_markup_end ( open ) ;
let parser_context =
context . with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Beta ,
exit_matcher : & text_markup_end_specialized ,
} ) ) ;
2023-04-22 23:06:48 +00:00
2023-04-22 23:34:13 +00: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 ) ,
) ,
| ( children , _exit_contents ) | ! children . is_empty ( ) ,
) ( remaining ) ? ;
2023-04-24 21:16:07 +00:00
{
2023-08-11 00:04:59 +00:00
#[ cfg(feature = " tracing " ) ]
2023-04-24 21:16:07 +00:00
let span = span! ( tracing ::Level ::DEBUG , " Checking parent exit. " ) ;
2023-08-11 00:04:59 +00:00
#[ cfg(feature = " tracing " ) ]
2023-04-24 21:16:07 +00:00
let _enter = span . enter ( ) ;
if exit_matcher_parser ( context , remaining ) . is_ok ( ) {
return Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
" Parent exit matcher is triggering. " ,
) ) ) ) ;
}
2023-04-24 20:48:33 +00:00
}
2023-04-23 00:04:35 +00:00
let ( remaining , _close ) = text_markup_end_specialized ( context , remaining ) ? ;
2023-04-23 00:02:51 +00:00
let ( remaining , _trailing_whitespace ) = space0 ( remaining ) ? ;
2023-04-23 00:48:01 +00:00
Ok ( ( remaining , children ) )
2023-04-22 22:54:19 +00:00
}
2023-04-22 23:06:48 +00:00
2023-04-23 00:57:30 +00:00
fn text_markup_string (
marker_symbol : & str ,
) -> impl for < ' r , ' s > Fn ( Context < ' r , ' s > , & ' s str ) -> Res < & ' s str , & ' s str > {
let marker_symbol = marker_symbol . to_owned ( ) ;
move | context : Context , input : & str | _text_markup_string ( context , input , marker_symbol . as_str ( ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-23 00:57:30 +00:00
fn _text_markup_string < ' r , ' s , ' x > (
context : Context < ' r , ' s > ,
input : & ' s str ,
marker_symbol : & ' x str ,
) -> Res < & ' s str , & ' s str > {
let ( remaining , _ ) = pre ( context , input ) ? ;
2023-04-23 01:01:29 +00:00
let ( remaining , open ) = tag ( marker_symbol ) ( remaining ) ? ;
2023-04-23 02:34:37 +00:00
let ( remaining , _peek_not_whitespace ) = peek ( not ( multispace1 ) ) ( remaining ) ? ;
2023-04-23 00:57:30 +00:00
let text_markup_end_specialized = text_markup_end ( open ) ;
let parser_context =
context . with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Beta ,
exit_matcher : & text_markup_end_specialized ,
} ) ) ;
let ( remaining , contents ) = recognize ( verify (
many_till (
anychar ,
parser_with_context! ( exit_matcher_parser ) ( & parser_context ) ,
) ,
| ( children , _exit_contents ) | ! children . is_empty ( ) ,
) ) ( remaining ) ? ;
2023-04-24 21:16:07 +00:00
{
2023-08-11 00:04:59 +00:00
#[ cfg(feature = " tracing " ) ]
2023-04-24 21:16:07 +00:00
let span = span! ( tracing ::Level ::DEBUG , " Checking parent exit. " ) ;
2023-08-11 00:04:59 +00:00
#[ cfg(feature = " tracing " ) ]
2023-04-24 21:16:07 +00:00
let _enter = span . enter ( ) ;
if exit_matcher_parser ( context , remaining ) . is_ok ( ) {
return Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
" Parent exit matcher is triggering. " ,
) ) ) ) ;
}
2023-04-24 20:48:33 +00:00
}
2023-04-23 00:57:30 +00:00
let ( remaining , _close ) = text_markup_end_specialized ( context , remaining ) ? ;
let ( remaining , _trailing_whitespace ) = space0 ( remaining ) ? ;
Ok ( ( remaining , contents ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-22 23:06:48 +00:00
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 ( ) ;
match preceding_character {
// If None, we are at the start of the file which is technically the beginning of a line.
None | Some ( '\r' ) | Some ( '\n' ) | Some ( ' ' ) | Some ( '\t' ) | Some ( '-' ) | Some ( '(' )
2023-07-15 00:55:16 +00:00
| Some ( '{' ) | Some ( '\'' ) | Some ( '"' ) | Some ( '<' ) = > { }
2023-04-22 23:06:48 +00:00
Some ( _ ) = > {
// Not at start of line, cannot be a heading
return Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
" Not a valid pre character for text markup. " ,
) ) ) ) ;
}
} ;
Ok ( ( input , ( ) ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-22 23:34:13 +00:00
pub fn post < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , ( ) > {
2023-07-15 00:55:16 +00:00
let ( remaining , _ ) = alt ( ( recognize ( one_of ( " \r \n \t -.,;:!?')}[ \" > " ) ) , line_ending ) ) ( input ) ? ;
2023-04-23 00:02:51 +00:00
Ok ( ( remaining , ( ) ) )
2023-04-22 23:34:13 +00:00
}
fn text_markup_end (
marker_symbol : & str ,
) -> impl for < ' r , ' s > Fn ( Context < ' r , ' s > , & ' s str ) -> Res < & ' s str , & ' s str > {
let marker_symbol = marker_symbol . to_owned ( ) ;
move | context : Context , input : & str | _text_markup_end ( context , input , marker_symbol . as_str ( ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-04-22 23:34:13 +00:00
fn _text_markup_end < ' r , ' s , ' x > (
context : Context < ' r , ' s > ,
input : & ' s str ,
marker_symbol : & ' x str ,
) -> Res < & ' s str , & ' s str > {
2023-04-23 02:34:37 +00:00
not ( parser_with_context! ( preceded_by_whitespace ) ( context ) ) ( input ) ? ;
2023-04-22 23:34:13 +00:00
let ( remaining , _marker ) = terminated (
tag ( marker_symbol ) ,
peek ( parser_with_context! ( post ) ( context ) ) ,
) ( input ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
2023-07-14 21:37:46 +00:00
2023-07-14 22:04:01 +00:00
impl < ' x > RematchObject < ' x > for Bold < ' x > {
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-14 21:37:46 +00:00
fn rematch_object < ' r , ' s > (
2023-07-14 22:04:01 +00:00
& ' x self ,
2023-07-14 21:37:46 +00:00
_context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , Object < ' s > > {
let ( remaining , children ) =
_rematch_text_markup_object ( _context , input , " * " , & self . children ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Object ::Bold ( Bold { source , children } ) ) )
}
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-14 21:37:46 +00:00
fn _rematch_text_markup_object < ' r , ' s , ' x > (
context : Context < ' r , ' s > ,
input : & ' s str ,
marker_symbol : & 'static str ,
2023-07-14 22:04:01 +00:00
original_match_children : & ' x Vec < Object < ' x > > ,
2023-07-14 21:37:46 +00:00
) -> Res < & ' s str , Vec < Object < ' s > > > {
let ( remaining , _ ) = pre ( context , input ) ? ;
let ( remaining , open ) = tag ( marker_symbol ) ( remaining ) ? ;
let ( remaining , _peek_not_whitespace ) = peek ( not ( multispace1 ) ) ( remaining ) ? ;
let text_markup_end_specialized = text_markup_end ( open ) ;
let parser_context =
context . with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Beta ,
exit_matcher : & text_markup_end_specialized ,
} ) ) ;
let ( remaining , children ) =
// TODO: This doesn't really check the exit matcher between each object. I think it may be possible to construct an org document that parses incorrectly with the current code.
rematch_target ( & parser_context , original_match_children , remaining ) ? ;
{
2023-08-11 00:04:59 +00:00
#[ cfg(feature = " tracing " ) ]
2023-07-14 21:37:46 +00:00
let span = span! ( tracing ::Level ::DEBUG , " Checking parent exit. " ) ;
2023-08-11 00:04:59 +00:00
#[ cfg(feature = " tracing " ) ]
2023-07-14 21:37:46 +00:00
let _enter = span . enter ( ) ;
if exit_matcher_parser ( context , remaining ) . is_ok ( ) {
return Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
" Parent exit matcher is triggering. " ,
) ) ) ) ;
}
}
let ( remaining , _close ) = text_markup_end_specialized ( context , remaining ) ? ;
let ( remaining , _trailing_whitespace ) = space0 ( remaining ) ? ;
2023-07-14 22:32:16 +00:00
Ok ( ( remaining , children ) )
2023-07-14 21:37:46 +00:00
}