Skip to content

Commit c3257c3

Browse files
authored
Merge pull request #513 from lewis6991/feat/emmyluaerrors
emmylua_check
2 parents 3b14843 + 6db8735 commit c3257c3

File tree

6 files changed

+142
-41
lines changed

6 files changed

+142
-41
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/emmylua_check/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ emmylua_parser.workspace = true
1919
serde.workspace = true
2020
serde_json.workspace = true
2121
lsp-types.workspace = true
22+
log.workspace = true
23+
fern.workspace = true
2224
rowan.workspace = true
2325
walkdir.workspace = true
2426
structopt.workspace = true

crates/emmylua_check/src/cmd_args.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,44 @@ use structopt::StructOpt;
44
#[derive(Debug, StructOpt, Clone)]
55
#[structopt(name = "emmylua-check", about = "EmmyLua Check")]
66
pub struct CmdArgs {
7-
#[structopt(short, long, parse(from_os_str), help = "Specify configuration file")]
8-
pub config: Option<std::path::PathBuf>,
7+
/// Configuration file paths.
8+
/// If not provided, both ".emmyrc.json" and ".luarc.json" will be searched in the workspace
9+
/// directory
10+
#[structopt(short, long, use_delimiter = true, parse(from_os_str))]
11+
pub config: Option<Vec<std::path::PathBuf>>,
912

10-
#[structopt(parse(from_os_str), help = "Path to the workspace directory")]
13+
/// Path to the workspace directory
14+
#[structopt(parse(from_os_str))]
1115
pub workspace: std::path::PathBuf,
1216

13-
#[structopt(
14-
short,
15-
long,
16-
help = "Comma separated list of ignore patterns",
17-
use_delimiter = true
18-
)]
17+
/// Comma separated list of ignore patterns.
18+
/// Patterns must follow glob syntax
19+
#[structopt(short, long, use_delimiter = true)]
1920
pub ignore: Option<Vec<String>>,
2021

22+
/// Specify output format
2123
#[structopt(
2224
long,
23-
help = "Specify output format (json or text)",
2425
default_value = "text",
2526
possible_values = &OutputFormat::variants(),
2627
case_insensitive = true
2728
)]
2829
pub output_format: OutputFormat,
2930

30-
#[structopt(
31-
long,
32-
help = "Specify output destination (stdout or a file path, only used when output_format is json)",
33-
default_value = "stdout",
34-
parse(try_from_str)
35-
)]
31+
/// Specify output destination (stdout or a file path, only used when output_format is json).
32+
#[structopt(long, default_value = "stdout", parse(try_from_str))]
3633
pub output: OutputDestination,
3734

38-
#[structopt(long, help = "Treat warnings as errors")]
35+
/// Treat warnings as errors
36+
#[structopt(long)]
3937
pub warnings_as_errors: bool,
38+
39+
/// Verbose output
40+
#[structopt(long)]
41+
pub verbose: bool,
4042
}
4143

