diff options
36 files changed, 194 insertions, 584 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 563e8e1..71b63ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,12 +94,17 @@ jobs: - name: Run cov-test run: cargo run --manifest-path .run/Cargo.toml --bin cov-test + - name: Delete .temp directory before deployment + run: rm -rf .temp + - name: Setup Pages uses: actions/configure-pages@v5 + - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: "." + - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v5 diff --git a/.run/src/bin/ci.rs b/.run/src/bin/ci.rs index 954034c..4b6f973 100644 --- a/.run/src/bin/ci.rs +++ b/.run/src/bin/ci.rs @@ -142,6 +142,11 @@ fn ci(test_docs: bool, test_codes: bool, run_all: bool) -> Result<(), i32> { exit_code = exit_code.max(code); } + println_cargo_style!("Phase: Try Build API docs"); + if let Err(code) = deploy_api_docs() { + exit_code = exit_code.max(code); + } + if exit_code != 0 { return Err(exit_code); } @@ -225,6 +230,12 @@ fn test_all() -> Result<(), i32> { run_parallel("Testing", tasks) } +fn deploy_api_docs() -> Result<(), i32> { + run_cmd!( + "cargo run --manifest-path .run/Cargo.toml --color always --bin deploy-api-docs -- --docsrs" + ) +} + fn docs_refresh() -> Result<(), i32> { println_cargo_style!("Refresh: document at `./docs/`"); diff --git a/.run/src/bin/clippy.sh b/.run/src/bin/clippy.sh index b393545..b393545 100644..100755 --- a/.run/src/bin/clippy.sh +++ b/.run/src/bin/clippy.sh diff --git a/.run/version-files.toml b/.run/version-files.toml index ca104d2..b69a568 100644 --- a/.run/version-files.toml +++ b/.run/version-files.toml @@ -17,3 +17,7 @@ pattern = "version = \"{VER}\"" [[file]] file = "./docs/res/guide.txt" pattern = "mingling = \"{VER}\"" + +[[file]] +file = "./mingling_core/src/lib.rs" +pattern = "mingling = \"{VER}\"" diff --git a/CHANGELOG.md b/CHANGELOG.md index ed7ad66..62ec971 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -171,6 +171,13 @@ None _No migration is required — these are purely additive derives that expand the type's capabilities without affecting existing behavior._ +**[`core`]** Added the `build` feature (renamed from `builds`) to `mingling_core` and `mingling`. The old `builds` feature has been deprecated in favor of `build`, with a backward-compatibility alias retained in `mingling/Cargo.toml`: + +- **`mingling_core/Cargo.toml`**: Renamed the feature from `builds` to `build`. +- **`mingling/Cargo.toml`**: Changed the feature dependency from `mingling_core/builds` to `mingling_core/build`. A deprecated `builds` feature alias is kept as `builds = ["mingling_core/build"]` with a note indicating it will be removed in a future breaking change. + + _No behavioral changes — the `build` feature provides identical functionality to the old `builds` feature. Downstream code using `builds` continues to work via the alias, but should migrate to `build`._ + #### Features: 1. **[`core`]** Added `RenderResult::new()` method for creating a new `RenderResult` with default values (empty text and exit code 0). This provides a more explicit and discoverable constructor compared to `RenderResult::default()`, making it clearer when a fresh result is being created for use with `write!`/`writeln!`. @@ -270,6 +270,10 @@ dependencies = [ ] [[package]] +name = "mingling-workspace" +version = "0.3.0" + +[[package]] name = "mingling_core" version = "0.3.0" dependencies = [ @@ -77,3 +77,9 @@ lto = "fat" codegen-units = 1 panic = "abort" strip = true + +[package] +name = "mingling-workspace" +version.workspace = true +edition.workspace = true +publish = false diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md index 621471e..516122e 100644 --- a/GETTING_STARTED.md +++ b/GETTING_STARTED.md @@ -239,7 +239,7 @@ In your `build.rs`, generate the shell scripts: ```rust // BUILD TIME -// Features: ["comp", "builds"] +// Features: ["comp", "build"] mingling::build::build_comp_scripts(env!("CARGO_PKG_NAME")).unwrap(); ``` diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..951ecf8 --- /dev/null +++ b/build.rs @@ -0,0 +1,13 @@ +use std::{env::current_dir, fs}; + +fn main() { + gen_fake_cargo_toml_in_temp_dir(); +} + +fn gen_fake_cargo_toml_in_temp_dir() { + fs::write( + current_dir().unwrap().join(".temp").join("Cargo.toml"), + "[workspace]", + ) + .unwrap(); +} diff --git a/docs/_zh_CN/pages/advanced/1-completion.md b/docs/_zh_CN/pages/advanced/1-completion.md index 3941404..a6500db 100644 --- a/docs/_zh_CN/pages/advanced/1-completion.md +++ b/docs/_zh_CN/pages/advanced/1-completion.md @@ -15,8 +15,8 @@ features = ["comp"] [build-dependencies.mingling] features = [ "comp", - # 启用 `builds` 特性以提供构建期支持 - "builds" + # 启用 `build` 特性以提供构建期支持 + "build" ] ``` diff --git a/docs/pages/advanced/1-completion.md b/docs/pages/advanced/1-completion.md index a90c3ce..52350db 100644 --- a/docs/pages/advanced/1-completion.md +++ b/docs/pages/advanced/1-completion.md @@ -15,8 +15,8 @@ features = ["comp"] [build-dependencies.mingling] features = [ "comp", - # Enable `builds` for build-time support - "builds" + # Enable `build` for build-time support + "build" ] ``` diff --git a/examples/example-completion/Cargo.toml b/examples/example-completion/Cargo.toml index 1c6b327..00c7f8c 100644 --- a/examples/example-completion/Cargo.toml +++ b/examples/example-completion/Cargo.toml @@ -20,8 +20,8 @@ features = [ "comp", # If you want to build completion scripts, - # enable `builds` features - "builds", + # enable `build` features + "build", ] [workspace] diff --git a/examples/example-completion/src/main.rs b/examples/example-completion/src/main.rs index 45cc8ef..d65be49 100644 --- a/examples/example-completion/src/main.rs +++ b/examples/example-completion/src/main.rs @@ -7,7 +7,7 @@ //! To make your completions work, you need to generate a completion script using Mingling's tools //! //! 1. Enable features -//! You need to enable the `builds` and `comp` features for `mingling` in `[build-dependencies]` +//! You need to enable the `build` and `comp` features for `mingling` in `[build-dependencies]` //! //! 2. Write `build.rs` //! Write the following in `build.rs` diff --git a/examples/example-pathfinder/Cargo.toml b/examples/example-pathfinder/Cargo.toml index bd362f2..bc41bd2 100644 --- a/examples/example-pathfinder/Cargo.toml +++ b/examples/example-pathfinder/Cargo.toml @@ -18,8 +18,8 @@ features = [ # Enable `pathf` features "pathf", - # Enable the `builds` feature for build-time support - "builds", + # Enable the `build` feature for build-time support + "build", ] [workspace] diff --git a/mingling/Cargo.toml b/mingling/Cargo.toml index 351384f..9bf82a7 100644 --- a/mingling/Cargo.toml +++ b/mingling/Cargo.toml @@ -43,7 +43,8 @@ macros = ["dep:mingling_macros", "mingling_macros/default"] nightly = ["mingling_core/nightly", "mingling_macros/nightly"] debug = ["mingling_core/debug"] async = ["mingling_core/async", "mingling_macros/async"] -builds = ["mingling_core/builds"] + +build = ["mingling_core/build"] default = ["core", "macros"] @@ -92,6 +93,9 @@ extra_macros = ["mingling_macros/extra_macros"] # Section only shown in docs.rs docs_rs = [] +# This is an old name, will be Breaking Change in the future +builds = ["mingling_core/build"] + [dependencies] mingling_core = { workspace = true, optional = true } mingling_macros = { workspace = true, optional = true } diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs index 89d5af1..35cf024 100644 --- a/mingling/src/example_docs.rs +++ b/mingling/src/example_docs.rs @@ -777,7 +777,7 @@ pub mod example_combine_pathf_dispatch_tree {} /// To make your completions work, you need to generate a completion script using Mingling's tools /// /// 1. Enable features -/// You need to enable the `builds` and `comp` features for `mingling` in `[build-dependencies]` +/// You need to enable the `build` and `comp` features for `mingling` in `[build-dependencies]` /// /// 2. Write `build.rs` /// Write the following in `build.rs` @@ -838,8 +838,8 @@ pub mod example_combine_pathf_dispatch_tree {} /// "comp", /// /// # If you want to build completion scripts, -/// # enable `builds` features -/// "builds", +/// # enable `build` features +/// "build", /// ] /// /// [workspace] @@ -2268,8 +2268,8 @@ pub mod example_panic_unwind {} /// # Enable `pathf` features /// "pathf", /// -/// # Enable the `builds` feature for build-time support -/// "builds", +/// # Enable the `build` feature for build-time support +/// "build", /// ] /// /// [workspace] diff --git a/mingling/src/features.rs b/mingling/src/features.rs index 78d6226..0dde333 100644 --- a/mingling/src/features.rs +++ b/mingling/src/features.rs @@ -20,6 +20,17 @@ pub const MINGLING_ASYNC: bool = false; #[cfg(feature = "async")] #[allow(unused)] pub const MINGLING_ASYNC: bool = true; +/// Whether the `build` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "build"))] +#[allow(unused)] +pub const MINGLING_BUILD: bool = false; + +/// Whether the `build` feature is enabled +/// Current: `enabled` +#[cfg(feature = "build")] +#[allow(unused)] +pub const MINGLING_BUILD: bool = true; /// Whether the `builds` feature is enabled /// Current: `disabled` #[cfg(not(feature = "builds"))] diff --git a/mingling_cli/Cargo.toml b/mingling_cli/Cargo.toml index 906cdd0..330ef5a 100644 --- a/mingling_cli/Cargo.toml +++ b/mingling_cli/Cargo.toml @@ -31,7 +31,7 @@ features = [ [build-dependencies.mingling] path = "../mingling" features = [ - "builds", + "build", "pathf", ] diff --git a/mingling_cli/src/linter.rs b/mingling_cli/src/linter.rs index 5d20900..859ffc5 100644 --- a/mingling_cli/src/linter.rs +++ b/mingling_cli/src/linter.rs @@ -4,15 +4,11 @@ use mingling::{ }; use crate::{ - linter::{ - cmd_mlint::{CMDLint, EntryLint}, - cmd_mlint_install::CMDLintInstall, - }, + linter::cmd_mlint::{CMDLint, EntryLint}, metadata::setup::ResUsingJson, }; pub mod cmd_mlint; -pub mod cmd_mlint_install; pub mod mlint_attr; pub mod mlint_report; @@ -24,7 +20,6 @@ pub fn mingling_linter_setup(program: &mut Program<crate::ThisProgram>) { #[program_setup] pub fn mingling_linter_command_setup(program: &mut Program<crate::ThisProgram>) { program.with_dispatcher(CMDLint); - program.with_dispatcher(CMDLintInstall); program.with_dispatcher(CMDLinterSupportRustAnalyzer); program.with_dispatcher(CMDLinterSupportRustAnalyzerWithClippy); program.with_dispatcher(CMDLinterSupportRustAnalyzerWithCheck); diff --git a/mingling_cli/src/linter/cmd_mlint_install.rs b/mingling_cli/src/linter/cmd_mlint_install.rs deleted file mode 100644 index d29d3e5..0000000 --- a/mingling_cli/src/linter/cmd_mlint_install.rs +++ /dev/null @@ -1,454 +0,0 @@ -use crate::Next; -use crate::linter::mlint_report::{ - LintSpan, LintSpanLine, LintSuggestion, MlintLevel, MlintReport, StateLintReports, -}; -use mingling::Routable; -use mingling::macros::{buffer, chain, dispatcher, pack, r_eprintln, renderer, routeify}; -use mingling::res::ResCurrentDir; -use std::ops::Range; -use std::path::PathBuf; - -const OVERRIDE_KEY: &str = "check.overrideCommand"; -const EXPECTED_LINE: &str = r#"check.overrideCommand = ["mling", "ra-lint-check"]"#; -const VALID_FIRST: &[&str] = &["mling", "mingling-cli"]; -const RA_CONFIG_TEMPLATE: &str = include_str!("../../tmpls/rust-analyzer.toml"); - -// Key names -const KEY_CHECK_ON_SAVE: &str = "checkOnSave"; -const VALUE_CHECK_ON_SAVE_TRUE: &str = "true"; -const DISPLAY_CHECK_ON_SAVE_TRUE: &str = "checkOnSave = true"; - -// File names -const CFG_FILE_NAME: &str = ".rust-analyzer.toml"; -const SOURCE_FILE_NAME: &str = "rust-analyzer.toml"; - -const MSG_ALREADY_CORRECT: &str = "`.rust-analyzer.toml` already has the correct mling settings"; -const MSG_NON_EMPTY_ARRAY: &str = "`check.overrideCommand`: expected a non-empty array"; -const MSG_FIRST_ARG_INVALID: &str = - "`check.overrideCommand`: first argument should be `mling` or `mingling-cli`"; -const MSG_MISSING_SECOND: &str = "`check.overrideCommand`: missing second argument"; -const MSG_SECOND_ARG_INVALID: &str = - "`check.overrideCommand`: second argument should be a `ra-lint-*` subcommand or `lint`"; -const MSG_MESSAGE_FORMAT_REQUIRED: &str = - "`check.overrideCommand`: `lint` subcommand needs `--message-format=json`"; - -// Suggestions / replacements -const SUGGEST_RA_LINT_CHECK_ARRAY: &str = r#"["mling", "ra-lint-check"]"#; -const SUGGEST_MLING_QUOTED: &str = r#""mling""#; -const SUGGEST_RA_LINT_CHECK_QUOTED: &str = r#""ra-lint-check""#; -const SUGGEST_MESSAGE_FORMAT_JSON: &str = ", \"--message-format=json\"]"; -const SUGGEST_OVERRIDE_LINE: &str = "overrideCommand = [\"mling\", \"ra-lint-check\"]\n"; -const SUGGEST_OVERRIDE_FULL_LINE: &str = r#"check.overrideCommand = ["mling", "ra-lint-check"]"#; - -// Subcommand constants -const SUB_CMD_LINT: &str = "lint"; -const MESSAGE_FORMAT_FLAG: &str = "--message-format=json"; - -dispatcher!("lint-install", CMDLintInstall => EntryLintInstall); - -pack!(StateWriteMlingLinterConfig = PathBuf); -pack!(StateSuggestMlingLinterSetup = ()); -pack!(ResultMlingLinterConfigInstalled = PathBuf); - -#[chain] -pub fn handle_lint_install(_: EntryLintInstall, current_dir: &ResCurrentDir) -> Next { - let cfg_file_path = current_dir.join(CFG_FILE_NAME); - - if !cfg_file_path.exists() { - return StateWriteMlingLinterConfig::new(cfg_file_path).to_chain(); - } - - StateSuggestMlingLinterSetup::new(()).to_chain() -} - -#[chain(routeify)] -pub fn handle_state_write_mling_linter_config(prev: StateWriteMlingLinterConfig) -> Next { - let cfg_file_path = prev.inner; - std::fs::write(&cfg_file_path, RA_CONFIG_TEMPLATE)?; - ResultMlingLinterConfigInstalled::new(cfg_file_path).into() -} - -#[renderer(buffer)] -pub fn render_mling_linter_config_installed(result: ResultMlingLinterConfigInstalled) { - let cfg_file_path = result.inner; - r_eprintln!( - "info: created `{}` with mling lint-integrated settings", - cfg_file_path.display() - ); -} - -#[chain] -pub fn handle_state_suggest_mling_linter_setup( - _: StateSuggestMlingLinterSetup, - current_dir: &ResCurrentDir, -) -> StateLintReports { - let cfg_file_path = current_dir.join(CFG_FILE_NAME); - let file_name = cfg_file_path.to_string_lossy().to_string(); - - let content = match std::fs::read_to_string(&cfg_file_path) { - Ok(c) => c, - Err(e) => { - return StateLintReports::new(vec![MlintReport { - level: MlintLevel::Error, - message: format!("failed to read `{file_name}`: {e}"), - ..Default::default() - }]); - } - }; - - let mut reports: Vec<MlintReport> = vec![]; - reports.extend(check_simple_key( - &content, - KEY_CHECK_ON_SAVE, - VALUE_CHECK_ON_SAVE_TRUE, - DISPLAY_CHECK_ON_SAVE_TRUE, - SOURCE_FILE_NAME, - )); - reports.extend(check_override_command(&content, SOURCE_FILE_NAME)); - - if reports.is_empty() { - reports.push(MlintReport { - level: MlintLevel::Note, - message: MSG_ALREADY_CORRECT.to_string(), - ..Default::default() - }); - } - - StateLintReports::new(reports) -} - -/// A `MlintReport` at `Help` level with the given message, file, and source. -fn report_help(file_name: &str, source_code: &str, message: String) -> MlintReport { - MlintReport { - file_name: file_name.to_string(), - source_code: source_code.to_string(), - level: MlintLevel::Help, - message, - ..Default::default() - } -} - -/// Attach a single-line span + replace suggestion to a report. -fn with_replace_suggestion( - report: MlintReport, - line: usize, - line_text: &str, - byte_range: Range<usize>, - replacement: String, - label: Option<String>, -) -> MlintReport { - let span = LintSpan { - line_start: line, - line_end: line, - column_start: byte_range.start + 1, - column_end: byte_range.end + 1, - text: vec![LintSpanLine { - text: line_text.to_string(), - highlight_start: byte_range.start + 1, - highlight_end: byte_range.end + 1, - }], - label, - }; - let suggestion = LintSuggestion { - source: line_text.to_string(), - line_start: line, - byte_range, - replacement, - }; - MlintReport { - spans: vec![span], - suggestions: vec![suggestion], - ..report - } -} - -/// Attach an "insert new content" suggestion (byte_range 0..0) to a report. -fn with_insert_suggestion(report: MlintReport, line: usize, new_content: String) -> MlintReport { - let suggestion = LintSuggestion { - source: new_content.clone(), - line_start: line, - byte_range: 0..0, - replacement: new_content, - }; - MlintReport { - suggestions: vec![suggestion], - ..report - } -} - -fn check_simple_key( - content: &str, - key: &str, - expected_val: &str, - display_line: &str, - source_file: &str, -) -> Vec<MlintReport> { - let found = find_key_value(content, key); - - let matches = found - .as_ref() - .is_some_and(|(_, v)| collapse_whitespace(v) == collapse_whitespace(expected_val)); - - if matches { - return vec![]; - } - - let msg = format!("expected `{display_line}` in `rust-analyzer.toml`"); - let report = report_help(source_file, content, msg); - - match found { - Some((ln, val)) => { - // Key exists but value is wrong → suggest replacing the value - let line_text = nth_line(content, ln); - let byte_start = line_text.find(&val).unwrap_or(0); - let byte_end = byte_start + val.len(); - vec![with_replace_suggestion( - report, - ln, - &line_text, - byte_start..byte_end, - expected_val.to_string(), - Some(format!("expected {expected_val}")), - )] - } - None => { - // Key missing entirely → suggest inserting line at end - let insert_line = content.lines().count().max(1) + 1; - let new_content = format!("{display_line}\n"); - vec![with_insert_suggestion(report, insert_line, new_content)] - } - } -} - -fn check_override_command(content: &str, source_file: &str) -> Vec<MlintReport> { - let mut reports = Vec::new(); - - let Some((ln, val)) = find_key_value(content, OVERRIDE_KEY) else { - // Setting entirely missing - let report = report_help( - source_file, - content, - format!("expected `{EXPECTED_LINE}` in `rust-analyzer.toml`"), - ); - let (insert_line, new_content) = match find_table_header(content, "check") { - Some(header_line) => (header_line + 1, SUGGEST_OVERRIDE_LINE.to_string()), - None => ( - content.lines().count().max(1) + 1, - format!("{SUGGEST_OVERRIDE_FULL_LINE}\n"), - ), - }; - reports.push(with_insert_suggestion(report, insert_line, new_content)); - return reports; - }; - - let line_text = nth_line(content, ln); - let args = parse_array_items(&val); - - // First: must be `mling` or `mingling-cli` - if !args - .first() - .is_some_and(|a| VALID_FIRST.contains(&a.as_str())) - { - let Some(first) = args.first() else { - let report = report_help(source_file, content, MSG_NON_EMPTY_ARRAY.into()); - reports.push(with_replace_suggestion( - report, - ln, - &line_text, - 0..val.len(), - SUGGEST_RA_LINT_CHECK_ARRAY.into(), - None, - )); - return reports; - }; - let quoted = format!("\"{first}\""); - let byte_start = line_text.find("ed).unwrap_or(0); - let byte_end = byte_start + quoted.len(); - let report = report_help(source_file, content, MSG_FIRST_ARG_INVALID.into()); - reports.push(with_replace_suggestion( - report, - ln, - &line_text, - byte_start..byte_end, - SUGGEST_MLING_QUOTED.into(), - None, - )); - return reports; - } - - // Second: must be `ra-lint-*` or `lint` - let Some(second) = args.get(1) else { - let report = report_help(source_file, content, MSG_MISSING_SECOND.into()); - reports.push(with_replace_suggestion( - report, - ln, - &line_text, - 0..val.len(), - SUGGEST_RA_LINT_CHECK_ARRAY.into(), - None, - )); - return reports; - }; - - if !second.starts_with("ra-lint-") && second != SUB_CMD_LINT { - let quoted = format!("\"{second}\""); - let byte_start = line_text.find("ed).unwrap_or(0); - let byte_end = byte_start + quoted.len(); - let report = report_help(source_file, content, MSG_SECOND_ARG_INVALID.into()); - reports.push(with_replace_suggestion( - report, - ln, - &line_text, - byte_start..byte_end, - SUGGEST_RA_LINT_CHECK_QUOTED.into(), - None, - )); - return reports; - } - - // If second arg is `lint`, it must be followed by --message-format=json - if second == SUB_CMD_LINT && !has_message_format_json(&args[2..]) { - let byte_start = line_text - .rfind(']') - .unwrap_or(line_text.len().saturating_sub(1)); - let byte_end = byte_start + 1; - let report = report_help(source_file, content, MSG_MESSAGE_FORMAT_REQUIRED.into()); - reports.push(with_replace_suggestion( - report, - ln, - &line_text, - byte_start..byte_end, - SUGGEST_MESSAGE_FORMAT_JSON.into(), - None, - )); - } - - reports -} - -fn has_message_format_json(rest: &[String]) -> bool { - rest.contains(&MESSAGE_FORMAT_FLAG.to_string()) - || rest - .windows(2) - .any(|w| w[0] == "--message-format" && w[1] == "json") -} - -fn parse_array_items(s: &str) -> Vec<String> { - let s = s.trim(); - if !s.starts_with('[') || !s.ends_with(']') { - return vec![]; - } - let inner = s[1..s.len() - 1].trim(); - if inner.is_empty() { - return vec![]; - } - let mut items = Vec::new(); - let mut current = String::new(); - let mut in_quote = false; - for ch in inner.chars() { - match ch { - '"' => in_quote = !in_quote, - ',' if !in_quote => { - let trimmed = current.trim().trim_matches('"').to_string(); - if !trimmed.is_empty() { - items.push(trimmed); - } - current.clear(); - } - _ => current.push(ch), - } - } - let trimmed = current.trim().trim_matches('"').to_string(); - if !trimmed.is_empty() { - items.push(trimmed); - } - items -} - -/// Result of looking up a key=value pair in TOML content. -/// -/// - `Some((line, value))` — found on that 1-based line with that value string. -/// - `None` — key not found. -type FoundKey = Option<(usize, String)>; - -fn find_key_value(content: &str, dotted_key: &str) -> FoundKey { - let parts: Vec<&str> = dotted_key.split('.').collect(); - let field = parts.last().copied().unwrap_or(dotted_key); - let table_path = if parts.len() > 1 { - &parts[..parts.len() - 1] - } else { - &[] - }; - let table_path_str = if parts.len() > 1 { - Some(parts[..parts.len() - 1].join(".")) - } else { - None - }; - - let mut in_correct_table = table_path.is_empty(); - - for (i, line) in content.lines().enumerate() { - let trimmed = line.trim(); - - // Track table headers like [check] - if trimmed.starts_with('[') && trimmed.ends_with(']') { - let header = &trimmed[1..trimmed.len() - 1]; - in_correct_table = header.split('.').collect::<Vec<_>>() == table_path; - continue; - } - - let without_comment = trimmed.split('#').next().unwrap_or("").trim(); - if without_comment.is_empty() { - continue; - } - - if let Some(eq_pos) = without_comment.find('=') { - let k = without_comment[..eq_pos].trim(); - let v = without_comment[eq_pos + 1..].trim(); - - // Inside explicit [table] header - if in_correct_table && k == field { - return Some((i + 1, v.to_string())); - } - // Inline dotted key at root (e.g. `check.overrideCommand = ...`) - if table_path_str.is_some() && k == dotted_key { - return Some((i + 1, v.to_string())); - } - } - } - - None -} - -fn find_table_header(content: &str, table_name: &str) -> Option<usize> { - let target = format!("[{table_name}]"); - content - .lines() - .position(|line| line.trim() == target) - .map(|i| i + 1) -} - -fn nth_line(content: &str, n: usize) -> String { - content - .lines() - .nth(n.saturating_sub(1)) - .unwrap_or("") - .to_string() -} - -fn collapse_whitespace(s: &str) -> String { - let mut out = String::with_capacity(s.len()); - let mut in_space = false; - for ch in s.chars() { - if ch.is_whitespace() { - if !in_space { - out.push(' '); - in_space = true; - } - } else { - out.push(ch); - in_space = false; - } - } - out.trim().to_string() -} diff --git a/mingling_cli/src/lints.rs b/mingling_cli/src/lints.rs index 89f5ca3..8cc1e6e 100644 --- a/mingling_cli/src/lints.rs +++ b/mingling_cli/src/lints.rs @@ -1,3 +1,5 @@ +// This file is auto-generated by pre/lint_registry.rs + #![allow(unused)] use crate::linter::mlint_report::{MlintLevel, MlintReport}; diff --git a/mingling_cli/tmpls/lints.tmpl b/mingling_cli/tmpls/lints.tmpl index 590828a..e177079 100644 --- a/mingling_cli/tmpls/lints.tmpl +++ b/mingling_cli/tmpls/lints.tmpl @@ -1,3 +1,5 @@ +// This file is auto-generated by pre/lint_registry.rs + #![allow(unused)] use crate::linter::mlint_report::{MlintLevel, MlintReport}; diff --git a/mingling_cli/tmpls/rust-analyzer.toml b/mingling_cli/tmpls/rust-analyzer.toml deleted file mode 100644 index 96a96b4..0000000 --- a/mingling_cli/tmpls/rust-analyzer.toml +++ /dev/null @@ -1,9 +0,0 @@ -checkOnSave = true - -# Use mling with ra-lint-check for code checking -# -# This tool will: -# 1. first run `cargo check` to perform basic checks on your workspace -# 2. then run `mling lint` to perform additional checks -# on the `Mingling` framework code in your workspace -check.overrideCommand = ["mling", "ra-lint-check"] diff --git a/mingling_core/Cargo.toml b/mingling_core/Cargo.toml index 14140c6..f525609 100644 --- a/mingling_core/Cargo.toml +++ b/mingling_core/Cargo.toml @@ -14,7 +14,7 @@ categories = ["command-line-interface"] nightly = [] default = [] async = [] -builds = [] +build = [] picker = [] dispatch_tree = [] diff --git a/mingling_core/src/any.rs b/mingling_core/src/any.rs index 3e8fdf0..e922e2e 100644 --- a/mingling_core/src/any.rs +++ b/mingling_core/src/any.rs @@ -1,8 +1,8 @@ +use crate::ProgramCollect; use crate::error::ChainProcessError; -use crate::{Grouped, ProgramCollect}; -#[doc(hidden)] -pub mod group; +mod group; +pub use group::*; /// Any type output /// diff --git a/mingling_core/src/asset.rs b/mingling_core/src/asset.rs index 9b9a5d4..f26952b 100644 --- a/mingling_core/src/asset.rs +++ b/mingling_core/src/asset.rs @@ -1,26 +1,9 @@ -#[doc(hidden)] -pub mod chain; - -#[doc(hidden)] -pub mod dispatcher; - -#[doc(hidden)] -pub mod enum_tag; - -#[doc(hidden)] -pub mod global_resource; - -#[doc(hidden)] -pub mod help; - -#[doc(hidden)] -pub mod lazy_resource; - -#[doc(hidden)] -pub mod node; - -#[doc(hidden)] -pub mod renderer; - -#[doc(hidden)] -pub mod routable; +pub(crate) mod chain; +pub(crate) mod dispatcher; +pub(crate) mod enum_tag; +pub(crate) mod global_resource; +pub(crate) mod help; +pub(crate) mod lazy_resource; +pub(crate) mod node; +pub(crate) mod renderer; +pub(crate) mod routable; diff --git a/mingling_core/src/asset/global_resource.rs b/mingling_core/src/asset/global_resource.rs index a610378..19374e7 100644 --- a/mingling_core/src/asset/global_resource.rs +++ b/mingling_core/src/asset/global_resource.rs @@ -184,7 +184,10 @@ pub trait ResourceMarker { C: ProgramCollect<Enum = C> + 'static; } -impl<T: Default + Clone + Send + Sync + 'static> ResourceMarker for T { +impl<T> ResourceMarker for T +where + T: Default + Clone + Send + Sync + 'static, +{ fn res_clone(&self) -> Self { Clone::clone(self) } diff --git a/mingling_core/src/build.rs b/mingling_core/src/build.rs new file mode 100644 index 0000000..7918f3a --- /dev/null +++ b/mingling_core/src/build.rs @@ -0,0 +1,13 @@ +#[doc(hidden)] +#[cfg(feature = "comp")] +mod comp; + +#[cfg(feature = "comp")] +pub use comp::*; + +#[doc(hidden)] +#[cfg(feature = "pathf")] +mod pathf; + +#[cfg(feature = "pathf")] +pub use pathf::*; diff --git a/mingling_core/src/builds/comp.rs b/mingling_core/src/build/comp.rs index 2abb1e1..2abb1e1 100644 --- a/mingling_core/src/builds/comp.rs +++ b/mingling_core/src/build/comp.rs diff --git a/mingling_core/src/builds/pathf.rs b/mingling_core/src/build/pathf.rs index d8d4698..d8d4698 100644 --- a/mingling_core/src/builds/pathf.rs +++ b/mingling_core/src/build/pathf.rs diff --git a/mingling_core/src/builds.rs b/mingling_core/src/builds.rs deleted file mode 100644 index 3c52907..0000000 --- a/mingling_core/src/builds.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[doc(hidden)] -#[cfg(feature = "comp")] -pub mod comp; - -#[doc(hidden)] -#[cfg(feature = "pathf")] -pub mod pathf; diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 31476c9..b9dbd06 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -1,3 +1,4 @@ +// #![deny(missing_docs)] //! Mingling Core //! //! # Intro @@ -8,7 +9,7 @@ //! //! Recommended to import [mingling](https://crates.io/crates/mingling) to use its features. -#![deny(missing_docs)] +// Private Modules mod any; mod asset; @@ -16,20 +17,65 @@ mod program; mod renderer; mod tester; +/// Module for setting up a `Mingling` program. +/// +/// This module provides the [`ProgramSetup`] type, which allows users to configure +/// and initialize the program's execution environment. +pub mod setup { + pub use crate::program::setup::ProgramSetup; +} + +/// This module provides result types for Mingling components. +/// +/// These are re-exported at the top level via `mingling::res`. +#[doc(hidden)] +pub mod core_res { + #[cfg(feature = "repl")] + pub use crate::program::repl_exec::res::*; +} + +/// Provides the runtime logic for Mingling's dynamic completion system. +/// +/// This module contains the core functionality for the "comp" (completion) feature, +/// which enables dynamic tab-completion and input suggestion capabilities within +/// Mingling applications. +#[cfg(feature = "comp")] +pub(crate) mod comp; + +/// Provides Mingling's build script module, used in `build.rs` to provide build-time behavior for certain features. +/// +/// To use it, add the following to your `Cargo.toml` under `[build-dependencies]`, and enable the features +/// that require build-time behavior from the crate: +/// +/// ```toml +/// [build-dependencies.mingling] +/// version = "0.3.0" +/// features = [ +/// "build", // Enable it +/// "comp", // If you need completion-related build-time behavior, enable this as well +/// ] +/// ``` +#[cfg(feature = "build")] +#[doc(hidden)] +pub mod build; + +// Public Modules + /// Provides a toolkit for `Mingling` testing capabilities. pub mod test { pub use crate::tester::*; } -#[cfg(feature = "structural_renderer")] -pub use crate::renderer::structural::StructuralRenderer; +/// Provided for framework developers +pub mod debug; // NOT re-exported at top level: the `StructuralData` trait is sealed and only // accessible through the derive macro. Users who need the trait can access it // via `mingling::renderer::structural::StructuralData` (through the inner alias). -pub use crate::any::group::*; -pub use crate::any::*; +#[cfg(feature = "structural_renderer")] +pub use crate::renderer::structural::StructuralRenderer; +pub use crate::any::*; pub use crate::asset::chain::*; pub use crate::asset::dispatcher::*; pub use crate::asset::enum_tag::*; @@ -39,74 +85,32 @@ pub use crate::asset::lazy_resource::*; pub use crate::asset::node::*; pub use crate::asset::renderer::*; pub use crate::asset::routable::*; +#[cfg(feature = "comp")] +pub use crate::comp::*; +pub use crate::program::*; +pub use crate::renderer::render_result::*; /// All error types of `Mingling` pub mod error { pub use crate::asset::chain::error::*; pub use crate::exec::error::*; pub use crate::program::error::*; + #[cfg(feature = "structural_renderer")] pub use crate::renderer::structural::error::*; - #[cfg(feature = "pathf")] - pub use mingling_pathf::error::*; -} - -pub use crate::program::*; - -pub use crate::renderer::render_result::*; - -#[cfg(feature = "builds")] -#[doc(hidden)] -pub mod builds; - -/// Provides build scripts for users -#[cfg(feature = "builds")] -pub mod build { - #[cfg(feature = "comp")] - pub use crate::builds::comp::*; #[cfg(feature = "pathf")] - pub use crate::builds::pathf::*; + pub use mingling_pathf::error::*; } -/// Provided for framework developers -pub mod debug; - -#[cfg(feature = "comp")] #[doc(hidden)] -pub mod comp; - -#[cfg(feature = "comp")] -pub use crate::comp::*; +mod private; -/// Module for setting up a `Mingling` program. +/// Internal API provided by Mingling Core /// -/// This module provides the [`ProgramSetup`] type, which allows users to configure -/// and initialize the program's execution environment. -pub mod setup { - pub use crate::program::setup::ProgramSetup; -} - -/// Private API — not intended for direct use. +/// These are used by macros and are not exposed to users, but are still accessible externally. #[doc(hidden)] +#[allow(unused_imports)] pub mod __private { - use crate::ProgramCollect; - - /// Sealed trait for `StructuralData` — only implementable via derive macro. - pub trait StructuralDataSealed<C> - where - C: ProgramCollect<Enum = C>, - { - } - - /// Re-export so the derive macro can reference the trait without - /// conflicting with the derive macro name at `::mingling::StructuralData`. - #[cfg(feature = "structural_renderer")] - pub use crate::renderer::structural::structural_data::StructuralData; -} - -#[doc(hidden)] -pub mod core_res { - #[cfg(feature = "repl")] - pub use crate::program::repl_exec::res::ResREPL; + pub use crate::private::*; } diff --git a/mingling_core/src/private.rs b/mingling_core/src/private.rs new file mode 100644 index 0000000..371ada2 --- /dev/null +++ b/mingling_core/src/private.rs @@ -0,0 +1,12 @@ +/// Sealed trait for `StructuralData` — only implementable via derive macro. +#[cfg(feature = "structural_renderer")] +pub trait StructuralDataSealed<C> +where + C: crate::ProgramCollect<Enum = C>, +{ +} + +/// Re-export so the derive macro can reference the trait without +/// conflicting with the derive macro name at `::mingling::StructuralData`. +#[cfg(feature = "structural_renderer")] +pub use crate::renderer::structural::structural_data::StructuralData; diff --git a/mingling_core/tests/test-all/tests/integration.rs b/mingling_core/tests/test-all/tests/integration.rs index d36b9df..acb12db 100644 --- a/mingling_core/tests/test-all/tests/integration.rs +++ b/mingling_core/tests/test-all/tests/integration.rs @@ -7,9 +7,9 @@ use mingling::StringVec; use mingling::StructuralData; use mingling::StructuralRenderer; use mingling::StructuralRendererSetting; -use mingling::comp::{ShellContext, ShellFlag, Suggest}; use mingling::core_res::ResREPL; use mingling::hook::ProgramHook; +use mingling::{ShellContext, ShellFlag, Suggest}; use serde::Serialize; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/mingling_core/tests/test-comp/tests/integration.rs b/mingling_core/tests/test-comp/tests/integration.rs index 37aa716..5c5a9e4 100644 --- a/mingling_core/tests/test-comp/tests/integration.rs +++ b/mingling_core/tests/test-comp/tests/integration.rs @@ -1,6 +1,6 @@ use mingling::MockProgramCollect; use mingling::Program; -use mingling::comp::{ShellContext, ShellFlag, Suggest, SuggestItem}; +use mingling::{ShellContext, ShellFlag, Suggest, SuggestItem}; #[test] fn test_shell_context_parsing_full() { diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..f328e4d --- /dev/null +++ b/src/main.rs @@ -0,0 +1 @@ +fn main() {} |
