rnix 0.14.0

A Nix parser written in Rust
Documentation
use rnix::ParseError;
use std::{env, fs};

fn main() {
    let file = match env::args().nth(1) {
        Some(file) => file,
        None => {
            eprintln!("Usage: error-report <file>");
            return;
        }
    };
    let content = match fs::read_to_string(&file) {
        Ok(content) => content,
        Err(err) => {
            eprintln!("error reading file: {}", err);
            return;
        }
    };
    let ast = rnix::Root::parse(&content);
    for error in ast.errors() {
        let range = match error {
            ParseError::Unexpected(range) => range,
            ParseError::UnexpectedExtra(range) => range,
            ParseError::UnexpectedWanted(_, range, _) => range,
            ParseError::UnexpectedDoubleBind(range) => range,
            ParseError::DuplicatedArgs(range, _) => range,
            err => {
                eprintln!("error: {}", err);
                continue;
            }
        };
        eprintln!("----- ERROR -----");
        eprintln!("{}", error);
        let start = usize::from(range.start());
        let start_row = content[..start].lines().count() - 1;
        let start_line = content[..start].rfind('\n').map(|i| i + 1).unwrap_or(0);
        let start_col = content[start_line..start].chars().count();
        let end = usize::from(range.end());
        let end_row = content[..end].lines().count() - 1;
        let end_line = content[..end].rfind('\n').map(|i| i + 1).unwrap_or(0);
        let end_col = content[end_line..end].chars().count();

        let mut line_len = 1;
        let mut line = end_row;
        while line >= 10 {
            line /= 10;
            line_len += 1;
        }

        let i = start_row.saturating_sub(1);
        for (i, line) in content.lines().enumerate().skip(i).take(end_row - i + 1) {
            println!("{:line_len$} {}", i + 1, line, line_len = line_len);
            if i >= start_row && i <= end_row {
                print!("{:line_len$} ", "", line_len = line_len);
                let mut end_col = if i == end_row { end_col } else { line.chars().count() };
                if i == start_row {
                    print!("{:indent$}", "", indent = start_col);
                    end_col -= start_col;
                }
                for _ in 0..end_col {
                    print!("^");
                }
                println!();
            }
        }
    }
}