diff --git a/src/preprocess/links.rs b/src/preprocess/links.rs index 624d74d6a9..d4fd3105d2 100644 --- a/src/preprocess/links.rs +++ b/src/preprocess/links.rs @@ -102,11 +102,16 @@ where #[derive(PartialEq, Debug, Clone)] enum LinkType<'a> { Escaped, - IncludeRange(PathBuf, LineRange), - IncludeAnchor(PathBuf, String), + Include(PathBuf, RangeOrAnchor), Playpen(PathBuf, Vec<&'a str>), } +#[derive(PartialEq, Debug, Clone)] +enum RangeOrAnchor { + Range(LineRange), + Anchor(String), +} + // A range of lines specified with some include directive. #[derive(PartialEq, Debug, Clone)] enum LineRange { @@ -165,8 +170,7 @@ impl<'a> LinkType<'a> { let base = base.as_ref(); match self { LinkType::Escaped => None, - LinkType::IncludeRange(p, _) => Some(return_relative_path(base, &p)), - LinkType::IncludeAnchor(p, _) => Some(return_relative_path(base, &p)), + LinkType::Include(p, _) => Some(return_relative_path(base, &p)), LinkType::Playpen(p, _) => Some(return_relative_path(base, &p)), } } @@ -179,9 +183,8 @@ fn return_relative_path>(base: P, relative: P) -> PathBuf { .to_path_buf() } -fn parse_include_path(path: &str) -> LinkType<'static> { - let mut parts = path.splitn(4, ':').fuse(); - let path = parts.next().unwrap().into(); +fn parse_range_or_anchor(parts: Option<&str>) -> RangeOrAnchor { + let mut parts = parts.unwrap_or("").splitn(3, ':').fuse(); let next_element = parts.next(); let start = if let Some(value) = next_element.and_then(|s| s.parse::().ok()) { @@ -190,7 +193,7 @@ fn parse_include_path(path: &str) -> LinkType<'static> { } else if let Some("") = next_element { None } else if let Some(anchor) = next_element { - return LinkType::IncludeAnchor(path, String::from(anchor)); + return RangeOrAnchor::Anchor(String::from(anchor)); } else { None }; @@ -202,16 +205,23 @@ fn parse_include_path(path: &str) -> LinkType<'static> { let end = end.map(|s| s.parse::()); match (start, end) { - (Some(start), Some(Ok(end))) => LinkType::IncludeRange(path, LineRange::from(start..end)), - (Some(start), Some(Err(_))) => LinkType::IncludeRange(path, LineRange::from(start..)), - (Some(start), None) => LinkType::IncludeRange(path, LineRange::from(start..start + 1)), - (None, Some(Ok(end))) => LinkType::IncludeRange(path, LineRange::from(..end)), - (None, None) | (None, Some(Err(_))) => { - LinkType::IncludeRange(path, LineRange::from(RangeFull)) - } + (Some(start), Some(Ok(end))) => RangeOrAnchor::Range(LineRange::from(start..end)), + (Some(start), Some(Err(_))) => RangeOrAnchor::Range(LineRange::from(start..)), + (Some(start), None) => RangeOrAnchor::Range(LineRange::from(start..start + 1)), + (None, Some(Ok(end))) => RangeOrAnchor::Range(LineRange::from(..end)), + (None, None) | (None, Some(Err(_))) => RangeOrAnchor::Range(LineRange::from(RangeFull)), } } +fn parse_include_path(path: &str) -> LinkType<'static> { + let mut parts = path.splitn(2, ':'); + + let path = parts.next().unwrap().into(); + let range_or_anchor = parse_range_or_anchor(parts.next()); + + LinkType::Include(path, range_or_anchor) +} + #[derive(PartialEq, Debug, Clone)] struct Link<'a> { start_index: usize, @@ -255,24 +265,14 @@ impl<'a> Link<'a> { match self.link_type { // omit the escape char LinkType::Escaped => Ok((&self.link_text[1..]).to_owned()), - LinkType::IncludeRange(ref pat, ref range) => { + LinkType::Include(ref pat, ref range_or_anchor) => { 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(), - ) + .map(|s| match range_or_anchor { + RangeOrAnchor::Range(range) => take_lines(&s, range.clone()), + RangeOrAnchor::Anchor(anchor) => take_anchored_lines(&s, anchor), }) - } - LinkType::IncludeAnchor(ref pat, ref anchor) => { - let target = base.join(pat); - - fs::read_to_string(&target) - .map(|s| take_anchored_lines(&s, anchor)) .chain_err(|| { format!( "Could not read file for link {} ({})", @@ -419,7 +419,10 @@ mod tests { vec![Link { start_index: 22, end_index: 48, - link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(9..20)), + link_type: LinkType::Include( + PathBuf::from("file.rs"), + RangeOrAnchor::Range(LineRange::from(9..20)) + ), link_text: "{{#include file.rs:10:20}}", }] ); @@ -435,7 +438,10 @@ mod tests { vec![Link { start_index: 22, end_index: 45, - link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(9..10)), + link_type: LinkType::Include( + PathBuf::from("file.rs"), + RangeOrAnchor::Range(LineRange::from(9..10)) + ), link_text: "{{#include file.rs:10}}", }] ); @@ -451,7 +457,10 @@ mod tests { vec![Link { start_index: 22, end_index: 46, - link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(9..)), + link_type: LinkType::Include( + PathBuf::from("file.rs"), + RangeOrAnchor::Range(LineRange::from(9..)) + ), link_text: "{{#include file.rs:10:}}", }] ); @@ -467,7 +476,10 @@ mod tests { vec![Link { start_index: 22, end_index: 46, - link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(..20)), + link_type: LinkType::Include( + PathBuf::from("file.rs"), + RangeOrAnchor::Range(LineRange::from(..20)) + ), link_text: "{{#include file.rs::20}}", }] ); @@ -483,7 +495,10 @@ mod tests { vec![Link { start_index: 22, end_index: 44, - link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(..)), + link_type: LinkType::Include( + PathBuf::from("file.rs"), + RangeOrAnchor::Range(LineRange::from(..)) + ), link_text: "{{#include file.rs::}}", }] ); @@ -499,7 +514,10 @@ mod tests { vec![Link { start_index: 22, end_index: 42, - link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(..)), + link_type: LinkType::Include( + PathBuf::from("file.rs"), + RangeOrAnchor::Range(LineRange::from(..)) + ), link_text: "{{#include file.rs}}", }] ); @@ -515,9 +533,9 @@ mod tests { vec![Link { start_index: 22, end_index: 49, - link_type: LinkType::IncludeAnchor( + link_type: LinkType::Include( PathBuf::from("file.rs"), - String::from("anchor") + RangeOrAnchor::Anchor(String::from("anchor")) ), link_text: "{{#include file.rs:anchor}}", }] @@ -585,7 +603,10 @@ mod tests { Link { start_index: 38, end_index: 58, - link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), LineRange::from(..)), + link_type: LinkType::Include( + PathBuf::from("file.rs"), + RangeOrAnchor::Range(LineRange::from(..)) + ), link_text: "{{#include file.rs}}", } ); @@ -617,7 +638,10 @@ mod tests { let link_type = parse_include_path("arbitrary"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(RangeFull)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(RangeFull)) + ) ); } @@ -626,7 +650,10 @@ mod tests { let link_type = parse_include_path("arbitrary:"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(RangeFull)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(RangeFull)) + ) ); } @@ -635,7 +662,10 @@ mod tests { let link_type = parse_include_path("arbitrary::"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(RangeFull)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(RangeFull)) + ) ); } @@ -644,7 +674,10 @@ mod tests { let link_type = parse_include_path("arbitrary::NaN"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(RangeFull)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(RangeFull)) + ) ); } @@ -653,7 +686,10 @@ mod tests { let link_type = parse_include_path("arbitrary:5"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(4..5)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(4..5)) + ) ); } @@ -662,7 +698,10 @@ mod tests { let link_type = parse_include_path("arbitrary:1"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(0..1)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(0..1)) + ) ); } @@ -671,7 +710,10 @@ mod tests { let link_type = parse_include_path("arbitrary:0"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(0..1)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(0..1)) + ) ); } @@ -680,7 +722,10 @@ mod tests { let link_type = parse_include_path("arbitrary:5:"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(4..)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(4..)) + ) ); } @@ -689,7 +734,10 @@ mod tests { let link_type = parse_include_path("arbitrary:5:NaN"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(4..)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(4..)) + ) ); } @@ -698,7 +746,10 @@ mod tests { let link_type = parse_include_path("arbitrary::5"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(..5)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(..5)) + ) ); } @@ -707,7 +758,10 @@ mod tests { let link_type = parse_include_path("arbitrary:5:10"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(4..10)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(4..10)) + ) ); } @@ -716,7 +770,10 @@ mod tests { let link_type = parse_include_path("arbitrary:-5"); assert_eq!( link_type, - LinkType::IncludeAnchor(PathBuf::from("arbitrary"), "-5".to_string()) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Anchor("-5".to_string()) + ) ); } @@ -725,7 +782,10 @@ mod tests { let link_type = parse_include_path("arbitrary:-5.7"); assert_eq!( link_type, - LinkType::IncludeAnchor(PathBuf::from("arbitrary"), "-5.7".to_string()) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Anchor("-5.7".to_string()) + ) ); } @@ -734,7 +794,10 @@ mod tests { let link_type = parse_include_path("arbitrary:some-anchor:this-gets-ignored"); assert_eq!( link_type, - LinkType::IncludeAnchor(PathBuf::from("arbitrary"), "some-anchor".to_string()) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Anchor("some-anchor".to_string()) + ) ); } @@ -743,7 +806,10 @@ mod tests { let link_type = parse_include_path("arbitrary:5:10:17:anything:"); assert_eq!( link_type, - LinkType::IncludeRange(PathBuf::from("arbitrary"), LineRange::from(4..10)) + LinkType::Include( + PathBuf::from("arbitrary"), + RangeOrAnchor::Range(LineRange::from(4..10)) + ) ); } }