Lints and suggestions for the Nix programming language
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add support for errfmt friendly output

Akshay c79799c0 2e7b95f2

+96 -41
+1 -1
bin/src/main.rs
··· 49 49 50 50 let mut stderr = io::stderr(); 51 51 lint_results.for_each(|r| { 52 - stderr.write(&r, &vfs).unwrap(); 52 + stderr.write(&r, &vfs, lint_config.format).unwrap(); 53 53 }); 54 54 errors.for_each(|e| { 55 55 eprintln!("{}", e);
+95 -40
bin/src/traits.rs
··· 3 3 str, 4 4 }; 5 5 6 - use crate::lint::LintResult; 6 + use crate::{config::OutFormat, lint::LintResult}; 7 7 8 8 use ariadne::{ 9 9 CharSet, Color, Config as CliConfig, Fmt, Label, LabelAttach, Report as CliReport, ··· 13 13 use vfs::ReadOnlyVfs; 14 14 15 15 pub trait WriteDiagnostic { 16 - fn write(&mut self, report: &LintResult, vfs: &ReadOnlyVfs) -> io::Result<()>; 16 + fn write( 17 + &mut self, 18 + report: &LintResult, 19 + vfs: &ReadOnlyVfs, 20 + format: OutFormat, 21 + ) -> io::Result<()>; 17 22 } 18 23 19 24 impl<T> WriteDiagnostic for T 20 25 where 21 26 T: Write, 22 27 { 23 - fn write(&mut self, lint_result: &LintResult, vfs: &ReadOnlyVfs) -> io::Result<()> { 24 - let file_id = lint_result.file_id; 25 - let src = str::from_utf8(vfs.get(file_id)).unwrap(); 26 - let path = vfs.file_path(file_id); 27 - let range = |at: TextRange| at.start().into()..at.end().into(); 28 - let src_id = path.to_str().unwrap_or("<unknown>"); 29 - for report in lint_result.reports.iter() { 30 - let offset = report 31 - .diagnostics 32 - .iter() 33 - .map(|d| d.at.start().into()) 34 - .min() 35 - .unwrap_or(0usize); 36 - report 37 - .diagnostics 38 - .iter() 39 - .fold( 40 - CliReport::build(CliReportKind::Warning, src_id, offset) 41 - .with_config( 42 - CliConfig::default() 43 - .with_cross_gap(true) 44 - .with_multiline_arrows(false) 45 - .with_label_attach(LabelAttach::Middle) 46 - .with_char_set(CharSet::Unicode), 47 - ) 48 - .with_message(report.note) 49 - .with_code(report.code), 50 - |cli_report, diagnostic| { 51 - cli_report.with_label( 52 - Label::new((src_id, range(diagnostic.at))) 53 - .with_message(&colorize(&diagnostic.message)) 54 - .with_color(Color::Magenta), 55 - ) 56 - }, 57 - ) 58 - .finish() 59 - .write((src_id, Source::from(src)), &mut *self)?; 28 + fn write( 29 + &mut self, 30 + lint_result: &LintResult, 31 + vfs: &ReadOnlyVfs, 32 + format: OutFormat, 33 + ) -> io::Result<()> { 34 + match format { 35 + OutFormat::StdErr => write_stderr(self, lint_result, vfs), 36 + OutFormat::Errfmt => write_errfmt(self, lint_result, vfs), 37 + _ => Ok(()), 38 + } 39 + } 40 + } 41 + 42 + fn write_stderr<T: Write>( 43 + writer: &mut T, 44 + lint_result: &LintResult, 45 + vfs: &ReadOnlyVfs, 46 + ) -> io::Result<()> { 47 + let file_id = lint_result.file_id; 48 + let src = str::from_utf8(vfs.get(file_id)).unwrap(); 49 + let path = vfs.file_path(file_id); 50 + let range = |at: TextRange| at.start().into()..at.end().into(); 51 + let src_id = path.to_str().unwrap_or("<unknown>"); 52 + for report in lint_result.reports.iter() { 53 + let offset = report 54 + .diagnostics 55 + .iter() 56 + .map(|d| d.at.start().into()) 57 + .min() 58 + .unwrap_or(0usize); 59 + report 60 + .diagnostics 61 + .iter() 62 + .fold( 63 + CliReport::build(CliReportKind::Warning, src_id, offset) 64 + .with_config( 65 + CliConfig::default() 66 + .with_cross_gap(true) 67 + .with_multiline_arrows(false) 68 + .with_label_attach(LabelAttach::Middle) 69 + .with_char_set(CharSet::Unicode), 70 + ) 71 + .with_message(report.note) 72 + .with_code(report.code), 73 + |cli_report, diagnostic| { 74 + cli_report.with_label( 75 + Label::new((src_id, range(diagnostic.at))) 76 + .with_message(&colorize(&diagnostic.message)) 77 + .with_color(Color::Magenta), 78 + ) 79 + }, 80 + ) 81 + .finish() 82 + .write((src_id, Source::from(src)), &mut *writer)?; 83 + } 84 + Ok(()) 85 + } 86 + 87 + fn write_errfmt<T: Write>(writer: &mut T, lint_result: &LintResult, vfs: &ReadOnlyVfs) -> io::Result<()> { 88 + let file_id = lint_result.file_id; 89 + let src = str::from_utf8(vfs.get(file_id)).unwrap(); 90 + let path = vfs.file_path(file_id); 91 + for report in lint_result.reports.iter() { 92 + for diagnostic in report.diagnostics.iter() { 93 + let line = line(diagnostic.at, &src); 94 + let col = column(diagnostic.at, &src); 95 + writeln!( 96 + writer, 97 + "{filename}>{linenumber}:{columnnumber}:{errortype}:{errornumber}:{errormessage}", 98 + filename = path.to_str().unwrap_or("<unknown>"), 99 + linenumber = line, 100 + columnnumber = col, 101 + errortype = "W", 102 + errornumber = report.code, 103 + errormessage = diagnostic.message 104 + )?; 60 105 } 61 - Ok(()) 62 106 } 107 + Ok(()) 108 + } 109 + 110 + fn line(at: TextRange, src: &str) -> usize { 111 + let at = at.start().into(); 112 + src[..at].chars().filter(|&c| c == '\n').count() + 1 113 + } 114 + 115 + fn column(at: TextRange, src: &str) -> usize { 116 + let at = at.start().into(); 117 + src[..at].rfind('\n').map(|c| at - c).unwrap_or(at + 1) 63 118 } 64 119 65 120 // everything within backticks is colorized, backticks are removed