diff options
Diffstat (limited to 'mingling_cli/src/linter')
| -rw-r--r-- | mingling_cli/src/linter/cmd_explain.rs | 105 | ||||
| -rw-r--r-- | mingling_cli/src/linter/cmd_lint.rs (renamed from mingling_cli/src/linter/cmd_mlint.rs) | 8 | ||||
| -rw-r--r-- | mingling_cli/src/linter/cmd_ra_lints.rs | 63 | ||||
| -rw-r--r-- | mingling_cli/src/linter/registry.rs | 33 |
4 files changed, 208 insertions, 1 deletions
diff --git a/mingling_cli/src/linter/cmd_explain.rs b/mingling_cli/src/linter/cmd_explain.rs new file mode 100644 index 0000000..0bc969a --- /dev/null +++ b/mingling_cli/src/linter/cmd_explain.rs @@ -0,0 +1,105 @@ +use crate::{Next, linter::registry::ResLintRegistry}; +use mingling::{ + Grouped, LazyRes, Routable, ShellContext, StructuralData, Suggest, SuggestItem, + macros::{ + arg, buffer, chain, completion, dispatcher, metadata, pack, pack_err_structural, r_println, + renderer, routeify, + }, + metadata::Description, + picker::EntryPicker, +}; +use serde::Serialize; + +dispatcher!("explain"); + +#[metadata(EntryExplain)] +pub fn desc_explain() -> Description { + "Explain the meaning of the specified Lint".into() +} + +pack!(StateExplainLint = String); +pack_err_structural!(ErrorNoExplainLintProvided); +pack_err_structural!(ErrorNoSuchLint = String); + +#[derive(Debug, Default, Grouped, StructuralData, Serialize)] +pub struct ResultExplainLint { + pub lint_name: String, + pub title: String, + pub summary: String, + pub active_on: String, + pub author: String, + pub default: String, +} + +#[chain(routeify)] +pub fn handle_explain(args: EntryExplain) -> Next { + let lint_name = args + .pick_or_route(&arg![String], || { + ErrorNoExplainLintProvided::default().to_chain() + }) + .to_result()?; + StateExplainLint::new(lint_name).into() +} + +#[chain] +pub fn handle_state_explain_lint( + p: StateExplainLint, + registry: &mut LazyRes<ResLintRegistry>, +) -> Next { + let registry = registry.get_ref(); + let lint_name = p.inner; + let Some(entry) = registry.lints.iter().find(|l| l.name == lint_name) else { + return ErrorNoSuchLint::new(lint_name).to_chain(); + }; + ResultExplainLint { + lint_name: entry.name.clone(), + title: entry.title.clone(), + summary: entry.summary.clone(), + active_on: entry.metadata.active_on.clone(), + author: entry.metadata.author.clone(), + default: entry.metadata.default.clone(), + } + .to_chain() +} + +#[renderer(buffer)] +pub fn render_explain_lint(r: ResultExplainLint) { + r_println!("{}", r.title); + r_println!(""); + r_println!(" Name : #[mlint[{}({})]", r.default, r.lint_name); + r_println!(" Author : {}", r.author); + r_println!(""); + r_println!("{}", r.summary); +} + +#[renderer(buffer)] +pub fn render_error_no_explain_lint_provided(_: ErrorNoExplainLintProvided) { + r_println!("No lint name provided"); + r_println!(""); + r_println!("Usage: mling explain <LINT>"); +} + +#[renderer(buffer)] +pub fn render_error_no_such_lint(err: ErrorNoSuchLint, registry: &mut LazyRes<ResLintRegistry>) { + let registry = registry.get_ref(); + r_println!("No such lint: \"{}\"", err.info); + r_println!(""); + r_println!("Available lints:"); + for entry in registry.lints.iter() { + r_println!(" {}", entry.name); + } +} + +#[completion(EntryExplain)] +pub fn complete_explain(ctx: &ShellContext, registry: &mut LazyRes<ResLintRegistry>) -> Suggest { + let registry = registry.get_ref(); + if ctx.previous_word != "explain" { + return Suggest::FileCompletion; + } + let lints: Vec<String> = registry.lints.iter().map(|l| l.name.clone()).collect(); + let mut suggest = Suggest::new(); + for lint in lints { + suggest.insert(SuggestItem::Simple(lint)); + } + suggest +} diff --git a/mingling_cli/src/linter/cmd_mlint.rs b/mingling_cli/src/linter/cmd_lint.rs index 1dfd02b..57a78ad 100644 --- a/mingling_cli/src/linter/cmd_mlint.rs +++ b/mingling_cli/src/linter/cmd_lint.rs @@ -2,12 +2,18 @@ use crate::linter::mlint_report::{MlintReport, StateLintReports}; use cargo_metadata::Metadata; use mingling::LazyRes; use mingling::consts::REMAINS; -use mingling::macros::{arg, chain, dispatcher, pack}; +use mingling::macros::{arg, chain, dispatcher, metadata, pack}; +use mingling::metadata::Description; use mingling::picker::EntryPicker; use tokio::task::JoinSet; dispatcher!("lint", CMDLint => EntryLint); +#[metadata(EntryLint)] +pub fn desc_lint() -> Description { + "Mingling Linter".to_string().into() +} + /// Main linting function that processes all packages in the metadata. /// /// Iterates through all packages and their targets (e.g., binaries, libraries, tests), diff --git a/mingling_cli/src/linter/cmd_ra_lints.rs b/mingling_cli/src/linter/cmd_ra_lints.rs new file mode 100644 index 0000000..733d611 --- /dev/null +++ b/mingling_cli/src/linter/cmd_ra_lints.rs @@ -0,0 +1,63 @@ +use mingling::{ + macros::{chain, dispatcher, entry, metadata}, + metadata::Description, +}; + +use crate::{linter::cmd_lint::EntryLint, metadata::setup::ResUsingJson}; + +// Aliases + +dispatcher!("ra-lint-clippy", + CMDLinterSupportRustAnalyzerWithClippy => EntryLinterSupportRustAnalyzerWithClippy +); + +dispatcher!("ra-lint-check", + CMDLinterSupportRustAnalyzerWithCheck => EntryLinterSupportRustAnalyzerWithCheck +); + +dispatcher!("ra-lint", + CMDLinterSupportRustAnalyzer => EntryLinterSupportRustAnalyzer +); + +#[chain] +pub fn handle_ra_lint(_: EntryLinterSupportRustAnalyzer, use_json: &mut ResUsingJson) -> EntryLint { + use_json.using = true; + entry!("--message-format=json") +} + +#[chain] +pub fn handle_ra_lint_check( + _: EntryLinterSupportRustAnalyzerWithCheck, + use_json: &mut ResUsingJson, +) -> EntryLint { + use_json.using = true; + entry!("--message-format=json", "--with-checker=cargo,check") +} + +#[chain] +pub fn handle_ra_lint_clippy( + _: EntryLinterSupportRustAnalyzerWithClippy, + use_json: &mut ResUsingJson, +) -> EntryLint { + use_json.using = true; + entry!("--message-format=json", "--with-checker=cargo,clippy") +} + +#[metadata(EntryLinterSupportRustAnalyzer)] +pub fn desc_ra_lint() -> Description { + "Run `mling lint` and output the results".to_string().into() +} + +#[metadata(EntryLinterSupportRustAnalyzerWithCheck)] +pub fn desc_ra_lint_check() -> Description { + "Run `mling lint` and `cargo check`, and output the combined results" + .to_string() + .into() +} + +#[metadata(EntryLinterSupportRustAnalyzerWithClippy)] +pub fn desc_ra_lint_clippy() -> Description { + "Run `mling lint` and `cargo clippy`, and output the combined results" + .to_string() + .into() +} diff --git a/mingling_cli/src/linter/registry.rs b/mingling_cli/src/linter/registry.rs new file mode 100644 index 0000000..79f3225 --- /dev/null +++ b/mingling_cli/src/linter/registry.rs @@ -0,0 +1,33 @@ +use mingling::{LazyInit, Program, macros::program_setup}; +use serde::Deserialize; + +use crate::ThisProgram; + +#[derive(Debug, Default, Clone, Deserialize)] +pub struct ResLintRegistry { + pub lints: Vec<LintEntry>, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct LintEntry { + pub name: String, + pub title: String, + pub summary: String, + pub metadata: LintMetadata, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct LintMetadata { + pub active_on: String, + pub author: String, + pub default: String, +} + +#[program_setup] +pub fn lint_registry_setup(p: &mut Program<ThisProgram>) { + p.with_resource(ResLintRegistry::lazy_init(|| { + let registry: ResLintRegistry = serde_json::from_str(include_str!("../../registry.json")) + .expect("failed to parse embedded registry.json"); + registry + })); +} |
