on master help sign in
update line-ranges
commit26dbdf4fa07534509ad7638a7ac4b425410c6b6e authorTaylor Skinner <tskinn12@gmail.com> dateMon 4 Jun 2018, 17:07 (8 years ago) parent6691786
3 files changed+111−44
src/app.rs+58−23 src/features.rs+52−21 src/main.rs+1
src/app.rs+58−23
@@ -148,8 +148,10 @@ impl App {
148148 .takes_value(true)
149149 .help("Print range of lines")
150150 .long_help(
151− "Print a specified range of lines from the files \
152− --line-range 30-40 or --line-range 30-",
151+ "Print a specified range or ranges of lines from the files. \
152+ For example: '--line-range 30:40' will print lines 30 to 40 \n\
153+ '--line-range :40' will print lines 1 to 40 \n\
154+ '--line-range 40:' will print lines 40 to the end of the file",
153155 ),
154156 )
155157 .arg(
@@ -280,7 +282,7 @@ impl App {
280282 term_width: Term::stdout().size().1 as usize,
281283 files,
282284 theme: self.matches.value_of("theme"),
283− line_range: get_ranges(self.matches.value_of("line-range")),
285+ line_range: LineRange::from(self.matches.value_of("line-range")),
284286 })
285287 }
286288
@@ -334,7 +336,7 @@ pub struct Config<'a> {
334336 pub term_width: usize,
335337 pub files: Vec<Option<&'a str>>,
336338 pub theme: Option<&'a str>,
337− pub line_range: Option<(usize, usize)>,
339+ pub line_range: Option<LineRange>,
338340}
339341
340342fn is_truecolor_terminal() -> bool {
@@ -343,28 +345,61 @@ fn is_truecolor_terminal() -> bool {
343345 .unwrap_or(false)
344346}
345347
346−fn get_ranges(value: Option<&str>) -> Option<(usize, usize)> {
347− match value {
348− None => None,
349− Some(str_range) => {
350− let mut new_range = (usize::min_value(), usize::max_value());
351− if str_range.bytes().nth(0).expect("Something should be here!") == b':' {
352− new_range.1 = str_range[1..].parse().expect("This should be a number!");
353− return Some(new_range);
354− } else if str_range.bytes().last().expect("There should be a last!") == b':' {
355− new_range.0 = str_range[..str_range.len() - 1]
356− .parse()
357− .expect("This should be a number!");
358− return Some(new_range);
359− }
348+pub struct LineRange {
349+ pub lower: usize,
350+ pub upper: usize,
351+}
360352
361− let line_numbers: Vec<&str> = str_range.split(':').collect();
362− if line_numbers.len() == 2 {
363− new_range.0 = line_numbers[0].parse().expect("Should be a number!");
364− new_range.1 = line_numbers[1].parse().expect("Should be a number!");
353+impl LineRange {
354+ pub fn from(value: Option<&str>) -> Option<LineRange> {
355+ match value {
356+ None => None,
357+ Some(range_raw) => {
358+ return LineRange::parse_range(range_raw).ok();
365359 }
360+ }
361+ }
362+
363+ pub fn parse_range(range_raw: &str) -> Result<LineRange> {
364+ let mut new_range = LineRange{
365+ lower: usize::min_value(),
366+ upper: usize::max_value(),
367+ };
368+
369+ if range_raw.bytes().nth(0).ok_or("No first byte")? == b':' {
370+ new_range.upper = range_raw[1..].parse()?;
371+ return Ok(new_range);
372+ } else if range_raw.bytes().last().ok_or("No last byte")? == b':' {
373+ new_range.lower = range_raw[..range_raw.len() - 1].parse()?;
374+ return Ok(new_range);
375+ }
366376
367− Some(new_range)
377+ let line_numbers: Vec<&str> = range_raw.split(':').collect();
378+ if line_numbers.len() == 2 {
379+ new_range.lower = line_numbers[0].parse()?;
380+ new_range.upper = line_numbers[1].parse()?;
368381 }
382+ Ok(new_range)
369383 }
370384}
385+
386+#[test]
387+fn test_parse_line_range_full() {
388+ let range = LineRange::from(Some("40:50")).expect("Shouldn't fail on test!");
389+ assert_eq!(40, range.lower);
390+ assert_eq!(50, range.upper);
391+}
392+
393+#[test]
394+fn test_parse_line_range_partial_min() {
395+ let range = LineRange::from(Some(":50")).expect("Shouldn't fail on test!");
396+ assert_eq!(usize::min_value(), range.lower);
397+ assert_eq!(50, range.upper);
398+}
399+
400+#[test]
401+fn test_parse_line_range_partial_max() {
402+ let range = LineRange::from(Some("40:")).expect("Shouldn't fail on test!");
403+ assert_eq!(40, range.lower);
404+ assert_eq!(usize::max_value(), range.upper);
405+}
src/features.rs+52−21
@@ -1,5 +1,5 @@
11use ansi_term::Colour::Green;
2−use app::Config;
2+use app::{Config,LineRange};
33use assets::HighlightingAssets;
44use diff::get_git_diff;
55use errors::*;
@@ -85,16 +85,35 @@ fn print_file(
8585 filename: Option<&str>,
8686) -> Result<()> {
8787 let stdin = io::stdin(); // TODO: this is not always needed
88+ {
89+ let reader: Box<BufRead> = match filename {
90+ None => Box::new(stdin.lock()),
91+ Some(filename) => Box::new(BufReader::new(File::open(filename)?)),
92+ };
93+
94+ let highlighter = HighlightLines::new(syntax, theme);
95+
96+ printer.print_header(filename)?;
97+
98+ match printer.config.line_range.as_ref() {
99+ Some(range) => {
100+ print_file_ranges(printer, reader, highlighter, range)?;
101+ },
102+ None => {
103+ print_file_no_ranges(printer, reader, highlighter)?;
104+ }
105+ }
106+ printer.print_footer()?;
107+ }
108+ Ok(())
109+}
88110
89− let mut reader: Box<BufRead> = match filename {
90− None => Box::new(stdin.lock()),
91− Some(filename) => Box::new(BufReader::new(File::open(filename)?)),
92− };
93−
94− let mut highlighter = HighlightLines::new(syntax, theme);
95−
96− printer.print_header(filename)?;
97−
111+fn print_file_ranges<'a>(
112+ printer: &mut Printer,
113+ mut reader: Box<BufRead + 'a>,
114+ mut highlighter: HighlightLines,
115+ ranges: &LineRange
116+) -> Result<()>{
98117 let mut buffer = Vec::new();
99118
100119 while reader.read_until(b'\n', &mut buffer)? > 0 {
@@ -102,24 +121,36 @@ fn print_file(
102121 let line = String::from_utf8_lossy(&buffer);
103122 let regions = highlighter.highlight(line.as_ref());
104123
105− if printer.config.line_range.is_some() {
106− if printer.line_number + 1 < printer.config.line_range.unwrap().0 {
107− // skip line
108− printer.line_number += 1;
109− } else if printer.line_number >= printer.config.line_range.unwrap().1 {
110− // no more lines in range
111− break;
112− } else {
113− printer.print_line(&regions)?;
114− }
124+ if printer.line_number + 1 < ranges.lower {
125+ // skip line
126+ printer.line_number += 1;
127+ } else if printer.line_number >= ranges.upper {
128+ // no more lines in range
129+ break;
115130 } else {
116131 printer.print_line(&regions)?;
117132 }
118133 }
119134 buffer.clear();
120135 }
136+ Ok(())
137+}
121138
122− printer.print_footer()?;
139+fn print_file_no_ranges<'a>(
140+ printer: &mut Printer,
141+ mut reader: Box<BufRead + 'a>,
142+ mut highlighter: HighlightLines
143+) -> Result<()>{
144+ let mut buffer = Vec::new();
145+
146+ while reader.read_until(b'\n', &mut buffer)? > 0 {
147+ {
148+ let line = String::from_utf8_lossy(&buffer);
149+ let regions = highlighter.highlight(line.as_ref());
150+ printer.print_line(&regions)?;
151+ }
152+ buffer.clear();
153+ }
123154
124155 Ok(())
125156}
src/main.rs+1
@@ -41,6 +41,7 @@ mod errors {
4141 Clap(::clap::Error);
4242 Io(::std::io::Error);
4343 SyntectError(::syntect::LoadingError);
44+ ParseIntError(::std::num::ParseIntError);
4445 }
4546 }
4647