diff --git a/src/main.rs b/src/main.rs index b6359e2f..1ada841a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,6 @@ -use nom::bytes::complete::tag; +use std::ops::RangeBounds; + +use nom::{bytes::complete::tag, Compare, InputTake, Slice}; fn main() { let input = "this is my test input".to_owned(); @@ -11,11 +13,86 @@ fn main() { #[derive(Debug)] struct WrappedInput<'s> { - contents: &'s str, + full_source: &'s str, + start: usize, + end: usize, //exclusive + preceding_line_break: Option, } impl<'s> WrappedInput<'s> { + /// Returns a wrapped string that keeps track of values we need for parsing org-mode. + /// + /// Only call this on the full original string. Calling this on a substring can result in invalid values. pub fn new(input: &'s str) -> Self { - WrappedInput { contents: input } + WrappedInput { + full_source: input, + start: 0, + end: input.len(), + preceding_line_break: None, + } + } +} + +impl<'s> InputTake for WrappedInput<'s> { + fn take(&self, count: usize) -> Self { + self.slice(..count) + } + + fn take_split(&self, count: usize) -> (Self, Self) { + (self.slice(count..), self.slice(..count)) + } +} + +impl<'s, O: Into<&'s str>> Compare for WrappedInput<'s> { + fn compare(&self, t: O) -> nom::CompareResult { + (&self.full_source[self.start..self.end]).compare(t.into()) + } + + fn compare_no_case(&self, t: O) -> nom::CompareResult { + (&self.full_source[self.start..self.end]).compare_no_case(t.into()) + } +} + +impl<'s> From<&'s str> for WrappedInput<'s> { + fn from(value: &'s str) -> Self { + WrappedInput::new(value) + } +} + +impl<'s> From<&WrappedInput<'s>> for &'s str { + fn from(value: &WrappedInput<'s>) -> Self { + &value.full_source[value.start..value.end] + } +} + +impl<'s, R> Slice for WrappedInput<'s> +where + R: RangeBounds, +{ + fn slice(&self, range: R) -> Self { + let new_start = match range.start_bound() { + std::ops::Bound::Included(idx) => self.start + idx, + std::ops::Bound::Excluded(idx) => self.start + idx - 1, + std::ops::Bound::Unbounded => self.start, + }; + let new_end = match range.end_bound() { + std::ops::Bound::Included(idx) => self.start + idx, + std::ops::Bound::Excluded(idx) => self.start + idx - 1, + std::ops::Bound::Unbounded => self.start, + }; + + // TODO: calculate updated values for WrappedInput + WrappedInput { + full_source: self.full_source, + start: new_start, + end: new_end, + preceding_line_break: None, + } + } +} + +impl<'s> std::fmt::Display for WrappedInput<'s> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + Into::<&str>::into(self).fmt(f) } }