use rnix::parser::ParseError; use std::{env, fs}; fn main() { let file = match env::args().nth(1) { Some(file) => file, None => { eprintln!("Usage: error-report "); 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!(); } } } }