diff options
Diffstat (limited to 'mingling_cli')
| -rw-r--r-- | mingling_cli/Cargo.lock | 3 | ||||
| -rw-r--r-- | mingling_cli/Cargo.toml | 3 | ||||
| -rw-r--r-- | mingling_cli/help/help.txt | 27 | ||||
| -rw-r--r-- | mingling_cli/src/diagnostic.rs | 2 | ||||
| -rw-r--r-- | mingling_cli/src/linter.rs | 47 | ||||
| -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 | ||||
| -rw-r--r-- | mingling_cli/src/lints/non_mingling_naming_style.rs | 16 | ||||
| -rw-r--r-- | mingling_cli/src/main.rs | 26 | ||||
| -rw-r--r-- | mingling_cli/src/metadata/cmd_metadata.rs | 10 | ||||
| -rw-r--r-- | mingling_cli/src/pkg_mgr.rs | 0 | ||||
| -rw-r--r-- | mingling_cli/src/proj_mgr.rs | 0 |
14 files changed, 281 insertions, 62 deletions
diff --git a/mingling_cli/Cargo.lock b/mingling_cli/Cargo.lock index 5a0dcd0..60f8792 100644 --- a/mingling_cli/Cargo.lock +++ b/mingling_cli/Cargo.lock @@ -277,6 +277,7 @@ dependencies = [ "arg-picker", "mingling_core", "mingling_macros", + "serde", ] [[package]] @@ -304,6 +305,8 @@ dependencies = [ "just_template", "might_be_async", "mingling_pathf", + "serde", + "serde_json", ] [[package]] diff --git a/mingling_cli/Cargo.toml b/mingling_cli/Cargo.toml index 4dfea20..a7a8538 100644 --- a/mingling_cli/Cargo.toml +++ b/mingling_cli/Cargo.toml @@ -27,7 +27,8 @@ features = [ "pathf", "dispatch_tree", "async", - "comp" + "comp", + "structural_renderer" ] [build-dependencies.mingling] diff --git a/mingling_cli/help/help.txt b/mingling_cli/help/help.txt index 85a4fb7..2089e2b 100644 --- a/mingling_cli/help/help.txt +++ b/mingling_cli/help/help.txt @@ -1,3 +1,30 @@ USAGE: mling [GLOBAL_FLAGS] [COMMAND] [ARGS...] GLOBAL_FLAGS: + --all-features Enable all features + --features <FEATURES> List of features to enable + -h, --help Show help messages + --manifest-path <PATH> Custom path to Cargo.toml + --message-format <FORMAT> Output message format + --no-default-features Disable default features + --no-deps Do not include dependencies in metadata + +COMMANDS: + metadata Check your workspace metadata using 'cargo metadata' + + LINTER: + lint Mingling Linter + ra-lint Run `mling lint` and output the results + ra-lint-check Run `mling lint` and `cargo check`, and output the combined results + ra-lint-clippy Run `mling lint` and `cargo clippy`, and output the combined results + explain <LINT> Explain the meaning of the specified Lint + + PROJECT MANAGE: + proj-new <NAME> [NOT_IMPL] Create a project + proj-init [NOT_IMPL] Initialize a project + + PACKAGE MANAGE: + install [NOT_IMPL] Install the project to the Mingling package list + package-show [NOT_IMPL] Show locally installed packages + package-enable <NAME> [NOT_IMPL] Enable the specified package + package-disable <NAME> [NOT_IMPL] Disable the specified package diff --git a/mingling_cli/src/diagnostic.rs b/mingling_cli/src/diagnostic.rs index 527e879..807cdf3 100644 --- a/mingling_cli/src/diagnostic.rs +++ b/mingling_cli/src/diagnostic.rs @@ -26,7 +26,7 @@ fn cargo_level_to_annotate( } } -/// 把 1-based char offset 转成 0-based byte offset +/// Convert 1-based char offset to 0-based byte offset fn char_offset_to_byte_offset(s: &str, char_offset: usize) -> usize { s.char_indices() .nth(char_offset.saturating_sub(1)) diff --git a/mingling_cli/src/linter.rs b/mingling_cli/src/linter.rs index 8be45c8..30d79de 100644 --- a/mingling_cli/src/linter.rs +++ b/mingling_cli/src/linter.rs @@ -1,45 +1,6 @@ -use mingling::macros::{chain, dispatcher, entry}; - -use crate::{linter::cmd_mlint::EntryLint, metadata::setup::ResUsingJson}; - -pub mod cmd_mlint; +pub mod cmd_explain; +pub mod cmd_lint; +pub mod cmd_ra_lints; pub mod mlint_attr; pub mod mlint_report; - -// 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") -} +pub mod registry; 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 + })); +} diff --git a/mingling_cli/src/lints/non_mingling_naming_style.rs b/mingling_cli/src/lints/non_mingling_naming_style.rs index 83168b7..eee3098 100644 --- a/mingling_cli/src/lints/non_mingling_naming_style.rs +++ b/mingling_cli/src/lints/non_mingling_naming_style.rs @@ -4,14 +4,14 @@ //! //! Checks that Mingling functions follow naming conventions: //! -//! | Prefix | 1st param must be | -//! |--------|------------------| -//! | `handle_` | `Entry*` | -//! | `handle_state_` | `State*` | -//! | `handle_error_` | `Error*` | -//! | `help_` | `Entry*` | -//! | `render_` | `Result*` | -//! | `render_error_` | `Error*` | +//! | Prefix | 1st param must be | +//! |-----------------|-------------------| +//! | `handle_` | `Entry*` | +//! | `handle_state_` | `State*` | +//! | `handle_error_` | `Error*` | +//! | `help_` | `Entry*` | +//! | `render_` | `Result*` | +//! | `render_error_` | `Error*` | //! //! The name after prefix (snake_case) must match the type after prefix (PascalCase). //! diff --git a/mingling_cli/src/main.rs b/mingling_cli/src/main.rs index b9164db..7c71bcd 100644 --- a/mingling_cli/src/main.rs +++ b/mingling_cli/src/main.rs @@ -1,15 +1,21 @@ -use crate::metadata::{ - MinglingMetadataSetup, - setup::{ - ARG_ALL_FEATURES, ARG_FEATURES, ARG_MANIFEST_PATH, ARG_MESSAGE_FORMAT, - ARG_NO_DEFAULT_FEATURES, ARG_NO_DEPS, +use crate::{ + linter::registry::LintRegistrySetup, + metadata::{ + MinglingMetadataSetup, + setup::{ + ARG_ALL_FEATURES, ARG_FEATURES, ARG_MANIFEST_PATH, ARG_MESSAGE_FORMAT, + ARG_NO_DEFAULT_FEATURES, ARG_NO_DEPS, + }, }, }; use mingling::{ ShellContext, Suggest, - consts::HELP_FLAG, + consts::{HELP_FLAG, JSON_FLAG, JSON_PRETTY_FLAG}, macros::{completion, gen_program, help, suggest}, - setup::{ExitCodeSetup, picker::HelpFlagSetup}, + setup::{ + ExitCodeSetup, + picker::{HelpFlagSetup, StructuralRendererSetup}, + }, }; pub mod diagnostic; @@ -18,16 +24,20 @@ pub mod linter; pub mod lints; pub mod message; pub mod metadata; +pub mod pkg_mgr; +pub mod proj_mgr; #[tokio::main] async fn main() { let mut program = ThisProgram::new(); // Setups + program.with_setup(StructuralRendererSetup); program.with_setup(HelpFlagSetup::default()); program.with_setup(ExitCodeSetup::default()); program.with_setup(MinglingMetadataSetup); + program.with_setup(LintRegistrySetup); // Exec program.exec_and_exit().await; @@ -48,6 +58,8 @@ pub fn complete_global(_ctx: &ShellContext) -> Suggest { ARG_ALL_FEATURES: "Enable all features", ARG_NO_DEFAULT_FEATURES: "Disable default features", ARG_NO_DEPS: "Do not include dependencies in metadata", + JSON_FLAG: "Render results in JSON format", + JSON_PRETTY_FLAG: "Render results in pretty JSON format" } } diff --git a/mingling_cli/src/metadata/cmd_metadata.rs b/mingling_cli/src/metadata/cmd_metadata.rs index 18241a2..3ee9f09 100644 --- a/mingling_cli/src/metadata/cmd_metadata.rs +++ b/mingling_cli/src/metadata/cmd_metadata.rs @@ -1,13 +1,21 @@ use cargo_metadata::Metadata; use mingling::{ LazyRes, - macros::{chain, dispatcher, pack}, + macros::{chain, dispatcher, metadata, pack}, + metadata::Description, }; use crate::metadata::setup::ResMetadata; dispatcher!("metadata"); +#[metadata(EntryMetadata)] +pub fn desc_metadata() -> Description { + "Check your workspace metadata using 'cargo metadata'" + .to_string() + .into() +} + pack!(ResultMetadata = ResMetadata); #[chain] diff --git a/mingling_cli/src/pkg_mgr.rs b/mingling_cli/src/pkg_mgr.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mingling_cli/src/pkg_mgr.rs diff --git a/mingling_cli/src/proj_mgr.rs b/mingling_cli/src/proj_mgr.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mingling_cli/src/proj_mgr.rs |
