Extract the line number from the switches.

This commit is contained in:
Tom Alexander 2023-10-04 11:31:45 -04:00
parent 3d7f411cf9
commit 317293f0f2
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
4 changed files with 93 additions and 4 deletions

View File

@ -0,0 +1,7 @@
#+begin_example -n -10
foo
#+end_example
#+begin_example +n -15
bar
#+end_example

View File

@ -0,0 +1,7 @@
#+begin_example -n 0
foo
#+end_example
#+begin_example +n 0
bar
#+end_example

View File

@ -6,10 +6,12 @@ use nom::character::complete::space0;
use nom::character::complete::space1; use nom::character::complete::space1;
use nom::combinator::consumed; use nom::combinator::consumed;
use nom::combinator::eof; use nom::combinator::eof;
use nom::combinator::map;
use nom::combinator::opt; use nom::combinator::opt;
use nom::combinator::recognize; use nom::combinator::recognize;
use nom::combinator::verify; use nom::combinator::verify;
use nom::multi::many_till; use nom::multi::many_till;
use nom::multi::separated_list1;
use nom::sequence::tuple; use nom::sequence::tuple;
use super::org_source::OrgSource; use super::org_source::OrgSource;
@ -29,9 +31,11 @@ use crate::parser::util::text_until_exit;
use crate::types::CommentBlock; use crate::types::CommentBlock;
use crate::types::ExampleBlock; use crate::types::ExampleBlock;
use crate::types::ExportBlock; use crate::types::ExportBlock;
use crate::types::LineNumber;
use crate::types::Object; use crate::types::Object;
use crate::types::PlainText; use crate::types::PlainText;
use crate::types::SrcBlock; use crate::types::SrcBlock;
use crate::types::SwitchNumberLines;
use crate::types::VerseBlock; use crate::types::VerseBlock;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
@ -130,7 +134,7 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>(
input: OrgSource<'s>, input: OrgSource<'s>,
) -> Res<OrgSource<'s>, ExampleBlock<'s>> { ) -> Res<OrgSource<'s>, ExampleBlock<'s>> {
let (remaining, _name) = lesser_block_begin("example")(context, input)?; let (remaining, _name) = lesser_block_begin("example")(context, input)?;
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?; let (remaining, parameters) = opt(tuple((space1, example_switches)))(remaining)?;
let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?; let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?;
let lesser_block_end_specialized = lesser_block_end("example"); let lesser_block_end_specialized = lesser_block_end("example");
let contexts = [ let contexts = [
@ -150,13 +154,20 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>(
let (remaining, _end) = lesser_block_end_specialized(&parser_context, remaining)?; let (remaining, _end) = lesser_block_end_specialized(&parser_context, remaining)?;
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
let (switches, number_lines) = {
if let Some(parameters) = parameters {
(Some(parameters.source), parameters.number_lines)
} else {
(None, None)
}
};
Ok(( Ok((
remaining, remaining,
ExampleBlock { ExampleBlock {
source: source.into(), source: source.into(),
name: source.into(), name: source.into(),
switches: parameters.map(|parameters| Into::<&str>::into(parameters)), switches,
number_lines: None, // TODO number_lines,
contents: contents.into(), contents: contents.into(),
}, },
)) ))
@ -302,3 +313,64 @@ fn _lesser_block_begin<'b, 'g, 'r, 's, 'c>(
))(remaining)?; ))(remaining)?;
Ok((remaining, name)) Ok((remaining, name))
} }
struct ExampleSwitches<'s> {
source: &'s str,
number_lines: Option<SwitchNumberLines>,
}
enum SwitchState {
Normal,
NewLineNumber,
ContinuedLineNumber,
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn example_switches<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ExampleSwitches<'s>> {
let mut number_lines = None;
let (remaining, (source, words)) = consumed(separated_list1(
space1,
map(is_not(" \t\r\n"), |val| Into::<&str>::into(val)),
))(input)?;
let mut state = SwitchState::Normal;
for word in words {
state = match (state, word) {
(SwitchState::Normal, "-n") => SwitchState::NewLineNumber,
(SwitchState::Normal, "+n") => SwitchState::ContinuedLineNumber,
(SwitchState::NewLineNumber, _) => {
let val = word
.parse::<LineNumber>()
.expect("TODO: I should be able to return CustomError from nom parsers.");
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));
}
SwitchState::Normal
}
(SwitchState::ContinuedLineNumber, _) => {
let val = word
.parse::<LineNumber>()
.expect("TODO: I should be able to return CustomError from nom parsers.");
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));
}
SwitchState::Normal
}
(state @ SwitchState::Normal, _) => state,
};
}
Ok((
remaining,
ExampleSwitches {
source: Into::<&str>::into(source),
number_lines,
},
))
}

View File

@ -108,7 +108,10 @@ pub struct LatexEnvironment<'s> {
pub source: &'s str, pub source: &'s str,
} }
pub type LineNumber = usize; /// A line number used in switches to lesser blocks.
///
/// This must be signed because emacs subtracts 1 from the actual value in the org-mode text, which makes a 0 turn into a -1.
pub type LineNumber = isize;
#[derive(Debug)] #[derive(Debug)]
pub enum SwitchNumberLines { pub enum SwitchNumberLines {