Repository: sharkdp/bat
File: src/features.rs (Rust)

Code before:
) -> Result<()> {
    let stdin = io::stdin(); // TODO: this is not always needed
    {
        let reader: Box<BufRead> = match filename {
            None => Box::new(stdin.lock()),
            Some(filename) => Box::new(BufReader::new(File::open(filename)?)),
        };

        let highlighter = HighlightLines::new(syntax, theme);

        printer.print_header(filename)?;

        match printer.config.line_range.as_ref() {
            Some(range) => {
                print_file_ranges(printer, reader, highlighter, range)?;
            },
            None => {
                print_file_no_ranges(printer, reader, highlighter)?;
            }
        }
        printer.print_footer()?;
    }
    Ok(())
}

fn print_file_ranges<'a>(
    printer: &mut Printer,
    mut reader: Box<BufRead + 'a>,
    mut highlighter: HighlightLines,
    ranges: &LineRange
) -> Result<()>{
    let mut buffer = Vec::new();

    while reader.read_until(b'\n', &mut buffer)? > 0 {
        {
            let line = String::from_utf8_lossy(&buffer);
            let regions = highlighter.highlight(line.as_ref());

            if printer.line_number + 1 < ranges.lower {
                // skip line
                printer.line_number += 1;
            } else if printer.line_number >= ranges.upper {
                // no more lines in range
                break;
            } else {
                printer.print_line(&regions)?;
            }
        }
        buffer.clear();
    }
    Ok(())

Review comment (suggestion):
It would be really great if we had just a single function and would avoid this code duplication. I would try to change the `ranges` parameter to accept an `Option<Range>`.

Code after:
) -> Result<()> {
    let stdin = io::stdin(); // TODO: this is not always needed
    {
        let reader: Box<BufRead> = match filename {
            None => Box::new(stdin.lock()),
            Some(filename) => Box::new(BufReader::new(File::open(filename)?)),
        };

        let highlighter = HighlightLines::new(syntax, theme);

        printer.print_header(filename)?;
        print_file_ranges(printer, reader, highlighter, &printer.config.line_range)?;
        printer.print_footer()?;
    }
    Ok(())
}

fn print_file_ranges<'a>(
    printer: &mut Printer,
    mut reader: Box<BufRead + 'a>,
    mut highlighter: HighlightLines,
    line_ranges: &Option<LineRange>,
) -> Result<()> {
    let mut buffer = Vec::new();

    while reader.read_until(b'\n', &mut buffer)? > 0 {
        {
            let line = String::from_utf8_lossy(&buffer);
            let regions = highlighter.highlight(line.as_ref());

            match line_ranges {
                &Some(ref range) => {
                    if printer.line_number + 1 < range.lower {
                        // skip line
                        printer.line_number += 1;
                    } else if printer.line_number >= range.upper {
                        // no more lines in range
                        break;
                    } else {
                        printer.print_line(&regions)?;
                    }
                }
                &None => {
                    printer.print_line(&regions)?;
                }
            }
        }
        buffer.clear();
    }
    Ok(())
}