42-
#[derive(Debug, Clone)]
44+
#[derive(Debug, Clone, PartialEq)]
4345
pub enum OutputFormat {
4446
Json,
4547
Text,

crates/emmylua_check/src/init.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,30 @@ use emmylua_code_analysis::{
44
load_configs, load_workspace_files, update_code_style, EmmyLuaAnalysis, Emmyrc, LuaFileInfo,
55
};
66

7+
fn root_from_configs(config_paths: &Vec<PathBuf>, fallback: &PathBuf) -> PathBuf {
8+
if config_paths.len() > 1 {
9+
fallback.clone()
10+
} else {
11+
let config_path = &config_paths[0];
12+
// Need to convert to canonical path to ensure parent() is not an empty
13+
// string in the case the path is a relative basename.
14+
match config_path.canonicalize() {
15+
Ok(path) => path.parent().unwrap().to_path_buf(),
16+
Err(err) => {
17+
log::error!(
18+
"Failed to canonicalize config path: \"{:?}\": {}",
19+
config_path,
20+
err
21+
);
22+
fallback.clone()
23+
}
24+
}
25+
}
26+
}
27+
728
pub fn load_workspace(
829
workspace_folder: PathBuf,
9-
config_path: Option<PathBuf>,
30+
config_paths: Option<Vec<PathBuf>>,
1031
ignore: Option<Vec<String>>,
1132
) -> Option<EmmyLuaAnalysis> {
1233
let mut analysis = EmmyLuaAnalysis::new();
@@ -18,22 +39,27 @@ pub fn load_workspace(
1839
}
1940

2041
let main_path = workspace_folders.first()?.clone();
21-
let (config_files, config_root) = if let Some(config_path) = config_path {
22-
(
23-
vec![config_path.clone()],
24-
config_path.parent().unwrap().to_path_buf(),
25-
)
26-
} else {
27-
(
28-
vec![
29-
main_path.join(".luarc.json"),
30-
main_path.join(".emmyrc.json"),
31-
],
32-
main_path.clone(),
33-
)
34-
};
42+
let (config_files, config_root): (Vec<PathBuf>, PathBuf) =
43+
if let Some(config_paths) = config_paths {
44+
(
45+
config_paths.clone(),
46+
root_from_configs(&config_paths, &main_path),
47+
)
48+
} else {
49+
(
50+
vec![
51+
main_path.join(".luarc.json"),
52+
main_path.join(".emmyrc.json"),
53+
],
54+
main_path.clone(),
55+
)
56+
};
3557

3658
let mut emmyrc = load_configs(config_files, None);
59+
log::info!(
60+
"Pre processing configurations using root: \"{}\"",
61+
config_root.display()
62+
);
3763
emmyrc.pre_process_emmyrc(&config_root);
3864

3965
for root in &emmyrc.workspace.workspace_roots {
@@ -110,23 +136,29 @@ pub fn calculate_include_and_exclude(
110136

111137
for extension in &emmyrc.runtime.extensions {
112138
if extension.starts_with(".") {
139+
log::info!("Adding extension: **/*{}", extension);
113140
include.push(format!("**/*{}", extension));
114141
} else if extension.starts_with("*.") {
142+
log::info!("Adding extension: **/{}", extension);
115143
include.push(format!("**/{}", extension));
116144
} else {
145+
log::info!("Adding extension: {}", extension);
117146
include.push(extension.clone());
118147
}
119148
}
120149

121150
for ignore_glob in &emmyrc.workspace.ignore_globs {
151+
log::info!("Adding ignore glob: {}", ignore_glob);
122152
exclude.push(ignore_glob.clone());
123153
}
124154

125155
if let Some(ignore) = ignore {
156+
log::info!("Adding ignores from \"--ignore\": {:?}", ignore);
126157
exclude.extend(ignore);
127158
}
128159

129160
for dir in &emmyrc.workspace.ignore_dir {
161+
log::info!("Adding ignore dir: {}", dir);
130162
exclude_dirs.push(PathBuf::from(dir));
131163
}
132164

crates/emmylua_check/src/main.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ mod output;
44

55
use cmd_args::CmdArgs;
66
use emmylua_code_analysis::{DbIndex, FileId};
7+
use fern::Dispatch;
8+
use log::LevelFilter;
79
use output::output_result;
810
use std::{error::Error, path::PathBuf, sync::Arc};
911
use structopt::StructOpt;
@@ -17,6 +19,37 @@ async fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
1719
workspace = std::env::current_dir()?.join(workspace);
1820
}
1921

22+
let verbose = cmd_args.verbose;
23+
let logger = Dispatch::new()
24+
.format(move |out, message, record| {
25+
let (color, reset) = match record.level() {
26+
log::Level::Error => ("\x1b[31m", "\x1b[0m"), // Red
27+
log::Level::Warn => ("\x1b[33m", "\x1b[0m"), // Yellow
28+
log::Level::Info | log::Level::Debug | log::Level::Trace => ("", ""),
29+
};
30+
out.finish(format_args!(
31+
"{}{}: {}{}",
32+
color,
33+
record.level(),
34+
if verbose {
35+
format!("({}) {}", record.target(), message)
36+
} else {
37+
message.to_string()
38+
},
39+
reset
40+
))
41+
})
42+
.level(if verbose {
43+
LevelFilter::Info
44+
} else {
45+
LevelFilter::Warn
46+
})
47+
.chain(std::io::stderr());
48+
49+
if let Err(e) = logger.apply() {
50+
eprintln!("Failed to apply logger: {:?}", e);
51+
}
52+
2053
let analysis = match init::load_workspace(workspace.clone(), cmd_args.config, cmd_args.ignore) {
2154
Some(analysis) => analysis,
2255
None => {

crates/emmylua_check/src/output/mod.rs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,33 @@ pub async fn output_result(
2525

2626
let mut has_error = false;
2727
let mut count = 0;
28+
let mut error_count = 0;
29+
let mut warning_count = 0;
30+
let mut info_count = 0;
31+
let mut hint_count = 0;
32+
2833
while let Some((file_id, diagnostics)) = receiver.recv().await {
2934
count += 1;
3035
if let Some(diagnostics) = diagnostics {
3136
for diagnostic in &diagnostics {
32-
if diagnostic.severity == Some(lsp_types::DiagnosticSeverity::ERROR) {
33-
has_error = true;
34-
break;
35-
} else if warnings_as_errors
36-
&& diagnostic.severity == Some(lsp_types::DiagnosticSeverity::WARNING)
37-
{
38-
has_error = true;
39-
break;
37+
match diagnostic.severity {
38+
Some(lsp_types::DiagnosticSeverity::ERROR) => {
39+
has_error = true;
40+
error_count += 1;
41+
}
42+
Some(lsp_types::DiagnosticSeverity::WARNING) => {
43+
if warnings_as_errors {
44+
has_error = true;
45+
}
46+
warning_count += 1;
47+
}
48+
Some(lsp_types::DiagnosticSeverity::INFORMATION) => {
49+
info_count += 1;
50+
}
51+
Some(lsp_types::DiagnosticSeverity::HINT) => {
52+
hint_count += 1;
53+
}
54+
_ => {}
4055
}
4156
}
4257
writer.write(db, file_id, diagnostics);
@@ -49,6 +64,21 @@ pub async fn output_result(
4964

5065
writer.finish();
5166

67+
if output_format == OutputFormat::Text {
68+
if error_count > 0 {
69+
println!("Errors: {}", error_count);
70+
}
71+
if warning_count > 0 {
72+
println!("Warnings: {}", warning_count);
73+
}
74+
if info_count > 0 {
75+
println!("Information: {}", info_count);
76+
}
77+
if hint_count > 0 {
78+
println!("Hints: {}", hint_count);
79+
}
80+
}
81+
5282
if has_error {
5383
1
5484
} else {

0 commit comments

Comments
 (0)