Factor out the use of different ranges from linktype

This eliminates some duplication and will enable different kinds of
LinkTypes to have line number ranges.

Implement `From` for the std `Range` types to enable easier
construction.

The new code reaaalllly makes me wish for a delegation mechanism though
:(
This commit is contained in:
Carol (Nichols || Goulding) 2019-07-23 20:45:43 -04:00
parent 0f56c09d3a
commit 07459aef60
No known key found for this signature in database
GPG Key ID: D04B39A6CA243902
1 changed files with 67 additions and 60 deletions

View File

@ -2,7 +2,7 @@ use crate::errors::*;
use crate::utils::{take_anchored_lines, take_lines}; use crate::utils::{take_anchored_lines, take_lines};
use regex::{CaptureMatches, Captures, Regex}; use regex::{CaptureMatches, Captures, Regex};
use std::fs; use std::fs;
use std::ops::{Range, RangeFrom, RangeFull, RangeTo}; use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeTo};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use super::{Preprocessor, PreprocessorContext}; use super::{Preprocessor, PreprocessorContext};
@ -102,23 +102,70 @@ where
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
enum LinkType<'a> { enum LinkType<'a> {
Escaped, Escaped,
IncludeRange(PathBuf, Range<usize>), IncludeRange(PathBuf, LineRange),
IncludeRangeFrom(PathBuf, RangeFrom<usize>),
IncludeRangeTo(PathBuf, RangeTo<usize>),
IncludeRangeFull(PathBuf, RangeFull),
IncludeAnchor(PathBuf, String), IncludeAnchor(PathBuf, String),
Playpen(PathBuf, Vec<&'a str>), Playpen(PathBuf, Vec<&'a str>),
} }
// A range of lines specified with some include directive.
#[derive(PartialEq, Debug, Clone)]
enum LineRange {
Range(Range<usize>),
RangeFrom(RangeFrom<usize>),
RangeTo(RangeTo<usize>),
RangeFull(RangeFull),
}
impl RangeBounds<usize> for LineRange {
fn start_bound(&self) -> Bound<&usize> {
match self {
LineRange::Range(r) => r.start_bound(),
LineRange::RangeFrom(r) => r.start_bound(),
LineRange::RangeTo(r) => r.start_bound(),
LineRange::RangeFull(r) => r.start_bound(),
}
}
fn end_bound(&self) -> Bound<&usize> {
match self {
LineRange::Range(r) => r.end_bound(),
LineRange::RangeFrom(r) => r.end_bound(),
LineRange::RangeTo(r) => r.end_bound(),
LineRange::RangeFull(r) => r.end_bound(),
}
}
}
impl From<Range<usize>> for LineRange {
fn from(r: Range<usize>) -> LineRange {
LineRange::Range(r)
}
}
impl From<RangeFrom<usize>> for LineRange {
fn from(r: RangeFrom<usize>) -> LineRange {
LineRange::RangeFrom(r)
}
}
impl From<RangeTo<usize>> for LineRange {
fn from(r: RangeTo<usize>) -> LineRange {
LineRange::RangeTo(r)
}
}
impl From<RangeFull> for LineRange {
fn from(r: RangeFull) -> LineRange {
LineRange::RangeFull(r)
}
}
impl<'a> LinkType<'a> { impl<'a> LinkType<'a> {
fn relative_path<P: AsRef<Path>>(self, base: P) -> Option<PathBuf> { fn relative_path<P: AsRef<Path>>(self, base: P) -> Option<PathBuf> {
let base = base.as_ref(); let base = base.as_ref();
match self { match self {
LinkType::Escaped => None, LinkType::Escaped => None,
LinkType::IncludeRange(p, _) => Some(return_relative_path(base, &p)), LinkType::IncludeRange(p, _) => Some(return_relative_path(base, &p)),
LinkType::IncludeRangeFrom(p, _) => Some(return_relative_path(base, &p)),
LinkType::IncludeRangeTo(p, _) => Some(return_relative_path(base, &p)),
LinkType::IncludeRangeFull(p, _) => Some(return_relative_path(base, &p)),
LinkType::IncludeAnchor(p, _) => Some(return_relative_path(base, &p)), LinkType::IncludeAnchor(p, _) => Some(return_relative_path(base, &p)),
LinkType::Playpen(p, _) => Some(return_relative_path(base, &p)), LinkType::Playpen(p, _) => Some(return_relative_path(base, &p)),
} }
@ -155,24 +202,21 @@ fn parse_include_path(path: &str) -> LinkType<'static> {
let end = end.and_then(|s| s.parse::<usize>().ok()); let end = end.and_then(|s| s.parse::<usize>().ok());
match start { match start {
Some(start) => match end { Some(start) => match end {
Some(end) => LinkType::IncludeRange(path, Range { start, end }), Some(end) => LinkType::IncludeRange(path, LineRange::from(start..end)),
None => { None => {
if has_end { if has_end {
LinkType::IncludeRangeFrom(path, RangeFrom { start }) LinkType::IncludeRange(path, LineRange::from(start..))
} else { } else {
LinkType::IncludeRange( LinkType::IncludeRange(
path, path,
Range { LineRange::from(start..start + 1),
start,
end: start + 1,
},
) )
} }
} }
}, },
None => match end { None => match end {
Some(end) => LinkType::IncludeRangeTo(path, RangeTo { end }), Some(end) => LinkType::IncludeRange(path, LineRange::from(..end)),
None => LinkType::IncludeRangeFull(path, RangeFull), None => LinkType::IncludeRange(path, LineRange::from(RangeFull)),
}, },
} }
} }
@ -233,43 +277,6 @@ impl<'a> Link<'a> {
) )
}) })
} }
LinkType::IncludeRangeFrom(ref pat, ref range) => {
let target = base.join(pat);
fs::read_to_string(&target)
.map(|s| take_lines(&s, range.clone()))
.chain_err(|| {
format!(
"Could not read file for link {} ({})",
self.link_text,
target.display(),
)
})
}
LinkType::IncludeRangeTo(ref pat, ref range) => {
let target = base.join(pat);
fs::read_to_string(&target)
.map(|s| take_lines(&s, *range))
.chain_err(|| {
format!(
"Could not read file for link {} ({})",
self.link_text,
target.display(),
)
})
}
LinkType::IncludeRangeFull(ref pat, _) => {
let target = base.join(pat);
fs::read_to_string(&target).chain_err(|| {
format!(
"Could not read file for link {} ({})",
self.link_text,
target.display()
)
})
}
LinkType::IncludeAnchor(ref pat, ref anchor) => { LinkType::IncludeAnchor(ref pat, ref anchor) => {
let target = base.join(pat); let target = base.join(pat);
@ -421,7 +428,7 @@ mod tests {
vec![Link { vec![Link {
start_index: 22, start_index: 22,
end_index: 48, end_index: 48,
link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), 9..20), link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(9..20)),
link_text: "{{#include file.rs:10:20}}", link_text: "{{#include file.rs:10:20}}",
}] }]
); );
@ -437,7 +444,7 @@ mod tests {
vec![Link { vec![Link {
start_index: 22, start_index: 22,
end_index: 45, end_index: 45,
link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), 9..10), link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(9..10)),
link_text: "{{#include file.rs:10}}", link_text: "{{#include file.rs:10}}",
}] }]
); );
@ -453,7 +460,7 @@ mod tests {
vec![Link { vec![Link {
start_index: 22, start_index: 22,
end_index: 46, end_index: 46,
link_type: LinkType::IncludeRangeFrom(PathBuf::from("file.rs"), 9..), link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(9..)),
link_text: "{{#include file.rs:10:}}", link_text: "{{#include file.rs:10:}}",
}] }]
); );
@ -469,7 +476,7 @@ mod tests {
vec![Link { vec![Link {
start_index: 22, start_index: 22,
end_index: 46, end_index: 46,
link_type: LinkType::IncludeRangeTo(PathBuf::from("file.rs"), ..20), link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(..20)),
link_text: "{{#include file.rs::20}}", link_text: "{{#include file.rs::20}}",
}] }]
); );
@ -485,7 +492,7 @@ mod tests {
vec![Link { vec![Link {
start_index: 22, start_index: 22,
end_index: 44, end_index: 44,
link_type: LinkType::IncludeRangeFull(PathBuf::from("file.rs"), ..), link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(..)),
link_text: "{{#include file.rs::}}", link_text: "{{#include file.rs::}}",
}] }]
); );
@ -501,7 +508,7 @@ mod tests {
vec![Link { vec![Link {
start_index: 22, start_index: 22,
end_index: 42, end_index: 42,
link_type: LinkType::IncludeRangeFull(PathBuf::from("file.rs"), ..), link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(..)),
link_text: "{{#include file.rs}}", link_text: "{{#include file.rs}}",
}] }]
); );
@ -587,7 +594,7 @@ mod tests {
Link { Link {
start_index: 38, start_index: 38,
end_index: 58, end_index: 58,
link_type: LinkType::IncludeRangeFull(PathBuf::from("file.rs"), ..), link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(..)),
link_text: "{{#include file.rs}}", link_text: "{{#include file.rs}}",
} }
); );