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-09-03 03:16:02 +00:00
use super ::object_parser ::standard_set_object ;
2023-08-23 04:30:26 +00:00
use super ::org_source ::OrgSource ;
2023-07-14 21:37:46 +00:00
use super ::radio_link ::RematchObject ;
2023-08-31 19:44:44 +00:00
use super ::util ::maybe_consume_object_trailing_whitespace_if_not_exiting ;
2023-09-03 03:16:02 +00:00
use crate ::context ::parser_with_context ;
use crate ::context ::ContextElement ;
use crate ::context ::ExitClass ;
use crate ::context ::ExitMatcherNode ;
use crate ::context ::RefContext ;
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-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-24 20:19:48 +00:00
use crate ::parser ::util ::preceded_by_whitespace ;
2023-09-03 03:16:02 +00:00
use crate ::types ::Bold ;
use crate ::types ::Code ;
use crate ::types ::Italic ;
use crate ::types ::Object ;
use crate ::types ::StrikeThrough ;
use crate ::types ::Underline ;
use crate ::types ::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-08-23 04:30:26 +00:00
pub fn text_markup < ' r , ' s > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Object < ' s > > {
2023-04-23 00:48:01 +00:00
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-08-23 04:30:26 +00:00
pub fn bold < ' r , ' s > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Bold < ' s > > {
2023-04-23 00:48:01 +00:00
let text_markup_object_specialized = text_markup_object ( " * " ) ;
let ( remaining , children ) = text_markup_object_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
2023-08-23 04:30:26 +00:00
Ok ( (
remaining ,
Bold {
source : source . into ( ) ,
children ,
} ,
) )
2023-04-23 00:48:01 +00:00
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 04:30:26 +00:00
pub fn italic < ' r , ' s > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Italic < ' s > > {
2023-04-23 00:48:01 +00:00
let text_markup_object_specialized = text_markup_object ( " / " ) ;
let ( remaining , children ) = text_markup_object_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
2023-08-23 04:30:26 +00:00
Ok ( (
remaining ,
Italic {
source : source . into ( ) ,
children ,
} ,
) )
2023-04-23 00:48:01 +00:00
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 04:30:26 +00:00
pub fn underline < ' r , ' s > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Underline < ' s > > {
2023-04-23 00:48:01 +00:00
let text_markup_object_specialized = text_markup_object ( " _ " ) ;
let ( remaining , children ) = text_markup_object_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
2023-08-23 04:30:26 +00:00
Ok ( (
remaining ,
Underline {
source : source . into ( ) ,
children ,
} ,
) )
2023-04-23 00:48:01 +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 strike_through < ' r , ' s > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , StrikeThrough < ' s > > {
2023-04-23 00:48:01 +00:00
let text_markup_object_specialized = text_markup_object ( " + " ) ;
let ( remaining , children ) = text_markup_object_specialized ( context , input ) ? ;
let source = get_consumed ( input , remaining ) ;
2023-08-23 04:30:26 +00:00
Ok ( (
remaining ,
StrikeThrough {
source : source . into ( ) ,
children ,
} ,
) )
2023-04-23 00:48:01 +00:00
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 04:30:26 +00:00
pub fn verbatim < ' r , ' s > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , 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 ) ;
2023-08-23 04:30:26 +00:00
Ok ( (
remaining ,
Verbatim {
source : source . into ( ) ,
contents : contents . into ( ) ,
} ,
) )
2023-04-23 00:57:30 +00:00
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 04:30:26 +00:00
pub fn code < ' r , ' s > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , 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 ) ;
2023-08-23 04:30:26 +00:00
Ok ( (
remaining ,
Code {
source : source . into ( ) ,
contents : contents . into ( ) ,
} ,
) )
2023-04-23 00:57:30 +00:00
}
2023-09-03 03:16:02 +00:00
fn text_markup_object < ' c > (
marker_symbol : & ' c str ,
) -> impl for < ' b , ' r , ' s > Fn (
RefContext < ' b , ' r , ' s > ,
OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Vec < Object < ' s > > >
+ ' c {
2023-04-23 00:48:01 +00:00
let marker_symbol = marker_symbol . to_owned ( ) ;
2023-09-03 03:16:02 +00:00
move | context , input : OrgSource < '_ > | _text_markup_object ( context , input , marker_symbol . as_str ( ) )
2023-04-23 00:48:01 +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
fn _text_markup_object < ' r , ' s , ' x > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
2023-04-23 00:48:01 +00:00
marker_symbol : & ' x str ,
2023-08-23 04:30:26 +00:00
) -> Res < OrgSource < ' s > , 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-08-23 04:30:26 +00:00
let text_markup_end_specialized = text_markup_end ( open . into ( ) ) ;
2023-09-03 03:16:02 +00:00
let parser_context = ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Gamma ,
exit_matcher : & text_markup_end_specialized ,
} ) ;
let parser_context = context . with_additional_node ( & parser_context ) ;
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 (
2023-08-23 04:30:26 +00:00
" Parent exit matcher is triggering. " . into ( ) ,
2023-04-24 21:16:07 +00:00
) ) ) ) ;
}
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-08-31 19:44:44 +00:00
let ( remaining , _trailing_whitespace ) =
maybe_consume_object_trailing_whitespace_if_not_exiting ( context , 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-09-03 03:16:02 +00:00
fn text_markup_string < ' c > (
marker_symbol : & ' c str ,
) -> impl for < ' b , ' r , ' s > Fn (
RefContext < ' b , ' r , ' s > ,
OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , OrgSource < ' s > >
+ ' c {
move | context , input : OrgSource < '_ > | _text_markup_string ( context , input , marker_symbol )
2023-04-23 00:57:30 +00:00
}
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 > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
2023-04-23 00:57:30 +00:00
marker_symbol : & ' x str ,
2023-08-23 04:30:26 +00:00
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-04-23 00:57:30 +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-08-23 04:30:26 +00:00
let text_markup_end_specialized = text_markup_end ( open . into ( ) ) ;
2023-09-03 03:16:02 +00:00
let parser_context = ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Gamma ,
exit_matcher : & text_markup_end_specialized ,
} ) ;
let parser_context = context . with_additional_node ( & parser_context ) ;
2023-04-23 00:57:30 +00:00
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 (
2023-08-23 04:30:26 +00:00
" Parent exit matcher is triggering. " . into ( ) ,
2023-04-24 21:16:07 +00:00
) ) ) ) ;
}
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 ) ? ;
2023-08-31 19:44:44 +00:00
let ( remaining , _trailing_whitespace ) =
maybe_consume_object_trailing_whitespace_if_not_exiting ( context , remaining ) ? ;
2023-04-23 00:57:30 +00:00
Ok ( ( remaining , contents ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-09-03 03:16:02 +00:00
pub fn pre < ' r , ' s > (
_context : RefContext < '_ , ' r , ' s > ,
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , ( ) > {
2023-08-24 20:55:56 +00:00
let preceding_character = input . get_preceding_character ( ) ;
2023-04-22 23:06:48 +00:00
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 (
2023-08-23 04:30:26 +00:00
" Not a valid pre character for text markup. " . into ( ) ,
2023-04-22 23:06:48 +00:00
) ) ) ) ;
}
} ;
Ok ( ( input , ( ) ) )
}
2023-08-11 00:04:59 +00:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-09-03 03:16:02 +00:00
pub fn post < ' r , ' s > (
_context : RefContext < '_ , ' r , ' s > ,
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , ( ) > {
2023-08-30 03:57:15 +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
}
2023-09-03 03:16:02 +00:00
fn text_markup_end < ' c > (
marker_symbol : & ' c str ,
) -> impl for < ' r , ' s > Fn ( RefContext < '_ , ' r , ' s > , OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > + ' c
{
move | context , input : OrgSource < '_ > | _text_markup_end ( context , input , marker_symbol )
2023-04-22 23:34:13 +00:00
}
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 > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
2023-04-22 23:34:13 +00:00
marker_symbol : & ' x str ,
2023-08-23 04:30:26 +00:00
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-08-24 23:29:00 +00:00
not ( preceded_by_whitespace ) ( 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-09-03 02:45:46 +00:00
_context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Object < ' s > > {
2023-07-14 21:37:46 +00:00
let ( remaining , children ) =
_rematch_text_markup_object ( _context , input , " * " , & self . children ) ? ;
let source = get_consumed ( input , remaining ) ;
2023-08-23 04:30:26 +00:00
Ok ( (
remaining ,
Object ::Bold ( Bold {
source : source . into ( ) ,
children ,
} ) ,
) )
2023-07-14 21:37:46 +00:00
}
}
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 > (
2023-09-03 02:45:46 +00:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 04:30:26 +00:00
input : OrgSource < ' s > ,
2023-07-14 21:37:46 +00:00
marker_symbol : & 'static str ,
2023-07-14 22:04:01 +00:00
original_match_children : & ' x Vec < Object < ' x > > ,
2023-08-23 04:30:26 +00:00
) -> Res < OrgSource < ' s > , Vec < Object < ' s > > > {
2023-07-14 21:37:46 +00:00
let ( remaining , _ ) = pre ( context , input ) ? ;
let ( remaining , open ) = tag ( marker_symbol ) ( remaining ) ? ;
let ( remaining , _peek_not_whitespace ) = peek ( not ( multispace1 ) ) ( remaining ) ? ;
2023-08-23 04:30:26 +00:00
let text_markup_end_specialized = text_markup_end ( open . into ( ) ) ;
2023-09-03 03:16:02 +00:00
let parser_context = ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Gamma ,
exit_matcher : & text_markup_end_specialized ,
} ) ;
let parser_context = context . with_additional_node ( & parser_context ) ;
2023-07-14 21:37:46 +00:00
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 (
2023-08-23 04:30:26 +00:00
" Parent exit matcher is triggering. " . into ( ) ,
2023-07-14 21:37:46 +00:00
) ) ) ) ;
}
}
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
}