2023-04-21 16:57:49 -04:00
use nom ::branch ::alt ;
use nom ::bytes ::complete ::is_not ;
2023-10-04 12:36:38 -04:00
use nom ::bytes ::complete ::tag ;
2023-04-21 16:57:49 -04:00
use nom ::bytes ::complete ::tag_no_case ;
2023-10-04 13:08:24 -04:00
use nom ::character ::complete ::anychar ;
2023-04-21 16:57:49 -04:00
use nom ::character ::complete ::line_ending ;
use nom ::character ::complete ::space0 ;
use nom ::character ::complete ::space1 ;
use nom ::combinator ::consumed ;
use nom ::combinator ::eof ;
2023-10-04 11:31:45 -04:00
use nom ::combinator ::map ;
2023-04-21 16:57:49 -04:00
use nom ::combinator ::opt ;
2023-10-04 13:08:24 -04:00
use nom ::combinator ::peek ;
2023-09-06 18:25:35 -04:00
use nom ::combinator ::recognize ;
2023-04-21 16:57:49 -04:00
use nom ::combinator ::verify ;
use nom ::multi ::many_till ;
use nom ::sequence ::tuple ;
2023-10-10 00:43:02 -04:00
use nom ::InputTake ;
2023-04-21 16:57:49 -04:00
2023-10-11 14:44:25 -04:00
use super ::affiliated_keyword ::parse_affiliated_keywords ;
2023-08-23 00:30:26 -04:00
use super ::org_source ::OrgSource ;
2023-10-06 11:45:15 -04:00
use super ::util ::maybe_consume_trailing_whitespace_if_not_exiting ;
2023-09-03 11:05:34 -04:00
use crate ::context ::parser_with_context ;
use crate ::context ::ContextElement ;
2023-09-03 12:28:45 -04:00
use crate ::context ::ContextMatcher ;
2023-09-03 11:05:34 -04:00
use crate ::context ::ExitClass ;
use crate ::context ::ExitMatcherNode ;
use crate ::context ::RefContext ;
2023-10-05 01:55:33 -04:00
use crate ::error ::CustomError ;
2023-04-22 21:45:18 -04:00
use crate ::error ::Res ;
2023-04-21 16:57:49 -04:00
use crate ::parser ::object_parser ::standard_set_object ;
use crate ::parser ::util ::blank_line ;
use crate ::parser ::util ::exit_matcher_parser ;
use crate ::parser ::util ::get_consumed ;
use crate ::parser ::util ::start_of_line ;
2023-04-22 22:06:34 -04:00
use crate ::parser ::util ::text_until_exit ;
2023-10-04 15:20:57 -04:00
use crate ::types ::CharOffsetInLine ;
2023-09-03 11:05:34 -04:00
use crate ::types ::CommentBlock ;
use crate ::types ::ExampleBlock ;
use crate ::types ::ExportBlock ;
2023-10-12 17:12:55 -04:00
use crate ::types ::Keyword ;
2023-10-04 11:31:45 -04:00
use crate ::types ::LineNumber ;
2023-09-03 11:05:34 -04:00
use crate ::types ::Object ;
use crate ::types ::PlainText ;
2023-10-04 15:43:09 -04:00
use crate ::types ::RetainLabels ;
2023-09-03 11:05:34 -04:00
use crate ::types ::SrcBlock ;
2023-10-04 11:31:45 -04:00
use crate ::types ::SwitchNumberLines ;
2023-09-03 11:05:34 -04:00
use crate ::types ::VerseBlock ;
2023-04-21 16:31:25 -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 verse_block < ' b , ' g , ' r , ' s , AK > (
affiliated_keywords : AK ,
remaining : OrgSource < ' s > ,
2023-09-03 15:44:18 -04:00
context : RefContext < ' b , ' g , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
2023-10-12 17:12:55 -04:00
) -> Res < OrgSource < ' s > , VerseBlock < ' s > >
where
AK : IntoIterator < Item = Keyword < ' s > > ,
{
2023-10-06 11:45:15 -04:00
let ( remaining , _ ) = lesser_block_begin ( " verse " ) ( context , remaining ) ? ;
2023-04-21 16:57:49 -04:00
let ( remaining , parameters ) = opt ( tuple ( ( space1 , data ) ) ) ( remaining ) ? ;
2023-09-06 18:25:35 -04:00
let ( remaining , _nl ) = recognize ( tuple ( ( space0 , line_ending ) ) ) ( remaining ) ? ;
2023-04-21 18:01:06 -04:00
let lesser_block_end_specialized = lesser_block_end ( " verse " ) ;
2023-09-03 11:05:34 -04:00
let contexts = [
ContextElement ::ConsumeTrailingWhitespace ( true ) ,
ContextElement ::Context ( " lesser block " ) ,
ContextElement ::ExitMatcherNode ( ExitMatcherNode {
2023-09-06 14:14:02 -04:00
class : ExitClass ::Alpha ,
2023-04-21 17:11:27 -04:00
exit_matcher : & lesser_block_end_specialized ,
2023-09-03 11:05:34 -04:00
} ) ,
] ;
2023-09-03 12:28:45 -04:00
let parser_context = context . with_additional_node ( & contexts [ 0 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 1 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 2 ] ) ;
2023-10-16 17:58:52 -04:00
let parameters = parameters . map ( | ( _ws , parameters ) | parameters ) ;
2023-04-21 16:57:49 -04:00
let object_matcher = parser_with_context! ( standard_set_object ) ( & parser_context ) ;
let exit_matcher = parser_with_context! ( exit_matcher_parser ) ( & parser_context ) ;
// Check for a completely empty block
let ( remaining , children ) = match consumed ( many_till ( blank_line , exit_matcher ) ) ( remaining ) {
2023-04-21 18:01:06 -04:00
Ok ( ( remaining , ( whitespace , ( _children , _exit_contents ) ) ) ) = > (
remaining ,
2023-08-23 00:30:26 -04:00
vec! [ Object ::PlainText ( PlainText {
source : whitespace . into ( ) ,
} ) ] ,
2023-04-21 18:01:06 -04:00
) ,
2023-04-21 16:57:49 -04:00
Err ( _ ) = > {
let ( remaining , ( children , _exit_contents ) ) =
many_till ( object_matcher , exit_matcher ) ( remaining ) ? ;
( remaining , children )
}
} ;
2023-04-21 17:11:27 -04:00
let ( remaining , _end ) = lesser_block_end_specialized ( & parser_context , remaining ) ? ;
2023-04-21 16:57:49 -04:00
2023-10-06 11:45:15 -04:00
let ( remaining , _trailing_ws ) =
maybe_consume_trailing_whitespace_if_not_exiting ( context , remaining ) ? ;
2023-04-21 16:57:49 -04:00
let source = get_consumed ( input , remaining ) ;
Ok ( (
remaining ,
2023-04-21 17:40:49 -04:00
VerseBlock {
2023-08-23 00:30:26 -04:00
source : source . into ( ) ,
2023-10-11 14:44:25 -04:00
affiliated_keywords : parse_affiliated_keywords (
context . get_global_settings ( ) ,
affiliated_keywords ,
) ,
2023-10-16 17:58:52 -04:00
data : parameters . map ( Into ::< & str > ::into ) ,
2023-04-21 16:57:49 -04:00
children ,
} ,
) )
}
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 comment_block < ' b , ' g , ' r , ' s , AK > (
affiliated_keywords : AK ,
remaining : OrgSource < ' s > ,
2023-09-03 15:44:18 -04:00
context : RefContext < ' b , ' g , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
2023-10-12 17:12:55 -04:00
) -> Res < OrgSource < ' s > , CommentBlock < ' s > >
where
AK : IntoIterator < Item = Keyword < ' s > > ,
{
2023-10-06 11:45:15 -04:00
let ( remaining , _ ) = lesser_block_begin ( " comment " ) ( context , remaining ) ? ;
2023-10-04 09:51:28 -04:00
let ( remaining , _parameters ) = opt ( tuple ( ( space1 , data ) ) ) ( remaining ) ? ;
2023-09-06 18:25:35 -04:00
let ( remaining , _nl ) = recognize ( tuple ( ( space0 , line_ending ) ) ) ( remaining ) ? ;
2023-04-21 17:32:53 -04:00
let lesser_block_end_specialized = lesser_block_end ( " comment " ) ;
2023-09-03 11:05:34 -04:00
let contexts = [
ContextElement ::ConsumeTrailingWhitespace ( true ) ,
ContextElement ::Context ( " lesser block " ) ,
ContextElement ::ExitMatcherNode ( ExitMatcherNode {
2023-09-06 14:14:02 -04:00
class : ExitClass ::Alpha ,
2023-04-21 17:32:53 -04:00
exit_matcher : & lesser_block_end_specialized ,
2023-09-03 11:05:34 -04:00
} ) ,
] ;
2023-09-03 12:28:45 -04:00
let parser_context = context . with_additional_node ( & contexts [ 0 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 1 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 2 ] ) ;
2023-04-21 17:32:53 -04:00
2023-04-22 22:06:34 -04:00
let ( remaining , contents ) = parser_with_context! ( text_until_exit ) ( & parser_context ) ( remaining ) ? ;
2023-04-21 17:32:53 -04:00
let ( remaining , _end ) = lesser_block_end_specialized ( & parser_context , remaining ) ? ;
2023-10-06 11:45:15 -04:00
let ( remaining , _trailing_ws ) =
maybe_consume_trailing_whitespace_if_not_exiting ( context , remaining ) ? ;
2023-04-21 17:32:53 -04:00
let source = get_consumed ( input , remaining ) ;
Ok ( (
remaining ,
2023-04-21 17:40:49 -04:00
CommentBlock {
2023-08-23 00:30:26 -04:00
source : source . into ( ) ,
2023-10-11 14:44:25 -04:00
affiliated_keywords : parse_affiliated_keywords (
context . get_global_settings ( ) ,
affiliated_keywords ,
) ,
2023-08-23 00:30:26 -04:00
contents : contents . into ( ) ,
2023-04-21 17:40:49 -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 example_block < ' b , ' g , ' r , ' s , AK > (
affiliated_keywords : AK ,
remaining : OrgSource < ' s > ,
2023-09-03 15:44:18 -04:00
context : RefContext < ' b , ' g , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
2023-10-12 17:12:55 -04:00
) -> Res < OrgSource < ' s > , ExampleBlock < ' s > >
where
AK : IntoIterator < Item = Keyword < ' s > > ,
{
2023-10-06 11:45:15 -04:00
let ( remaining , _ ) = lesser_block_begin ( " example " ) ( context , remaining ) ? ;
2023-10-10 00:43:02 -04:00
let ( remaining , parameters ) = opt ( alt ( (
map ( tuple ( ( space1 , example_switches ) ) , | ( _ , switches ) | switches ) ,
map ( space1 , | ws : OrgSource < '_ > | {
let source = ws . take ( 0 ) ;
ExampleSrcSwitches {
source : source . into ( ) ,
number_lines : None ,
retain_labels : RetainLabels ::Yes ,
preserve_indent : None ,
use_labels : true ,
label_format : None ,
}
} ) ,
) ) ) ( remaining ) ? ;
2023-09-06 18:25:35 -04:00
let ( remaining , _nl ) = recognize ( tuple ( ( space0 , line_ending ) ) ) ( remaining ) ? ;
2023-04-21 17:40:49 -04:00
let lesser_block_end_specialized = lesser_block_end ( " example " ) ;
2023-09-03 12:28:45 -04:00
let contexts = [
ContextElement ::ConsumeTrailingWhitespace ( true ) ,
ContextElement ::Context ( " lesser block " ) ,
ContextElement ::ExitMatcherNode ( ExitMatcherNode {
2023-09-06 14:14:02 -04:00
class : ExitClass ::Alpha ,
2023-04-21 17:40:49 -04:00
exit_matcher : & lesser_block_end_specialized ,
2023-09-03 12:28:45 -04:00
} ) ,
] ;
let parser_context = context . with_additional_node ( & contexts [ 0 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 1 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 2 ] ) ;
2023-04-21 17:40:49 -04:00
2023-10-31 18:13:21 -04:00
let ( remaining , contents ) = text_until_exit ( & parser_context , remaining ) ? ;
2023-04-21 17:40:49 -04:00
let ( remaining , _end ) = lesser_block_end_specialized ( & parser_context , remaining ) ? ;
2023-10-06 11:45:15 -04:00
let ( remaining , _trailing_ws ) =
maybe_consume_trailing_whitespace_if_not_exiting ( context , remaining ) ? ;
2023-04-21 17:40:49 -04:00
let source = get_consumed ( input , remaining ) ;
2023-10-04 19:23:47 -04:00
let ( switches , number_lines , preserve_indent , retain_labels , use_labels , label_format ) = {
2023-10-04 11:31:45 -04:00
if let Some ( parameters ) = parameters {
2023-10-04 12:36:38 -04:00
(
2023-10-10 00:43:02 -04:00
Some ( parameters . source ) ,
2023-10-04 12:36:38 -04:00
parameters . number_lines ,
2023-10-04 19:23:47 -04:00
parameters . preserve_indent ,
2023-10-04 12:36:38 -04:00
parameters . retain_labels ,
parameters . use_labels ,
parameters . label_format ,
)
2023-10-04 11:31:45 -04:00
} else {
2023-10-04 19:23:47 -04:00
( None , None , None , RetainLabels ::Yes , true , None )
2023-10-04 11:31:45 -04:00
}
} ;
2023-04-21 17:40:49 -04:00
Ok ( (
remaining ,
ExampleBlock {
2023-08-23 00:30:26 -04:00
source : source . into ( ) ,
2023-10-11 14:44:25 -04:00
affiliated_keywords : parse_affiliated_keywords (
context . get_global_settings ( ) ,
affiliated_keywords ,
) ,
2023-10-04 11:31:45 -04:00
switches ,
number_lines ,
2023-10-04 19:23:47 -04:00
preserve_indent ,
2023-10-04 12:36:38 -04:00
retain_labels ,
use_labels ,
label_format ,
2023-10-31 18:13:21 -04:00
contents : Into ::< & str > ::into ( contents ) ,
2023-04-21 17:40:49 -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 export_block < ' b , ' g , ' r , ' s , AK > (
affiliated_keywords : AK ,
remaining : OrgSource < ' s > ,
2023-09-03 15:44:18 -04:00
context : RefContext < ' b , ' g , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
2023-10-12 17:12:55 -04:00
) -> Res < OrgSource < ' s > , ExportBlock < ' s > >
where
AK : IntoIterator < Item = Keyword < ' s > > ,
{
2023-10-06 11:45:15 -04:00
let ( remaining , _ ) = lesser_block_begin ( " export " ) ( context , remaining ) ? ;
2023-04-21 18:11:26 -04:00
// https://orgmode.org/worg/org-syntax.html#Blocks claims that export blocks must have a single word for data but testing shows no data and multi-word data still parses as an export block.
2023-10-05 02:17:53 -04:00
let ( remaining , export_type ) = opt ( map (
tuple ( ( space1 , switch_word , peek ( tuple ( ( space0 , line_ending ) ) ) ) ) ,
| ( _ , export_type , _ ) | export_type ,
) ) ( remaining ) ? ;
let ( remaining , parameters ) =
opt ( map ( tuple ( ( space1 , data ) ) , | ( _ , parameters ) | parameters ) ) ( remaining ) ? ;
2023-09-06 18:25:35 -04:00
let ( remaining , _nl ) = recognize ( tuple ( ( space0 , line_ending ) ) ) ( remaining ) ? ;
2023-04-21 17:40:49 -04:00
let lesser_block_end_specialized = lesser_block_end ( " export " ) ;
2023-09-03 12:28:45 -04:00
let contexts = [
ContextElement ::ConsumeTrailingWhitespace ( true ) ,
ContextElement ::Context ( " lesser block " ) ,
ContextElement ::ExitMatcherNode ( ExitMatcherNode {
2023-09-06 14:14:02 -04:00
class : ExitClass ::Alpha ,
2023-04-21 17:40:49 -04:00
exit_matcher : & lesser_block_end_specialized ,
2023-09-03 12:28:45 -04:00
} ) ,
] ;
let parser_context = context . with_additional_node ( & contexts [ 0 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 1 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 2 ] ) ;
2023-04-21 17:40:49 -04:00
2023-10-31 18:13:21 -04:00
let ( remaining , contents ) = text_until_exit ( & parser_context , remaining ) ? ;
2023-04-21 17:40:49 -04:00
let ( remaining , _end ) = lesser_block_end_specialized ( & parser_context , remaining ) ? ;
2023-10-06 11:45:15 -04:00
let ( remaining , _trailing_ws ) =
maybe_consume_trailing_whitespace_if_not_exiting ( context , remaining ) ? ;
2023-04-21 17:40:49 -04:00
let source = get_consumed ( input , remaining ) ;
Ok ( (
remaining ,
ExportBlock {
2023-08-23 00:30:26 -04:00
source : source . into ( ) ,
2023-10-11 14:44:25 -04:00
affiliated_keywords : parse_affiliated_keywords (
context . get_global_settings ( ) ,
affiliated_keywords ,
) ,
2023-10-05 02:15:32 -04:00
export_type : export_type . map ( Into ::< & str > ::into ) ,
2023-10-16 17:58:52 -04:00
data : parameters . map ( Into ::< & str > ::into ) ,
2023-10-31 18:13:21 -04:00
contents : Into ::< & str > ::into ( contents ) ,
2023-04-21 17:40:49 -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 src_block < ' b , ' g , ' r , ' s , AK > (
affiliated_keywords : AK ,
remaining : OrgSource < ' s > ,
2023-09-03 15:44:18 -04:00
context : RefContext < ' b , ' g , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
2023-10-12 17:12:55 -04:00
) -> Res < OrgSource < ' s > , SrcBlock < ' s > >
where
AK : IntoIterator < Item = Keyword < ' s > > ,
{
2023-10-06 11:45:15 -04:00
let ( remaining , _ ) = lesser_block_begin ( " src " ) ( context , remaining ) ? ;
2023-04-21 18:13:23 -04:00
// https://orgmode.org/worg/org-syntax.html#Blocks claims that data is mandatory and must follow the LANGUAGE SWITCHES ARGUMENTS pattern but testing has shown that no data and incorrect data here will still parse to a src block.
2023-10-05 01:55:33 -04:00
let ( remaining , language ) =
opt ( map ( tuple ( ( space1 , switch_word ) ) , | ( _ , language ) | language ) ) ( remaining ) ? ;
2023-10-04 19:23:47 -04:00
let ( remaining , switches ) = opt ( src_switches ) ( remaining ) ? ;
2023-10-04 18:57:51 -04:00
let ( remaining , parameters ) = opt ( map ( tuple ( ( space1 , src_parameters ) ) , | ( _ , parameters ) | {
2023-10-04 18:02:50 -04:00
parameters
} ) ) ( remaining ) ? ;
2023-09-06 18:25:35 -04:00
let ( remaining , _nl ) = recognize ( tuple ( ( space0 , line_ending ) ) ) ( remaining ) ? ;
2023-04-21 17:40:49 -04:00
let lesser_block_end_specialized = lesser_block_end ( " src " ) ;
2023-09-03 12:28:45 -04:00
let contexts = [
ContextElement ::ConsumeTrailingWhitespace ( true ) ,
ContextElement ::Context ( " lesser block " ) ,
ContextElement ::ExitMatcherNode ( ExitMatcherNode {
2023-08-14 17:28:57 -04:00
class : ExitClass ::Alpha ,
2023-04-21 17:40:49 -04:00
exit_matcher : & lesser_block_end_specialized ,
2023-09-03 12:28:45 -04:00
} ) ,
] ;
let parser_context = context . with_additional_node ( & contexts [ 0 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 1 ] ) ;
let parser_context = parser_context . with_additional_node ( & contexts [ 2 ] ) ;
2023-10-31 18:13:21 -04:00
let ( remaining , contents ) = text_until_exit ( & parser_context , remaining ) ? ;
2023-04-21 17:40:49 -04:00
let ( remaining , _end ) = lesser_block_end_specialized ( & parser_context , remaining ) ? ;
2023-10-06 11:45:15 -04:00
let ( remaining , _trailing_ws ) =
maybe_consume_trailing_whitespace_if_not_exiting ( context , remaining ) ? ;
2023-04-21 17:40:49 -04:00
let source = get_consumed ( input , remaining ) ;
2023-10-04 19:23:47 -04:00
let ( switches , number_lines , preserve_indent , retain_labels , use_labels , label_format ) = {
2023-10-04 18:02:50 -04:00
if let Some ( switches ) = switches {
2023-10-04 16:58:45 -04:00
(
2023-10-16 17:58:52 -04:00
if switches . source . is_empty ( ) {
2023-10-04 17:11:13 -04:00
None
} else {
2023-10-04 18:02:50 -04:00
Some ( switches . source )
2023-10-04 17:11:13 -04:00
} ,
2023-10-04 18:02:50 -04:00
switches . number_lines ,
2023-10-04 19:23:47 -04:00
switches . preserve_indent ,
2023-10-04 18:02:50 -04:00
switches . retain_labels ,
switches . use_labels ,
switches . label_format ,
2023-10-04 16:58:45 -04:00
)
} else {
2023-10-04 19:23:47 -04:00
( None , None , None , RetainLabels ::Yes , true , None )
2023-10-04 16:58:45 -04:00
}
} ;
2023-04-21 17:40:49 -04:00
Ok ( (
remaining ,
SrcBlock {
2023-08-23 00:30:26 -04:00
source : source . into ( ) ,
2023-10-11 14:44:25 -04:00
affiliated_keywords : parse_affiliated_keywords (
context . get_global_settings ( ) ,
affiliated_keywords ,
) ,
2023-10-04 18:57:51 -04:00
language : language . map ( Into ::< & str > ::into ) ,
2023-10-04 18:02:50 -04:00
switches ,
parameters : parameters . map ( Into ::< & str > ::into ) ,
2023-10-04 16:58:45 -04:00
number_lines ,
2023-10-04 19:23:47 -04:00
preserve_indent ,
2023-10-04 16:58:45 -04:00
retain_labels ,
use_labels ,
label_format ,
2023-10-31 18:13:21 -04:00
contents : Into ::< & str > ::into ( contents ) ,
2023-04-21 17:32:53 -04:00
} ,
) )
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 00:30:26 -04:00
fn name < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-04-21 16:57:49 -04:00
is_not ( " \t \r \n " ) ( input )
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 00:30:26 -04:00
fn data < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-04-21 16:57:49 -04:00
is_not ( " \r \n " ) ( input )
}
2023-10-16 17:58:52 -04:00
fn lesser_block_end ( current_name : & str ) -> impl ContextMatcher + '_ {
2023-09-22 00:55:10 -04:00
// Since the lesser block names are statically defined in code, we can simply assert that the name is lowercase instead of causing an allocation by converting to lowercase.
debug_assert! ( current_name = = current_name . to_lowercase ( ) ) ;
move | context , input : OrgSource < '_ > | _lesser_block_end ( context , input , current_name )
2023-04-21 16:31:25 -04:00
}
2023-04-21 17:32:53 -04:00
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( _context ) )
) ]
2023-09-03 15:44:18 -04:00
fn _lesser_block_end < ' b , ' g , ' r , ' s , ' c > (
_context : RefContext < ' b , ' g , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
2023-09-03 15:44:18 -04:00
current_name_lower : & ' c str ,
2023-08-23 00:30:26 -04:00
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-08-24 19:29:00 -04:00
start_of_line ( input ) ? ;
2023-08-14 17:18:48 -04:00
let ( remaining , _leading_whitespace ) = space0 ( input ) ? ;
2023-09-06 18:25:35 -04:00
let ( remaining , ( _begin , _name , _ws , _ending ) ) = tuple ( (
2023-08-14 17:18:48 -04:00
tag_no_case ( " #+end_ " ) ,
tag_no_case ( current_name_lower ) ,
2023-09-06 18:25:35 -04:00
space0 ,
2023-08-14 17:18:48 -04:00
alt ( ( eof , line_ending ) ) ,
) ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
2023-08-24 20:10:43 -04:00
/// Parser for the beginning of a lesser block
///
/// current_name MUST be lowercase. We do not do the conversion ourselves because it is not allowed in a const fn.
2023-10-16 17:58:52 -04:00
const fn lesser_block_begin ( current_name : & str ) -> impl ContextMatcher + '_ {
2023-08-24 20:10:43 -04:00
// TODO: Since this is a const fn, is there ANY way to "generate" functions at compile time?
2023-09-03 11:05:34 -04:00
move | context , input : OrgSource < '_ > | _lesser_block_begin ( context , input , current_name )
2023-04-21 17:32:53 -04:00
}
2023-08-14 17:18:48 -04:00
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( _context ) )
) ]
2023-09-03 15:44:18 -04:00
fn _lesser_block_begin < ' b , ' g , ' r , ' s , ' c > (
_context : RefContext < ' b , ' g , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
2023-09-03 15:44:18 -04:00
current_name_lower : & ' c str ,
2023-08-23 00:30:26 -04:00
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-08-24 19:29:00 -04:00
start_of_line ( input ) ? ;
2023-08-14 17:18:48 -04:00
let ( remaining , _leading_whitespace ) = space0 ( input ) ? ;
let ( remaining , ( _begin , name ) ) = tuple ( (
tag_no_case ( " #+begin_ " ) ,
2023-08-23 00:30:26 -04:00
verify ( name , | name : & OrgSource < '_ > | {
Into ::< & str > ::into ( name ) . to_lowercase ( ) . as_str ( ) = = current_name_lower
2023-08-14 17:18:48 -04:00
} ) ,
) ) ( remaining ) ? ;
Ok ( ( remaining , name ) )
}
2023-10-04 11:31:45 -04:00
2023-10-04 14:49:08 -04:00
#[ derive(Debug) ]
2023-10-04 16:58:45 -04:00
struct ExampleSrcSwitches < ' s > {
2023-10-04 11:31:45 -04:00
source : & ' s str ,
number_lines : Option < SwitchNumberLines > ,
2023-10-04 15:43:09 -04:00
retain_labels : RetainLabels ,
2023-10-04 19:23:47 -04:00
preserve_indent : Option < CharOffsetInLine > ,
2023-10-04 12:36:38 -04:00
use_labels : bool ,
label_format : Option < & ' s str > ,
2023-10-04 11:31:45 -04:00
}
2023-10-04 14:49:08 -04:00
#[ derive(Debug) ]
2023-10-04 11:31:45 -04:00
enum SwitchState {
Normal ,
NewLineNumber ,
ContinuedLineNumber ,
2023-10-04 12:36:38 -04:00
LabelFormat ,
2023-10-04 11:31:45 -04:00
}
2023-10-04 18:02:50 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-10-05 00:53:11 -04:00
fn src_parameters < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
verify (
recognize ( many_till ( anychar , peek ( tuple ( ( space0 , line_ending ) ) ) ) ) ,
| parameters : & OrgSource < '_ > | parameters . len ( ) > 0 ,
) ( input )
2023-10-04 18:02:50 -04:00
}
2023-10-04 11:31:45 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-10-04 16:58:45 -04:00
fn src_switches < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , ExampleSrcSwitches < ' s > > {
2023-10-04 19:23:47 -04:00
let ( remaining , leading_spaces ) = space1 ( input ) ? ;
let offset = Into ::< & str > ::into ( leading_spaces ) . chars ( ) . count ( ) ;
let offset = CharOffsetInLine ::try_from ( offset )
. expect ( " Character offset should fit in CharOffsetInLine " ) ;
example_src_switches ( true , offset ) ( remaining )
2023-10-04 16:58:45 -04:00
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn example_switches < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , ExampleSrcSwitches < ' s > > {
2023-10-04 19:23:47 -04:00
let ( remaining , switches ) = example_src_switches ( false , 0 ) ( input ) ? ;
2023-10-04 16:58:45 -04:00
Ok ( ( remaining , switches ) )
}
fn example_src_switches (
2023-10-04 18:02:50 -04:00
stop_at_parameters : bool ,
2023-10-04 19:23:47 -04:00
additional_char_offset : CharOffsetInLine ,
2023-10-04 16:58:45 -04:00
) -> impl for < ' s > Fn ( OrgSource < ' s > ) -> Res < OrgSource < ' s > , ExampleSrcSwitches < ' s > > {
2023-10-04 19:23:47 -04:00
move | input | _example_src_switches ( input , stop_at_parameters , additional_char_offset )
2023-10-04 16:58:45 -04:00
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn _example_src_switches < ' s > (
input : OrgSource < ' s > ,
2023-10-04 18:02:50 -04:00
stop_at_parameters : bool ,
2023-10-04 19:23:47 -04:00
additional_char_offset : CharOffsetInLine ,
2023-10-04 16:58:45 -04:00
) -> Res < OrgSource < ' s > , ExampleSrcSwitches < ' s > > {
2023-10-04 11:31:45 -04:00
let mut number_lines = None ;
2023-10-04 15:43:09 -04:00
let mut retain_labels = RetainLabels ::Yes ;
2023-10-04 19:23:47 -04:00
let mut preserve_indent = None ;
2023-10-04 12:36:38 -04:00
let mut use_labels = true ;
let mut label_format = None ;
2023-10-04 16:21:37 -04:00
let mut saw_r = false ;
2023-10-05 01:55:33 -04:00
let mut matched_a_word = false ;
let mut remaining = input ;
let mut last_match_remaining = input ;
2023-10-04 11:31:45 -04:00
let mut state = SwitchState ::Normal ;
2023-10-05 01:55:33 -04:00
' outer : loop {
let ( remain , word ) = opt ( switch_word ) ( remaining ) ? ;
let word = match word {
Some ( word ) = > word ,
None = > {
break ;
}
} ;
2023-10-04 15:20:57 -04:00
let normalized_word = Into ::< & str > ::into ( word ) ;
2023-10-05 01:55:33 -04:00
2023-10-04 12:36:38 -04:00
loop {
2023-10-04 15:20:57 -04:00
match ( & state , normalized_word ) {
2023-10-04 12:36:38 -04:00
( SwitchState ::Normal , " -n " ) = > {
state = SwitchState ::NewLineNumber ;
}
( SwitchState ::Normal , " +n " ) = > {
state = SwitchState ::ContinuedLineNumber ;
}
( SwitchState ::Normal , " -r " ) = > {
2023-10-04 16:21:37 -04:00
saw_r = true ;
2023-10-04 12:36:38 -04:00
use_labels = false ;
2023-10-16 17:58:52 -04:00
if let RetainLabels ::Yes = retain_labels {
retain_labels = RetainLabels ::No ;
2023-10-04 15:43:09 -04:00
}
2023-10-04 12:36:38 -04:00
}
( SwitchState ::Normal , " -l " ) = > {
state = SwitchState ::LabelFormat ;
}
2023-10-04 15:20:57 -04:00
( SwitchState ::Normal , " -k " ) = > {
2023-10-04 16:21:37 -04:00
use_labels = false ;
2023-10-04 15:20:57 -04:00
let text_until_flag = input . get_until ( word ) ;
let character_offset = Into ::< & str > ::into ( text_until_flag ) . chars ( ) . count ( ) ;
let character_offset = CharOffsetInLine ::try_from ( character_offset )
. expect ( " Character offset should fit in CharOffsetInLine " ) ;
2023-10-04 19:23:47 -04:00
retain_labels = RetainLabels ::Keep ( character_offset + additional_char_offset ) ;
}
( SwitchState ::Normal , " -i " ) = > {
let text_until_flag = input . get_until ( word ) ;
let character_offset = Into ::< & str > ::into ( text_until_flag ) . chars ( ) . count ( ) ;
let character_offset = CharOffsetInLine ::try_from ( character_offset )
. expect ( " Character offset should fit in CharOffsetInLine " ) ;
preserve_indent = Some ( character_offset + additional_char_offset ) ;
2023-10-04 15:20:57 -04:00
}
2023-10-04 12:36:38 -04:00
( SwitchState ::NewLineNumber , _ ) = > {
2023-10-04 15:20:57 -04:00
let val = normalized_word . parse ::< LineNumber > ( ) ;
2023-10-04 12:36:38 -04:00
if let Ok ( val ) = val {
if val < 0 {
number_lines = Some ( SwitchNumberLines ::New ( 0 ) ) ;
} else {
// Note that this can result in a negative 1 if the val is originally 0.
number_lines = Some ( SwitchNumberLines ::New ( val - 1 ) ) ;
}
state = SwitchState ::Normal ;
} else {
number_lines = Some ( SwitchNumberLines ::New ( 0 ) ) ;
state = SwitchState ::Normal ;
continue ; // Re-processes the word
}
}
( SwitchState ::ContinuedLineNumber , _ ) = > {
2023-10-04 15:20:57 -04:00
let val = normalized_word . parse ::< LineNumber > ( ) ;
2023-10-04 12:36:38 -04:00
if let Ok ( val ) = val {
if val < 0 {
number_lines = Some ( SwitchNumberLines ::Continued ( 0 ) ) ;
} else {
// Note that this can result in a negative 1 if the val is originally 0.
number_lines = Some ( SwitchNumberLines ::Continued ( val - 1 ) ) ;
}
state = SwitchState ::Normal ;
} else {
number_lines = Some ( SwitchNumberLines ::Continued ( 0 ) ) ;
state = SwitchState ::Normal ;
continue ; // Re-processes the word
}
2023-10-04 11:31:45 -04:00
}
2023-10-04 12:36:38 -04:00
( SwitchState ::LabelFormat , _ ) = > {
2023-10-04 15:20:57 -04:00
label_format = Some ( normalized_word ) ;
2023-10-04 12:36:38 -04:00
state = SwitchState ::Normal ;
2023-10-04 11:31:45 -04:00
}
2023-10-05 01:55:33 -04:00
( SwitchState ::Normal , _ ) if stop_at_parameters = > {
break 'outer ;
}
2023-10-04 12:36:38 -04:00
( SwitchState ::Normal , _ ) = > { }
} ;
2023-10-05 01:55:33 -04:00
matched_a_word = true ;
remaining = remain ;
last_match_remaining = remain ;
let ( remain , divider ) = opt ( space1 ) ( remaining ) ? ;
if divider . is_none ( ) {
break 'outer ;
}
remaining = remain ;
2023-10-04 12:36:38 -04:00
break ;
}
2023-10-04 11:31:45 -04:00
}
2023-10-05 01:55:33 -04:00
if ! matched_a_word {
2023-10-17 10:09:37 -04:00
return Err ( nom ::Err ::Error ( CustomError ::Static ( " No words. " ) ) ) ;
2023-10-05 01:55:33 -04:00
}
let remaining = last_match_remaining ;
let ( remaining , _post_spaces ) = opt ( tuple ( ( space0 , peek ( line_ending ) ) ) ) ( remaining ) ? ;
let source = input . get_until ( remaining ) ;
2023-10-04 11:31:45 -04:00
2023-10-04 18:02:50 -04:00
// Handle state that didn't get processed because we ran out of words.
match state {
SwitchState ::Normal = > { }
SwitchState ::NewLineNumber = > {
number_lines = Some ( SwitchNumberLines ::New ( 0 ) ) ;
}
SwitchState ::ContinuedLineNumber = > {
number_lines = Some ( SwitchNumberLines ::Continued ( 0 ) ) ;
}
SwitchState ::LabelFormat = > { }
}
2023-10-04 16:21:37 -04:00
let retain_labels = match retain_labels {
RetainLabels ::Keep ( _ ) if ! saw_r = > RetainLabels ::Yes ,
_ = > retain_labels ,
} ;
2023-10-04 11:31:45 -04:00
Ok ( (
remaining ,
2023-10-04 16:58:45 -04:00
ExampleSrcSwitches {
2023-10-04 11:31:45 -04:00
source : Into ::< & str > ::into ( source ) ,
number_lines ,
2023-10-04 12:36:38 -04:00
retain_labels ,
2023-10-04 19:23:47 -04:00
preserve_indent ,
2023-10-04 12:36:38 -04:00
use_labels ,
label_format ,
2023-10-04 11:31:45 -04:00
} ,
) )
}
2023-10-04 12:36:38 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-10-05 01:55:33 -04:00
fn switch_word < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-10-04 12:36:38 -04:00
alt ( (
map (
tuple ( ( tag ( r # """# ) , is_not ( " \" \r \n " ) , tag ( r # """# ) ) ) ,
| ( _ , contents , _ ) | contents ,
) ,
is_not ( " \t \r \n " ) ,
) ) ( input )
}