mirror of
https://github.com/oxalica/nil.git
synced 2025-12-23 09:19:49 +00:00
CLI for diagnostics
This commit is contained in:
parent
f1c2dbc857
commit
dfd91e3b7e
4 changed files with 149 additions and 1 deletions
35
Cargo.lock
generated
35
Cargo.lock
generated
|
|
@ -64,6 +64,16 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "countme"
|
||||
version = "3.0.1"
|
||||
|
|
@ -291,6 +301,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"argh",
|
||||
"codespan-reporting",
|
||||
"crossbeam-channel",
|
||||
"ide",
|
||||
"indexmap",
|
||||
|
|
@ -650,6 +661,15 @@ dependencies = [
|
|||
"rowan",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "text-size"
|
||||
version = "1.1.0"
|
||||
|
|
@ -768,6 +788,12 @@ version = "1.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.3.1"
|
||||
|
|
@ -802,6 +828,15 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ mod syntax_highlighting;
|
|||
use crate::base::SourceDatabaseStorage;
|
||||
use crate::def::DefDatabaseStorage;
|
||||
use crate::ty::TyDatabaseStorage;
|
||||
use crate::{Change, Diagnostic, FileId, FilePos, FileRange, WorkspaceEdit};
|
||||
use crate::{
|
||||
Change, Diagnostic, FileId, FilePos, FileRange, FileSet, SourceRoot, VfsPath, WorkspaceEdit,
|
||||
};
|
||||
use nix_interop::DEFAULT_IMPORT_FILE;
|
||||
use salsa::{Database, Durability, ParallelDatabase};
|
||||
use smol_str::SmolStr;
|
||||
use std::fmt;
|
||||
|
|
@ -73,6 +76,21 @@ impl AnalysisHost {
|
|||
Self::default()
|
||||
}
|
||||
|
||||
pub fn new_single_file(src: &str) -> (Self, FileId) {
|
||||
let mut change = Change::default();
|
||||
let file = FileId(0);
|
||||
change.change_file(file, src.into());
|
||||
let mut file_set = FileSet::default();
|
||||
file_set.insert(
|
||||
file,
|
||||
VfsPath::new(format!("/{DEFAULT_IMPORT_FILE}")).unwrap(),
|
||||
);
|
||||
change.set_roots(vec![SourceRoot::new_local(file_set, Some(file))]);
|
||||
let mut this = Self::new();
|
||||
this.apply_change(change);
|
||||
(this, file)
|
||||
}
|
||||
|
||||
pub fn snapshot(&self) -> Analysis {
|
||||
Analysis {
|
||||
db: self.db.snapshot(),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ rust-version = "1.66"
|
|||
[dependencies]
|
||||
anyhow = "1.0.68"
|
||||
argh = "0.1.10"
|
||||
codespan-reporting = "0.11.1"
|
||||
crossbeam-channel = "0.5.6"
|
||||
ide = { path = "../ide" }
|
||||
indexmap = "1.9.1"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use anyhow::Context;
|
||||
use argh::FromArgs;
|
||||
use ide::AnalysisHost;
|
||||
use lsp_server::Connection;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::{env, fs, io, process};
|
||||
use text_size::TextRange;
|
||||
use tracing_subscriber::fmt::writer::BoxMakeWriter;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
|
|
@ -17,6 +20,27 @@ struct Args {
|
|||
/// print the version and exit
|
||||
#[argh(switch)]
|
||||
version: bool,
|
||||
#[argh(subcommand)]
|
||||
subcommand: Option<Subcommand>,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromArgs)]
|
||||
#[argh(subcommand)]
|
||||
enum Subcommand {
|
||||
Diagnostics(DiagnosticsArgs),
|
||||
}
|
||||
|
||||
#[derive(Debug, FromArgs)]
|
||||
#[argh(subcommand, name = "diagnostics")]
|
||||
/// Check and print diagnostics for a file.
|
||||
/// Exit with non-zero code if there are any diagnostics.
|
||||
/// WARNING: The output format is for human and should not be relied on.
|
||||
struct DiagnosticsArgs {
|
||||
/// nix file to check, or read from stdin for `-`.
|
||||
/// NB. You need `--` before `-` for paths starting with `-`,
|
||||
/// to disambiguous it from flags.
|
||||
#[argh(positional)]
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
@ -31,6 +55,12 @@ fn main() {
|
|||
return;
|
||||
}
|
||||
|
||||
if let Some(subcommand) = args.subcommand {
|
||||
return match subcommand {
|
||||
Subcommand::Diagnostics(args) => main_diagnostics(args),
|
||||
};
|
||||
}
|
||||
|
||||
setup_logger();
|
||||
|
||||
let (conn, io_threads) = Connection::stdio();
|
||||
|
|
@ -44,6 +74,70 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
fn main_diagnostics(args: DiagnosticsArgs) {
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label, Severity};
|
||||
use codespan_reporting::files::SimpleFiles;
|
||||
use codespan_reporting::term;
|
||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||
|
||||
let ret = (|| -> anyhow::Result<bool> {
|
||||
let path = &*args.path;
|
||||
|
||||
let src = if path.as_os_str() == "-" {
|
||||
io::read_to_string(io::stdin().lock()).context("Failed to read from stdin")?
|
||||
} else {
|
||||
fs::read_to_string(path).context("Failed to read file")?
|
||||
};
|
||||
|
||||
let (analysis, file) = AnalysisHost::new_single_file(&src);
|
||||
let diags = analysis
|
||||
.snapshot()
|
||||
.diagnostics(file)
|
||||
.expect("No cancellation");
|
||||
if diags.is_empty() {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let mut files = SimpleFiles::new();
|
||||
let cr_file = files.add(path.display().to_string(), src);
|
||||
|
||||
let writer = StandardStream::stdout(ColorChoice::Auto);
|
||||
let config = codespan_reporting::term::Config::default();
|
||||
|
||||
for diag in diags {
|
||||
let severity = match diag.severity() {
|
||||
ide::Severity::IncompleteSyntax | ide::Severity::Error => Severity::Error,
|
||||
ide::Severity::Warning => Severity::Warning,
|
||||
};
|
||||
|
||||
let to_range = |range: TextRange| usize::from(range.start())..usize::from(range.end());
|
||||
|
||||
let labels = std::iter::once(Label::primary(cr_file, to_range(diag.range)))
|
||||
.chain(diag.notes.iter().map(|(frange, note)| {
|
||||
assert_eq!(frange.file_id, file, "Diagnostics are local");
|
||||
Label::secondary(cr_file, to_range(frange.range)).with_message(note)
|
||||
}))
|
||||
.collect();
|
||||
|
||||
let diag = Diagnostic::new(severity)
|
||||
.with_code(diag.code())
|
||||
.with_message(diag.message())
|
||||
.with_labels(labels);
|
||||
|
||||
term::emit(&mut writer.lock(), &config, &files, &diag)?;
|
||||
}
|
||||
Ok(false)
|
||||
})();
|
||||
match ret {
|
||||
Ok(true) => {}
|
||||
Ok(false) => process::exit(1),
|
||||
Err(err) => {
|
||||
eprintln!("{err:#}");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_logger() {
|
||||
let file = env::var_os(LOG_PATH_ENV).and_then(|path| {
|
||||
let path = PathBuf::from(path);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue