aboutsummaryrefslogtreecommitdiff
path: root/mling
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-20 15:29:22 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-20 15:29:22 +0800
commit62e323c80306d7dca68e47377a0ed6f4e146ba48 (patch)
tree0c6fe91d7197c83af52b08f793d12b0f01646d7d /mling
parent33da7c8cb4f24caeef4e8127bc484bc9d236a0f3 (diff)
feat: remove deprecated mling scaffolding tool
The mling CLI tool is being rewritten, so remove all its source files, resources, and workspace membership to clean up the repository
Diffstat (limited to 'mling')
-rw-r--r--mling/.gitignore2
-rw-r--r--mling/Cargo.toml41
l---------mling/LICENSE-APACHE1
l---------mling/LICENSE-MIT1
-rw-r--r--mling/README.md3
-rw-r--r--mling/build.rs63
-rw-r--r--mling/res/CHECKLIST.md110
-rw-r--r--mling/res/template_0.2/command/Cargo.toml.tmpl0
-rw-r--r--mling/res/template_0.2/command/src/main.rs1
-rw-r--r--mling/res/template_0.2/flat/Cargo.toml.tmpl0
-rw-r--r--mling/res/template_0.2/flat/src/main.rs0
-rw-r--r--mling/res/template_0.2/modularity/Cargo.toml.tmpl0
-rw-r--r--mling/res/template_0.2/modularity/src/main.rs0
-rw-r--r--mling/src/bin/cargo-mling.rs3
-rw-r--r--mling/src/bin/mling.rs3
-rw-r--r--mling/src/cargo_style.rs221
-rw-r--r--mling/src/cli.rs198
-rw-r--r--mling/src/display.rs384
-rw-r--r--mling/src/errors.rs2
-rw-r--r--mling/src/errors/io_error.rs224
-rw-r--r--mling/src/helps/mling_help.txt20
-rw-r--r--mling/src/lib.rs18
-rw-r--r--mling/src/pkg_mgr/installer.rs1
-rw-r--r--mling/src/pkg_mgr/mod.rs18
-rw-r--r--mling/src/proj_mgr/checklist_reader.rs294
-rw-r--r--mling/src/proj_mgr/generator.rs57
-rw-r--r--mling/src/proj_mgr/metadata.rs142
-rw-r--r--mling/src/proj_mgr/mod.rs30
-rw-r--r--mling/src/proj_mgr/show_binaries.rs78
-rw-r--r--mling/src/proj_mgr/show_directories.rs61
-rw-r--r--mling/src/res/current_dir.rs6
-rw-r--r--mling/src/res/manifest_path.rs13
-rw-r--r--mling/src/res/mod.rs5
33 files changed, 0 insertions, 2000 deletions
diff --git a/mling/.gitignore b/mling/.gitignore
deleted file mode 100644
index b124b7c..0000000
--- a/mling/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-debug.rs
-version.txt
diff --git a/mling/Cargo.toml b/mling/Cargo.toml
deleted file mode 100644
index 8008463..0000000
--- a/mling/Cargo.toml
+++ /dev/null
@@ -1,41 +0,0 @@
-[package]
-name = "mingling-cli"
-version.workspace = true
-edition.workspace = true
-authors = ["Weicao-CatilGrass"]
-license.workspace = true
-readme = "README.md"
-repository.workspace = true
-description = "Mingling's scaffolding tool"
-keywords = ["cli", "scaffolding", "command-line", "framework"]
-categories = ["command-line-interface"]
-
-[[bin]]
-name = "cargo-mling"
-path = "src/bin/cargo-mling.rs"
-
-[[bin]]
-name = "mling"
-path = "src/bin/mling.rs"
-
-[dependencies]
-mingling = { path = "../mingling", features = [
- "parser",
- "comp",
- "structural_renderer",
- "extra_macros",
- "yaml_serde_fmt",
- "pathf"
-] }
-
-serde = { version = "1", features = ["derive"] }
-serde_json = "1"
-
-colored = "3.1.1"
-dirs = "6.0.0"
-just_fmt = "0.1.2"
-toml.workspace = true
-
-[build-dependencies]
-chrono = "0.4"
-mingling = { path = "../mingling", features = ["comp", "pathf", "builds"] }
diff --git a/mling/LICENSE-APACHE b/mling/LICENSE-APACHE
deleted file mode 120000
index 965b606..0000000
--- a/mling/LICENSE-APACHE
+++ /dev/null
@@ -1 +0,0 @@
-../LICENSE-APACHE \ No newline at end of file
diff --git a/mling/LICENSE-MIT b/mling/LICENSE-MIT
deleted file mode 120000
index 76219eb..0000000
--- a/mling/LICENSE-MIT
+++ /dev/null
@@ -1 +0,0 @@
-../LICENSE-MIT \ No newline at end of file
diff --git a/mling/README.md b/mling/README.md
deleted file mode 100644
index a4d0b1d..0000000
--- a/mling/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-This directory is the companion CLI tool for Mingling. After installation, it can be invoked via `cargo mling` or `mling`.
-
-It is currently under refactoring and **completely unusable**.
diff --git a/mling/build.rs b/mling/build.rs
deleted file mode 100644
index 9a7b503..0000000
--- a/mling/build.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use std::path::Path;
-use std::process::Command;
-
-use mingling::build::analyze_and_build_type_mapping;
-use mingling::build::build_comp_scripts;
-
-fn main() {
- build_version_info();
- build_completion();
- analyze_and_build_type_mapping().unwrap();
-}
-
-fn build_version_info() {
- // Read version from CARGO_PKG_VERSION (inherited from workspace Cargo.toml)
- let version = env!("CARGO_PKG_VERSION");
-
- // Get git commit hash (first 9 characters)
- let commit_hash = Command::new("git")
- .args(["rev-parse", "--short=9", "HEAD"])
- .output()
- .ok()
- .and_then(|output| {
- if output.status.success() {
- String::from_utf8(output.stdout).ok()
- } else {
- None
- }
- })
- .map(|s| s.trim().to_string())
- .unwrap_or_else(|| "unknown".to_string());
-
- // Get date from git commit, fallback to current date
- let date = Command::new("git")
- .args(["log", "-1", "--format=%ad", "--date=format:%Y-%m-%d"])
- .output()
- .ok()
- .and_then(|output| {
- if output.status.success() {
- String::from_utf8(output.stdout).ok()
- } else {
- None
- }
- })
- .map(|s| s.trim().to_string())
- .unwrap_or_else(|| chrono::Local::now().format("%Y-%m-%d").to_string());
-
- let version_string = format!("mling {version} ({commit_hash} {date})");
-
- let out_dir = Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap())
- .join("src")
- .join("helps")
- .join("version.txt");
-
- std::fs::write(&out_dir, version_string).expect("failed to write version.txt");
-
- println!("cargo::rerun-if-changed=../Cargo.toml");
- println!("cargo::rerun-if-changed=../Cargo.lock");
- println!("cargo::rerun-if-changed=.git/HEAD");
-}
-
-fn build_completion() {
- build_comp_scripts("mling").unwrap();
-}
diff --git a/mling/res/CHECKLIST.md b/mling/res/CHECKLIST.md
deleted file mode 100644
index bc7b8bc..0000000
--- a/mling/res/CHECKLIST.md
+++ /dev/null
@@ -1,110 +0,0 @@
-> [!NOTE]
->
-> You are using `mling` to create your `mingling` project. Before proceeding, please fill in your project information.
-
-## Question 1: Fill in your project information
-
-Use `snake-case` style to fill in the project name. It will serve as your `crate` name:
-
-```name
-my-cli
-```
-
-Describe your `program` in one sentence:
-
-```description
-This is a command-line program
-```
-
-## Question 2: Which Mingling version do you need?
-
-> [!TIP]
->
-> You must select **EXACTLY ONE** option
-
-- [x] `ver:0.2` Based on the `Mingling@0.2.x` template
-
-## Question 3: What is your project layout style?
-
-> [!TIP]
->
-> You must select **EXACTLY ONE** option
-
-- [x] `base:flat` Flat mode (Simple)
-
-```
-# The most basic mode
-./main.rs
-./foo.rs
-./bar.rs
-./globals.rs
-```
-
-- [ ] `base:modularity` Modular mode
-
-```
-├─ module1/ # Stores private concepts internally
-│ ├── mod.rs # Command registration
-│ ├── chains/ # Core logic
-│ └── renderers/ # Result rendering
-├─ module2/
-│ ├── mod.rs # Command registration
-│ ├── chains/ # Core logic
-│ └── renderers/ # Result rendering
-├─ global/ # Stores public concepts in the global directory
-│ ├── errors/ # Global Errors
-│ ├── setups/ # Setups
-│ └── resources/ # Global Resources
-└─ main.rs
-```
-
-- [ ] `base:command` Command mode
-
-```
-# Stores all commands
-├─ commands/ # Organizes subcommands by hierarchy
-│ ├── remote/add.rs # "remote add"
-│ ├── remote/rm.rs # "remote rm"
-│ ├── remote.rs # Not a command,
-│ │ but a local implementation for
-│ │ the remote series of commands
-│ ├── foo.rs # "foo"
-│ └── bar.rs # "bar"
-├─ errors/ # Global Errors
-├─ resources/ # Global Resources
-├─ setups/ # Setups
-└─ main.rs
-```
-
-## Question 4: What additional features do you need to enable?
-
-> [!TIP]
->
-> All of the following options are **OPTIONAL**
-
-**Pre:**
-
-- [x] `exec:git_init` Initialize this project as a git repository (requires `git` to be installed)
-
-**Features:**
-
-- [x] `feat:extra_macros` Extra macro support
-- [x] `feat:dispatch_tree` Compile-time dispatch tree (solidify all commands)
-- [ ] `feat:structural_renderer` Structural renderer (JSON/YAML) for feature output
-- [ ] `feat:comp` Dynamic completion system
-- [ ] `feat:clap` Clap support
-- [ ] `feat:parser` Mingling Picker parser support
-- [ ] `feat:async` Async support
-
-**Implementations:**
-
-- [ ] `impl:exit_code` Introduce exit code control
-- [ ] `impl:fallback` Fallback functionality when no command is given
-
----
-
-After filling in the above, execute the following command to create the project:
-
-```
-~# mling gen
-```
diff --git a/mling/res/template_0.2/command/Cargo.toml.tmpl b/mling/res/template_0.2/command/Cargo.toml.tmpl
deleted file mode 100644
index e69de29..0000000
--- a/mling/res/template_0.2/command/Cargo.toml.tmpl
+++ /dev/null
diff --git a/mling/res/template_0.2/command/src/main.rs b/mling/res/template_0.2/command/src/main.rs
deleted file mode 100644
index 8b13789..0000000
--- a/mling/res/template_0.2/command/src/main.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/mling/res/template_0.2/flat/Cargo.toml.tmpl b/mling/res/template_0.2/flat/Cargo.toml.tmpl
deleted file mode 100644
index e69de29..0000000
--- a/mling/res/template_0.2/flat/Cargo.toml.tmpl
+++ /dev/null
diff --git a/mling/res/template_0.2/flat/src/main.rs b/mling/res/template_0.2/flat/src/main.rs
deleted file mode 100644
index e69de29..0000000
--- a/mling/res/template_0.2/flat/src/main.rs
+++ /dev/null
diff --git a/mling/res/template_0.2/modularity/Cargo.toml.tmpl b/mling/res/template_0.2/modularity/Cargo.toml.tmpl
deleted file mode 100644
index e69de29..0000000
--- a/mling/res/template_0.2/modularity/Cargo.toml.tmpl
+++ /dev/null
diff --git a/mling/res/template_0.2/modularity/src/main.rs b/mling/res/template_0.2/modularity/src/main.rs
deleted file mode 100644
index e69de29..0000000
--- a/mling/res/template_0.2/modularity/src/main.rs
+++ /dev/null
diff --git a/mling/src/bin/cargo-mling.rs b/mling/src/bin/cargo-mling.rs
deleted file mode 100644
index 4c285c6..0000000
--- a/mling/src/bin/cargo-mling.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
- mingling_cli::cli::run();
-}
diff --git a/mling/src/bin/mling.rs b/mling/src/bin/mling.rs
deleted file mode 100644
index 4c285c6..0000000
--- a/mling/src/bin/mling.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
- mingling_cli::cli::run();
-}
diff --git a/mling/src/cargo_style.rs b/mling/src/cargo_style.rs
deleted file mode 100644
index c212094..0000000
--- a/mling/src/cargo_style.rs
+++ /dev/null
@@ -1,221 +0,0 @@
-use colored::Colorize;
-
-/// Formats a message in cargo-style format with a bold green prefix.
-///
-/// The message should be in the format `prefix: content`. The prefix will be
-/// bold green and right-padded to 12 characters. If there is no colon in the
-/// string, the entire string is printed as content with an empty prefix.
-///
-/// # Macros
-///
-/// - `format_cargo!("prefix: {}", arg)` — format-style invocation
-/// - `format_cargo!(expr)` — direct expression invocation
-///
-/// # Panics
-///
-/// Panics if the prefix (text before the first `:`) exceeds 12 characters.
-///
-/// # Examples
-///
-/// ```ignore
-/// format_cargo!("Compiling: hello.rs");
-/// // Output: " Compiling hello.rs" (green bold "Compiling" padded to 12)
-/// ```
-#[macro_export]
-macro_rules! format_cargo {
- ($fmt:literal, $($arg:tt)*) => {
- $crate::get_cargo_info_format(format!($fmt, $($arg)*))
- };
- ($cmd:expr) => {
- $crate::get_cargo_info_format($cmd)
- };
-}
-
-/// Formats an error message in cargo-style format with a bold red "error" prefix.
-///
-/// # Macros
-///
-/// - `eformat_cargo!("prefix: {}", arg)` — format-style invocation
-/// - `eformat_cargo!(expr)` — direct expression invocation
-///
-/// # Examples
-///
-/// ```ignore
-/// eformat_cargo!("failed to parse input");
-/// // Output: "error: failed to parse input" (red bold "error")
-/// ```
-#[macro_export]
-macro_rules! eformat_cargo {
- ($fmt:literal, $($arg:tt)*) => {
- $crate::get_cargo_error_format(format!($fmt, $($arg)*))
- };
- ($cmd:expr) => {
- $crate::get_cargo_error_format($cmd)
- };
-}
-
-/// Formats a help message in cargo-style format with a bright white "help" prefix.
-///
-/// # Macros
-///
-/// - `hformat_cargo!("prefix: {}", arg)` — format-style invocation
-/// - `hformat_cargo!(expr)` — direct expression invocation
-///
-/// # Examples
-///
-/// ```ignore
-/// hformat_cargo!("use --verbose for more info");
-/// // Output: "help: use --verbose for more info" (bright white "help")
-/// ```
-#[macro_export]
-macro_rules! hformat_cargo {
- ($fmt:literal, $($arg:tt)*) => {
- $crate::get_cargo_help_format(format!($fmt, $($arg)*))
- };
- ($cmd:expr) => {
- $crate::get_cargo_help_format($cmd)
- };
-}
-
-/// Print a message in cargo-style format with a bold green prefix.
-///
-/// # Macros
-///
-/// - `println_cargo!("prefix: {}", arg)` — format-style invocation
-/// - `println_cargo!(expr)` — direct expression invocation
-///
-/// # Examples
-///
-/// ```ignore
-/// println_cargo!("Compiling: hello.rs");
-/// ```
-#[macro_export]
-macro_rules! println_cargo {
- ($fmt:literal, $($arg:tt)*) => {
- println!("{}", $crate::get_cargo_info_format(format!($fmt, $($arg)*)))
- };
- ($cmd:expr) => {
- println!("{}", $crate::get_cargo_info_format($cmd))
- };
-}
-
-/// Print an error message in cargo-style format with a bold red "error" prefix.
-///
-/// # Macros
-///
-/// - `eprintln_cargo!("prefix: {}", arg)` — format-style invocation
-/// - `eprintln_cargo!(expr)` — direct expression invocation
-///
-/// # Examples
-///
-/// ```ignore
-/// eprintln_cargo!("failed to parse input");
-/// ```
-#[macro_export]
-macro_rules! eprintln_cargo {
- ($fmt:literal, $($arg:tt)*) => {
- eprintln!("{}", $crate::get_cargo_error_format(format!($fmt, $($arg)*)))
- };
- ($cmd:expr) => {
- eprintln!("{}", $crate::get_cargo_error_format($cmd))
- };
-}
-
-/// Print a help message in cargo-style format with a bright white "help" prefix.
-///
-/// # Macros
-///
-/// - `hprintln_cargo!("prefix: {}", arg)` — format-style invocation
-/// - `hprintln_cargo!(expr)` — direct expression invocation
-///
-/// # Examples
-///
-/// ```ignore
-/// hprintln_cargo!("use --verbose for more info");
-/// ```
-#[macro_export]
-macro_rules! hprintln_cargo {
- ($fmt:literal, $($arg:tt)*) => {
- println!("{}", $crate::get_cargo_help_format(format!($fmt, $($arg)*)))
- };
- ($cmd:expr) => {
- println!("{}", $crate::get_cargo_help_format($cmd))
- };
-}
-
-/// Format a message in cargo style format, with bold green prefix.
-///
-/// The input string is split at the first `:`. The part before the colon becomes
-/// the prefix (bold green, right-padded to 12 characters), and the part after
-/// becomes the content.
-///
-/// If no colon is found, the entire string is treated as content and no prefix
-/// is shown.
-///
-/// # Panics
-///
-/// Panics if the prefix (text before the first `:`) exceeds 12 characters.
-///
-/// # Examples
-///
-/// ```ignore
-/// get_cargo_info_format("Compiling: my_program.rs");
-/// // returns " Compiling my_program.rs"
-/// ```
-pub fn get_cargo_info_format(str: impl Into<String>) -> String {
- let s = str.into();
- let (prefix, content) = if let Some(pos) = s.find(':') {
- (
- s[..pos].trim().to_string(),
- s[pos + 1..].trim_start().to_string(),
- )
- } else {
- (String::new(), s.trim().to_string())
- };
-
- assert!(
- prefix.len() <= 12,
- "prefix length exceeds 12: '{}' has length {}",
- prefix,
- prefix.len()
- );
-
- let padding = " ".repeat(12 - prefix.len());
-
- format!(
- "{}{} {}",
- padding,
- prefix.bold().bright_green(),
- content.trim()
- )
-}
-
-/// Format an error message in cargo style format, with bold red "error" prefix.
-///
-/// The input string is printed as the error content, prefixed by a bold red
-/// `error:` label.
-///
-/// # Examples
-///
-/// ```ignore
-/// get_cargo_error_format("something went wrong");
-/// // returns "error: something went wrong"
-/// ```
-pub fn get_cargo_error_format(str: impl Into<String>) -> String {
- format!("{}: {}", "error".bold().bright_red(), str.into())
-}
-
-/// Format a help message in cargo style format, with bright white "help" prefix.
-///
-/// The input string is printed as the help content, prefixed by a bright white
-/// `help:` label (not bold).
-///
-/// # Examples
-///
-/// ```ignore
-/// get_cargo_help_format("use --verbose for more info");
-/// // returns "help: use --verbose for more info"
-/// ```
-pub fn get_cargo_help_format(str: impl Into<String>) -> String {
- format!("{}: {}", "help".bright_white(), str.into())
-}
diff --git a/mling/src/cli.rs b/mling/src/cli.rs
deleted file mode 100644
index 20906c0..0000000
--- a/mling/src/cli.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-// `mling` has not been replaced from `parser` to `picker` yet
-#![allow(deprecated)]
-
-use crate::{
- CMDCompletion, ErrorDispatcherNotFound, Next, ThisProgram,
- display::markdown,
- eformat_cargo, eprintln_cargo, hformat_cargo,
- pkg_mgr::{CMDInstall, CMDListNamespace, CMDRemoveNamespace, PackageManagerSetup},
- proj_mgr::ProjectManagerSetup,
- res::{ResCurrentDir, ResManifestPath},
-};
-use colored::Colorize;
-use mingling::{
- Grouped, Program, RenderResult, Routable,
- hook::ProgramHook,
- macros::{chain, help, pack, program_setup, renderer},
- res::ResExitCode,
- setup::{ExitCodeSetup, HelpFlagSetup, QuietFlagSetup, StructuralRendererSetup},
-};
-use std::{env::current_dir, io::Write, path::PathBuf, process::exit, str::FromStr};
-
-pub fn run() {
- #[cfg(windows)]
- colored::control::set_virtual_terminal(true).unwrap();
-
- // Preprocess args to handle cargo-mling invocations
- let mut args: Vec<String> = std::env::args().collect();
- if args.first().is_some_and(|a| a.contains("cargo-mling")) {
- args[0] = "cargo-mling".to_string();
- }
- if args.get(1).is_some_and(|a| a == "mling") {
- args.remove(1);
- }
-
- // Build program with preprocessed args
- let mut program = Program::<ThisProgram>::new_with_args(args);
-
- // Intercept Version
- program.global_flag(["-V", "--version"], |_| {
- eprintln!(include_str!("helps/version.txt"));
- exit(0)
- });
-
- // Intercept Help
- program.with_hook(
- ProgramHook::empty().on_post_dispatch(|info| match info.entry {
- // When dispatcher is not found
- ThisProgram::ErrorDispatcherNotFound
- // And user requests Help
- if ThisProgram::this().user_context.help => {
- // Print help
- eprintln!("{}", markdown(include_str!("helps/mling_help.txt")));
- exit(0)
- }
- _ => {}
- }),
- );
-
- // Commands
- program.with_dispatcher(CMDCompletion);
-
- // Setups
- program.with_setup(HelpFlagSetup::new(["-h", "--help"]));
- program.with_setup(StructuralRendererSetup);
- program.with_setup(ExitCodeSetup::default());
-
- program.with_setup(StandardOutputSetup);
- program.with_setup(PackageManagerSetup);
- program.with_setup(ProjectManagerSetup);
-
- // Resources
- program.with_resource(ResCurrentDir {
- path: current_dir().unwrap(),
- });
-
- let manifest_path = program.pick_global_argument(["-P", "--manifest-path"]);
- program.with_resource(ResManifestPath {
- raw: manifest_path,
- resolved: None,
- });
-
- // Manifest Path Check
- if !program.is_completing() {
- program.with_hook(ProgramHook::empty().on_post_dispatch(|_| {
- let p = ThisProgram::this();
- p.modify_res(|manifest_path: &mut ResManifestPath| {
- manifest_path.resolved = Some(resolve_manifest_path(manifest_path.raw.clone()));
- });
- }));
- }
-
- // Execute
- let quiet = program.stdout_setting.quiet;
- let error_output = program.stdout_setting.error_output && !quiet;
- let render_output = program.stdout_setting.render_output && !quiet;
- let result = program.exec_without_render().unwrap();
- if !result.is_empty() {
- if result.exit_code == 0 && render_output {
- println!("{}", result.trim());
- } else if error_output {
- eprintln!("{}", result.trim());
- }
- }
- exit(result.exit_code);
-}
-
-#[program_setup]
-fn standard_output_setup(program: &mut Program<ThisProgram>) {
- program.with_setup(QuietFlagSetup::new("--silence"));
- program.global_flag(["--no-error"], |program| {
- program.stdout_setting.error_output = false;
- });
- program.global_flag(["--no-result"], |program| {
- program.stdout_setting.render_output = false;
- });
- program.global_flag(["--silence", "--quiet"], |program| {
- program.stdout_setting.quiet = true;
- });
-}
-
-fn resolve_manifest_path(provided: Option<String>) -> PathBuf {
- let p = ThisProgram::this();
- let disable_error_output =
- // --no-error
- !p.stdout_setting.error_output ||
- // or --quiet/--silence
- p.stdout_setting.quiet;
-
- if let Some(path) = provided {
- let p = PathBuf::from_str(&path).unwrap();
- if p.is_dir() {
- let candidate = p.join("Cargo.toml");
- if candidate.exists() {
- return candidate;
- }
- if !disable_error_output {
- eprintln_cargo!("`{}` is not a crate root", p.display());
- }
- exit(1);
- }
- return p;
- }
- // Walk up from current directory to find nearest Cargo.toml
- let mut dir = current_dir().unwrap();
- loop {
- let candidate = dir.join("Cargo.toml");
- if candidate.exists() {
- return candidate;
- }
- if !dir.pop() {
- // Reached filesystem root without finding Cargo.toml
- if !disable_error_output {
- eprintln_cargo!("`{}` is not a crate root", current_dir().unwrap().display());
- }
- exit(1);
- }
- }
-}
-
-pack!(ResultMlingHelp = ());
-pack!(ResultUnknownCommand = String);
-
-#[chain]
-pub fn handle_error_dispatcher_not_found(err: ErrorDispatcherNotFound) -> Next {
- if err.is_empty() {
- ResultMlingHelp::default().to_render()
- } else {
- ResultUnknownCommand::new(err.join(" ")).to_render()
- }
-}
-
-#[renderer]
-pub fn render_mling_help(_prev: ResultMlingHelp, ec: &mut ResExitCode) -> RenderResult {
- let mut result = RenderResult::default();
- writeln!(result, "{}", markdown(include_str!("helps/mling_help.txt"))).ok();
- ec.exit_code = 0;
- result
-}
-
-#[renderer]
-pub fn render_unknown_command(prev: ResultUnknownCommand, ec: &mut ResExitCode) -> RenderResult {
- let mut result = RenderResult::default();
- writeln!(
- result,
- "{}",
- eformat_cargo!("no such command: `{}`", prev.bright_yellow().bold())
- )
- .ok();
- writeln!(result).ok();
- writeln!(
- result,
- "{}",
- hformat_cargo!("view all commands with `cargo help mling`")
- )
- .ok();
- ec.exit_code = 101;
- result
-}
diff --git a/mling/src/display.rs b/mling/src/display.rs
deleted file mode 100644
index 313a054..0000000
--- a/mling/src/display.rs
+++ /dev/null
@@ -1,384 +0,0 @@
-use colored::Colorize;
-use std::collections::VecDeque;
-
-/// Trait for adding markdown formatting to strings
-pub trait Markdown {
- fn markdown(&self) -> String;
-}
-
-impl Markdown for &str {
- fn markdown(&self) -> String {
- markdown(self)
- }
-}
-
-impl Markdown for String {
- fn markdown(&self) -> String {
- markdown(self)
- }
-}
-
-/// Converts a string to colored/formatted text with ANSI escape codes.
-///
-/// Supported syntax:
-/// - Bold: `**text**`
-/// - Italic: `*text*`
-/// - Underline: `_text_`
-/// - Angle-bracketed content: `<text>` (displayed as cyan)
-/// - Inline code: `` `text` `` (displayed as green)
-/// - Color tags: `[[color_name]]` and `[[/]]` to close color
-/// - Escape characters: `\*`, `\<`, `\>`, `` \` ``, `\_` for literal characters
-/// - Headings: `# Heading 1`, `## Heading 2`, up to `###### Heading 6`
-/// - Blockquote: `> text` (displays a gray background marker at the beginning of the line)
-///
-/// Color tags support the following color names:
-/// Color tags support the following color names:
-///
-/// | Type | Color Names |
-/// |-------------------------|-----------------------------------------------------------------------------|
-/// | Standard colors | `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white` |
-/// | Bright colors | `bright_black` |
-/// | | `bright_red` |
-/// | | `bright_green` |
-/// | | `bright_yellow` |
-/// | | `bright_blue` |
-/// | | `bright_magenta` |
-/// | | `bright_cyan` |
-/// | | `bright_white` |
-/// | Bright color shorthands | `b_black` |
-/// | | `b_red` |
-/// | | `b_green` |
-/// | | `b_yellow` |
-/// | | `b_blue` |
-/// | | `b_magenta` |
-/// | | `b_cyan` |
-/// | | `b_white` |
-/// | Gray colors | `gray`/`grey` |
-/// | | `bright_gray`/`bright_grey` |
-/// | | `b_gray`/`b_grey` |
-///
-/// Color tags can be nested, `[[/]]` will close the most recently opened color tag.
-///
-/// # Arguments
-/// * `text` - The text to format, can be any type that implements `AsRef<str>`
-///
-/// # Returns
-/// Returns a `String` containing ANSI escape codes that can display colored/formatted text in ANSI-supported terminals.
-///
-/// # Examples
-/// ```
-/// # use mingling_cli::display::markdown;
-/// let formatted = markdown("Hello **world**!");
-/// println!("{}", formatted);
-///
-/// let colored = markdown("[[red]]Red text[[/]] and normal text");
-/// println!("{}", colored);
-///
-/// let nested = markdown("[[blue]]Blue [[green]]Green[[/]] Blue[[/]] normal");
-/// println!("{}", nested);
-/// ```
-pub fn markdown(text: impl AsRef<str>) -> String {
- let text = text.as_ref();
- let lines: Vec<&str> = text.lines().collect();
- let mut result = String::new();
- let mut content_indent = 0;
-
- for line in lines {
- // Don't trim the line initially, we need to check if it starts with #
- let trimmed_line = line.trim();
- let mut line_result = String::new();
-
- // Check if line starts with # for heading
- // Check if the original line (not trimmed) starts with #
- if line.trim_start().starts_with('#') {
- let chars: Vec<char> = line.trim_start().chars().collect();
- let mut level = 0;
-
- // Count # characters at the beginning
- while level < chars.len() && level < 7 && chars[level] == '#' {
- level += 1;
- }
-
- // Cap level at 6
- let effective_level = if level > 6 { 6 } else { level };
-
- // Skip # characters and any whitespace after them
- let mut content_start = level;
- while content_start < chars.len() && chars[content_start].is_whitespace() {
- content_start += 1;
- }
-
- // Extract heading content
- let heading_content: String = if content_start < chars.len() {
- chars[content_start..].iter().collect()
- } else {
- String::new()
- };
-
- // Process the heading content with formatting
- let processed_content = process_line(&heading_content);
-
- // Format heading as white background, black text, bold
- // ANSI codes: \x1b[1m for bold, \x1b[47m for white background, \x1b[30m for black text
- let formatted_heading = format!("\x1b[1m\x1b[47m\x1b[30m {processed_content} \x1b[0m");
-
- // Add indentation to the heading line itself
- // Heading indentation = level - 1
- let heading_indent = if effective_level > 0 {
- effective_level - 1
- } else {
- 0
- };
- let indent = " ".repeat(heading_indent);
- line_result.push_str(&indent);
- line_result.push_str(&formatted_heading);
-
- // Update content indent level for subsequent content
- // Content after heading should be indented by effective_level
- content_indent = effective_level;
- } else if !trimmed_line.is_empty() {
- // Process regular line with existing formatting
- let processed_line = process_line_with_quote(trimmed_line);
-
- // Add indentation based on content_indent
- let indent = " ".repeat(content_indent);
- line_result.push_str(&indent);
- line_result.push_str(&processed_line);
- } else {
- line_result.push(' ');
- }
-
- if !line_result.is_empty() {
- result.push_str(&line_result);
- result.push('\n');
- }
- }
-
- // Remove trailing newline
- if result.ends_with('\n') {
- result.pop();
- }
-
- result
-}
-
-// Helper function to process a single line with existing formatting and handle > quotes
-fn process_line_with_quote(line: &str) -> String {
- let chars: Vec<char> = line.chars().collect();
-
- // Check if line starts with '>' and not escaped
- if !chars.is_empty() && chars[0] == '>' {
- // Check if it's escaped
- if chars.len() > 1 && chars[1] == '\\' {
- // It's \>, so treat as normal text starting from position 0
- return process_line(line);
- }
-
- // It's a regular > at the beginning, replace with gray background gray text space
- let gray_bg_space = "\x1b[48;5;242m\x1b[38;5;242m \x1b[0m";
- let rest_of_line = if chars.len() > 1 {
- chars[1..].iter().collect::<String>()
- } else {
- String::new()
- };
-
- // Process the rest of the line normally
- let processed_rest = process_line(&rest_of_line);
-
- // Combine the gray background space with the processed rest
- format!("{gray_bg_space}{processed_rest}")
- } else {
- // No > at the beginning, process normally
- process_line(line)
- }
-}
-
-// Helper function to process a single line with existing formatting
-fn process_line(line: &str) -> String {
- let mut result = String::new();
- let mut color_stack: VecDeque<String> = VecDeque::new();
-
- let chars: Vec<char> = line.chars().collect();
- let mut i = 0;
-
- while i < chars.len() {
- // Check for escape character \
- if chars[i] == '\\' && i + 1 < chars.len() {
- let escaped_char = chars[i + 1];
- // Only escape specific characters
- if matches!(escaped_char, '*' | '<' | '>' | '`' | '_') {
- let mut escaped_text = escaped_char.to_string();
- apply_color_stack(&mut escaped_text, &color_stack);
- result.push_str(&escaped_text);
- i += 2;
- continue;
- }
- }
-
- // Check for color tag start [[color]]
- if i + 1 < chars.len()
- && chars[i] == '['
- && chars[i + 1] == '['
- && let Some(end) = find_tag_end(&chars, i)
- {
- let tag_content: String = chars[i + 2..end].iter().collect();
-
- // Check if it's a closing tag [[/]]
- if tag_content == "/" {
- color_stack.pop_back();
- } else {
- // It's a color tag
- color_stack.push_back(tag_content.clone());
- }
- i = end + 2;
- continue;
- }
-
- // Check for bold **text**
- if i + 1 < chars.len()
- && chars[i] == '*'
- && chars[i + 1] == '*'
- && let Some(end) = find_matching(&chars, i + 2, "**")
- {
- let bold_text: String = chars[i + 2..end].iter().collect();
- let mut formatted_text = bold_text.bold().to_string();
- apply_color_stack(&mut formatted_text, &color_stack);
- result.push_str(&formatted_text);
- i = end + 2;
- continue;
- }
-
- // Check for italic *text*
- if chars[i] == '*'
- && let Some(end) = find_matching(&chars, i + 1, "*")
- {
- let italic_text: String = chars[i + 1..end].iter().collect();
- let mut formatted_text = italic_text.italic().to_string();
- apply_color_stack(&mut formatted_text, &color_stack);
- result.push_str(&formatted_text);
- i = end + 1;
- continue;
- }
-
- // Check for underline _text_
- if chars[i] == '_'
- && let Some(end) = find_matching(&chars, i + 1, "_")
- {
- let underline_text: String = chars[i + 1..end].iter().collect();
- let mut formatted_text = format!("\x1b[4m{underline_text}\x1b[0m");
- apply_color_stack(&mut formatted_text, &color_stack);
- result.push_str(&formatted_text);
- i = end + 1;
- continue;
- }
-
- // Check for angle-bracketed content <text>
- if chars[i] == '<'
- && let Some(end) = find_matching(&chars, i + 1, ">")
- {
- // Include the angle brackets in the output
- let angle_text: String = chars[i..=end].iter().collect();
- let mut formatted_text = angle_text.cyan().to_string();
- apply_color_stack(&mut formatted_text, &color_stack);
- result.push_str(&formatted_text);
- i = end + 1;
- continue;
- }
-
- // Check for inline code `text`
- if chars[i] == '`'
- && let Some(end) = find_matching(&chars, i + 1, "`")
- {
- // Include the backticks in the output
- let code_text: String = chars[i..=end].iter().collect();
- let mut formatted_text = code_text.green().to_string();
- apply_color_stack(&mut formatted_text, &color_stack);
- result.push_str(&formatted_text);
- i = end + 1;
- continue;
- }
-
- // Regular character
- let mut current_char = chars[i].to_string();
- apply_color_stack(&mut current_char, &color_stack);
- result.push_str(&current_char);
- i += 1;
- }
-
- result
-}
-
-// Helper function to find matching delimiter
-fn find_matching(chars: &[char], start: usize, delimiter: &str) -> Option<usize> {
- let delim_chars: Vec<char> = delimiter.chars().collect();
- let delim_len = delim_chars.len();
-
- let mut j = start;
- while j < chars.len() {
- if delim_len == 1 {
- if chars[j] == delim_chars[0] {
- return Some(j);
- }
- } else if j + 1 < chars.len()
- && chars[j] == delim_chars[0]
- && chars[j + 1] == delim_chars[1]
- {
- return Some(j);
- }
- j += 1;
- }
- None
-}
-
-// Helper function to find color tag end
-fn find_tag_end(chars: &[char], start: usize) -> Option<usize> {
- let mut j = start + 2;
- while j + 1 < chars.len() {
- if chars[j] == ']' && chars[j + 1] == ']' {
- return Some(j);
- }
- j += 1;
- }
- None
-}
-
-// Helper function to apply color stack to text
-fn apply_color_stack(text: &mut String, color_stack: &VecDeque<String>) {
- let mut result = text.clone();
- for color in color_stack.iter().rev() {
- result = apply_color(&result, color);
- }
- *text = result;
-}
-
-// Helper function to apply color to text
-fn apply_color(text: impl AsRef<str>, color_name: impl AsRef<str>) -> String {
- let text = text.as_ref();
- let color_name = color_name.as_ref();
- match color_name {
- // Normal colors
- "black" => text.black().to_string(),
- "red" => text.red().to_string(),
- "green" => text.green().to_string(),
- "yellow" => text.yellow().to_string(),
- "blue" => text.blue().to_string(),
- "magenta" => text.magenta().to_string(),
- "cyan" => text.cyan().to_string(),
- "white" | "b_white" | "bright_gray" | "bright_grey" | "b_gray" | "b_grey" => {
- text.white().to_string()
- }
-
- // Bright colors and their b_ short aliases
- "bright_black" | "b_black" | "gray" | "grey" => text.bright_black().to_string(),
- "bright_red" | "b_red" => text.bright_red().to_string(),
- "bright_green" | "b_green" => text.bright_green().to_string(),
- "bright_yellow" | "b_yellow" => text.bright_yellow().to_string(),
- "bright_blue" | "b_blue" => text.bright_blue().to_string(),
- "bright_magenta" | "b_magenta" => text.bright_magenta().to_string(),
- "bright_cyan" | "b_cyan" => text.bright_cyan().to_string(),
- "bright_white" => text.bright_white().to_string(),
-
- // Default to white if color not recognized
- _ => text.to_string(),
- }
-}
diff --git a/mling/src/errors.rs b/mling/src/errors.rs
deleted file mode 100644
index ece80ce..0000000
--- a/mling/src/errors.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-mod io_error;
-pub use io_error::*;
diff --git a/mling/src/errors/io_error.rs b/mling/src/errors/io_error.rs
deleted file mode 100644
index ac503cc..0000000
--- a/mling/src/errors/io_error.rs
+++ /dev/null
@@ -1,224 +0,0 @@
-use mingling::{
- RenderResult,
- macros::{group, renderer},
- res::ResExitCode,
-};
-use std::io::Write as _;
-
-use crate::eformat_cargo;
-
-group!(ErrorIo = std::io::Error);
-
-// Error code constants for each std::io::ErrorKind variant
-pub const EC_IO_ERR_NOT_FOUND: i32 = 1000;
-pub const EC_IO_ERR_PERMISSION_DENIED: i32 = 1001;
-pub const EC_IO_ERR_CONNECTION_REFUSED: i32 = 1002;
-pub const EC_IO_ERR_CONNECTION_RESET: i32 = 1003;
-pub const EC_IO_ERR_HOST_UNREACHABLE: i32 = 1004;
-pub const EC_IO_ERR_NETWORK_UNREACHABLE: i32 = 1005;
-pub const EC_IO_ERR_CONNECTION_ABORTED: i32 = 1006;
-pub const EC_IO_ERR_NOT_CONNECTED: i32 = 1007;
-pub const EC_IO_ERR_ADDR_IN_USE: i32 = 1008;
-pub const EC_IO_ERR_ADDR_NOT_AVAILABLE: i32 = 1009;
-pub const EC_IO_ERR_NETWORK_DOWN: i32 = 1010;
-pub const EC_IO_ERR_BROKEN_PIPE: i32 = 1011;
-pub const EC_IO_ERR_ALREADY_EXISTS: i32 = 1012;
-pub const EC_IO_ERR_WOULD_BLOCK: i32 = 1013;
-pub const EC_IO_ERR_NOT_A_DIRECTORY: i32 = 1014;
-pub const EC_IO_ERR_IS_A_DIRECTORY: i32 = 1015;
-pub const EC_IO_ERR_DIRECTORY_NOT_EMPTY: i32 = 1016;
-pub const EC_IO_ERR_READ_ONLY_FILESYSTEM: i32 = 1017;
-pub const EC_IO_ERR_STALE_NETWORK_FILE_HANDLE: i32 = 1018;
-pub const EC_IO_ERR_INVALID_INPUT: i32 = 1019;
-pub const EC_IO_ERR_INVALID_DATA: i32 = 1020;
-pub const EC_IO_ERR_TIMED_OUT: i32 = 1021;
-pub const EC_IO_ERR_WRITE_ZERO: i32 = 1022;
-pub const EC_IO_ERR_STORAGE_FULL: i32 = 1023;
-pub const EC_IO_ERR_NOT_SEEKABLE: i32 = 1024;
-pub const EC_IO_ERR_QUOTA_EXCEEDED: i32 = 1025;
-pub const EC_IO_ERR_FILE_TOO_LARGE: i32 = 1026;
-pub const EC_IO_ERR_RESOURCE_BUSY: i32 = 1027;
-pub const EC_IO_ERR_EXECUTABLE_FILE_BUSY: i32 = 1028;
-pub const EC_IO_ERR_DEADLOCK: i32 = 1029;
-pub const EC_IO_ERR_CROSSES_DEVICES: i32 = 1030;
-pub const EC_IO_ERR_TOO_MANY_LINKS: i32 = 1031;
-pub const EC_IO_ERR_INVALID_FILENAME: i32 = 1032;
-pub const EC_IO_ERR_ARGUMENT_LIST_TOO_LONG: i32 = 1033;
-pub const EC_IO_ERR_INTERRUPTED: i32 = 1034;
-pub const EC_IO_ERR_UNSUPPORTED: i32 = 1035;
-pub const EC_IO_ERR_UNEXPECTED_EOF: i32 = 1036;
-pub const EC_IO_ERR_OUT_OF_MEMORY: i32 = 1037;
-pub const EC_IO_ERR_OTHER: i32 = 1038;
-
-#[renderer]
-pub fn render_error_io(err: ErrorIo, ec: &mut ResExitCode) -> RenderResult {
- let mut result = RenderResult::default();
- match err.kind() {
- std::io::ErrorKind::NotFound => {
- writeln!(result, "{}", eformat_cargo!("file or directory not found")).ok();
- ec.exit_code = EC_IO_ERR_NOT_FOUND;
- }
- std::io::ErrorKind::PermissionDenied => {
- writeln!(result, "{}", eformat_cargo!("permission denied")).ok();
- ec.exit_code = EC_IO_ERR_PERMISSION_DENIED;
- }
- std::io::ErrorKind::ConnectionRefused => {
- writeln!(result, "{}", eformat_cargo!("connection refused")).ok();
- ec.exit_code = EC_IO_ERR_CONNECTION_REFUSED;
- }
- std::io::ErrorKind::ConnectionReset => {
- writeln!(result, "{}", eformat_cargo!("connection reset")).ok();
- ec.exit_code = EC_IO_ERR_CONNECTION_RESET;
- }
- std::io::ErrorKind::HostUnreachable => {
- writeln!(result, "{}", eformat_cargo!("host unreachable")).ok();
- ec.exit_code = EC_IO_ERR_HOST_UNREACHABLE;
- }
- std::io::ErrorKind::NetworkUnreachable => {
- writeln!(result, "{}", eformat_cargo!("network unreachable")).ok();
- ec.exit_code = EC_IO_ERR_NETWORK_UNREACHABLE;
- }
- std::io::ErrorKind::ConnectionAborted => {
- writeln!(result, "{}", eformat_cargo!("connection aborted")).ok();
- ec.exit_code = EC_IO_ERR_CONNECTION_ABORTED;
- }
- std::io::ErrorKind::NotConnected => {
- writeln!(result, "{}", eformat_cargo!("not connected")).ok();
- ec.exit_code = EC_IO_ERR_NOT_CONNECTED;
- }
- std::io::ErrorKind::AddrInUse => {
- writeln!(result, "{}", eformat_cargo!("address in use")).ok();
- ec.exit_code = EC_IO_ERR_ADDR_IN_USE;
- }
- std::io::ErrorKind::AddrNotAvailable => {
- writeln!(result, "{}", eformat_cargo!("address not available")).ok();
- ec.exit_code = EC_IO_ERR_ADDR_NOT_AVAILABLE;
- }
- std::io::ErrorKind::NetworkDown => {
- writeln!(result, "{}", eformat_cargo!("network down")).ok();
- ec.exit_code = EC_IO_ERR_NETWORK_DOWN;
- }
- std::io::ErrorKind::BrokenPipe => {
- writeln!(result, "{}", eformat_cargo!("broken pipe")).ok();
- ec.exit_code = EC_IO_ERR_BROKEN_PIPE;
- }
- std::io::ErrorKind::AlreadyExists => {
- writeln!(
- result,
- "{}",
- eformat_cargo!("file or directory already exists")
- )
- .ok();
- ec.exit_code = EC_IO_ERR_ALREADY_EXISTS;
- }
- std::io::ErrorKind::WouldBlock => {
- writeln!(result, "{}", eformat_cargo!("operation would block")).ok();
- ec.exit_code = EC_IO_ERR_WOULD_BLOCK;
- }
- std::io::ErrorKind::NotADirectory => {
- writeln!(result, "{}", eformat_cargo!("not a directory")).ok();
- ec.exit_code = EC_IO_ERR_NOT_A_DIRECTORY;
- }
- std::io::ErrorKind::IsADirectory => {
- writeln!(result, "{}", eformat_cargo!("is a directory")).ok();
- ec.exit_code = EC_IO_ERR_IS_A_DIRECTORY;
- }
- std::io::ErrorKind::DirectoryNotEmpty => {
- writeln!(result, "{}", eformat_cargo!("directory not empty")).ok();
- ec.exit_code = EC_IO_ERR_DIRECTORY_NOT_EMPTY;
- }
- std::io::ErrorKind::ReadOnlyFilesystem => {
- writeln!(result, "{}", eformat_cargo!("read-only filesystem")).ok();
- ec.exit_code = EC_IO_ERR_READ_ONLY_FILESYSTEM;
- }
- std::io::ErrorKind::StaleNetworkFileHandle => {
- writeln!(result, "{}", eformat_cargo!("stale network file handle")).ok();
- ec.exit_code = EC_IO_ERR_STALE_NETWORK_FILE_HANDLE;
- }
- std::io::ErrorKind::InvalidInput => {
- writeln!(result, "{}", eformat_cargo!("invalid input")).ok();
- ec.exit_code = EC_IO_ERR_INVALID_INPUT;
- }
- std::io::ErrorKind::InvalidData => {
- writeln!(result, "{}", eformat_cargo!("invalid data")).ok();
- ec.exit_code = EC_IO_ERR_INVALID_DATA;
- }
- std::io::ErrorKind::TimedOut => {
- writeln!(result, "{}", eformat_cargo!("timed out")).ok();
- ec.exit_code = EC_IO_ERR_TIMED_OUT;
- }
- std::io::ErrorKind::WriteZero => {
- writeln!(result, "{}", eformat_cargo!("write zero")).ok();
- ec.exit_code = EC_IO_ERR_WRITE_ZERO;
- }
- std::io::ErrorKind::StorageFull => {
- writeln!(result, "{}", eformat_cargo!("storage full")).ok();
- ec.exit_code = EC_IO_ERR_STORAGE_FULL;
- }
- std::io::ErrorKind::NotSeekable => {
- writeln!(result, "{}", eformat_cargo!("not seekable")).ok();
- ec.exit_code = EC_IO_ERR_NOT_SEEKABLE;
- }
- std::io::ErrorKind::QuotaExceeded => {
- writeln!(result, "{}", eformat_cargo!("quota exceeded")).ok();
- ec.exit_code = EC_IO_ERR_QUOTA_EXCEEDED;
- }
- std::io::ErrorKind::FileTooLarge => {
- writeln!(result, "{}", eformat_cargo!("file too large")).ok();
- ec.exit_code = EC_IO_ERR_FILE_TOO_LARGE;
- }
- std::io::ErrorKind::ResourceBusy => {
- writeln!(result, "{}", eformat_cargo!("resource busy")).ok();
- ec.exit_code = EC_IO_ERR_RESOURCE_BUSY;
- }
- std::io::ErrorKind::ExecutableFileBusy => {
- writeln!(result, "{}", eformat_cargo!("executable file busy")).ok();
- ec.exit_code = EC_IO_ERR_EXECUTABLE_FILE_BUSY;
- }
- std::io::ErrorKind::Deadlock => {
- writeln!(result, "{}", eformat_cargo!("deadlock")).ok();
- ec.exit_code = EC_IO_ERR_DEADLOCK;
- }
- std::io::ErrorKind::CrossesDevices => {
- writeln!(result, "{}", eformat_cargo!("crosses devices")).ok();
- ec.exit_code = EC_IO_ERR_CROSSES_DEVICES;
- }
- std::io::ErrorKind::TooManyLinks => {
- writeln!(result, "{}", eformat_cargo!("too many links")).ok();
- ec.exit_code = EC_IO_ERR_TOO_MANY_LINKS;
- }
- std::io::ErrorKind::InvalidFilename => {
- writeln!(result, "{}", eformat_cargo!("invalid filename")).ok();
- ec.exit_code = EC_IO_ERR_INVALID_FILENAME;
- }
- std::io::ErrorKind::ArgumentListTooLong => {
- writeln!(result, "{}", eformat_cargo!("argument list too long")).ok();
- ec.exit_code = EC_IO_ERR_ARGUMENT_LIST_TOO_LONG;
- }
- std::io::ErrorKind::Interrupted => {
- writeln!(result, "{}", eformat_cargo!("interrupted")).ok();
- ec.exit_code = EC_IO_ERR_INTERRUPTED;
- }
- std::io::ErrorKind::Unsupported => {
- writeln!(result, "{}", eformat_cargo!("unsupported")).ok();
- ec.exit_code = EC_IO_ERR_UNSUPPORTED;
- }
- std::io::ErrorKind::UnexpectedEof => {
- writeln!(result, "{}", eformat_cargo!("unexpected end of file")).ok();
- ec.exit_code = EC_IO_ERR_UNEXPECTED_EOF;
- }
- std::io::ErrorKind::OutOfMemory => {
- writeln!(result, "{}", eformat_cargo!("out of memory")).ok();
- ec.exit_code = EC_IO_ERR_OUT_OF_MEMORY;
- }
- std::io::ErrorKind::Other => {
- writeln!(result, "{}", eformat_cargo!(err.to_string())).ok();
- ec.exit_code = EC_IO_ERR_OTHER;
- }
- _ => {
- writeln!(result, "{}", eformat_cargo!(err.to_string())).ok();
- ec.exit_code = EC_IO_ERR_OTHER;
- }
- }
- result
-}
diff --git a/mling/src/helps/mling_help.txt b/mling/src/helps/mling_help.txt
deleted file mode 100644
index 73bfd4d..0000000
--- a/mling/src/helps/mling_help.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Mingling's scaffolding tool
-
-[[b_green]]**Usage:**[[/]] [[b_cyan]]**cargo mling**[[/]] [[cyan]][COMMAND] [OPTIONS]...[[/]]
-
-[[b_green]]**Options:**[[/]]
-__ [[b_cyan]]**-V**[[/]], [[b_cyan]]**--version**[[/]] Print version info and exit
-__ [[b_cyan]]**-h**[[/]], [[b_cyan]]**--help**[[/]] Print this help message
-
-__ [[b_cyan]]**-P**[[/]], [[b_cyan]]**--manifest-path**[[/]] [[cyan]]<PATH>[[/]] Path to _Cargo.toml_
-
-__ [[b_cyan]]**--silence**[[/]], [[b_cyan]]**--quiet**[[/]] Suppress all output
-__ [[b_cyan]]**--no-error**[[/]] Suppress error output
-__ [[b_cyan]]**--no-result**[[/]] Suppress result output
-
-[[b_green]]**Commands:**[[/]]
-__ [[b_cyan]]**install**[[/]] Install current project into
-__ the **mling** package manager
-__ [[b_cyan]]**ls**[[/]], [[b_cyan]]**show**[[/]], [[b_cyan]]**add**[[/]], [[b_cyan]]**rm**[[/]] List, show, add, or remove something
-
-Run \`[[b_cyan]]**cargo help mling**[[/]]\` for more detailed information.
diff --git a/mling/src/lib.rs b/mling/src/lib.rs
deleted file mode 100644
index 1de1228..0000000
--- a/mling/src/lib.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-#![allow(unused_imports)]
-
-use mingling::{
- macros::{chain, gen_program, pack, renderer},
- res::ResExitCode,
-};
-
-mod cargo_style;
-pub use cargo_style::*;
-
-pub mod cli;
-pub mod display;
-pub mod errors;
-pub mod pkg_mgr;
-pub mod proj_mgr;
-pub mod res;
-
-gen_program!();
diff --git a/mling/src/pkg_mgr/installer.rs b/mling/src/pkg_mgr/installer.rs
deleted file mode 100644
index 8b13789..0000000
--- a/mling/src/pkg_mgr/installer.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/mling/src/pkg_mgr/mod.rs b/mling/src/pkg_mgr/mod.rs
deleted file mode 100644
index 682b433..0000000
--- a/mling/src/pkg_mgr/mod.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use crate::ThisProgram;
-use mingling::{
- Program,
- macros::{dispatcher, program_setup},
-};
-
-pub mod installer;
-
-dispatcher!("install");
-dispatcher!("ls.namespace", CMDListNamespace => EntryListNamespace);
-dispatcher!("rm.namespace", CMDRemoveNamespace => EntryRemoveNamespace);
-
-#[program_setup]
-pub fn package_manager_setup(p: &mut Program<ThisProgram>) {
- p.with_dispatcher(CMDInstall);
- p.with_dispatcher(CMDListNamespace);
- p.with_dispatcher(CMDRemoveNamespace);
-}
diff --git a/mling/src/proj_mgr/checklist_reader.rs b/mling/src/proj_mgr/checklist_reader.rs
deleted file mode 100644
index 558d303..0000000
--- a/mling/src/proj_mgr/checklist_reader.rs
+++ /dev/null
@@ -1,294 +0,0 @@
-use std::{collections::HashMap, io, path::Path};
-
-/// Reads and parses a `CHECKLIST.md` file, extracting both *values* (from
-/// fenced code blocks) and *toggles* (from checkbox lines).
-///
-/// # Format
-///
-/// - **Values**: fenced code blocks where the info string is the key and
-/// the first non-empty line is the value. Example:
-/// <code>\`\`\`name<br>my-cli<br>\`\`\`</code>
-/// - **Toggles**: checkbox lines like `- [x] \`ns:key\`` (checked) or
-/// `- [ ] \`ns:key\`` (unchecked).
-///
-/// Checked items are stored as `"namespace:key"`.
-///
-/// # Usage
-///
-/// ```rust,ignore
-/// let reader = CheckListReader::from(&Path::new("CHECKLIST.md")).unwrap();
-/// assert_eq!(reader.read_value("name"), Some("my-cli".into()));
-/// assert!(reader.read_toggle("ver:0.2"));
-/// assert!(!reader.read_toggle("feat:comp"));
-/// assert_eq!(reader.read_toggles("feat"), vec!["feat:async"]);
-/// ```
-pub struct CheckListReader {
- /// Values extracted from fenced code blocks: `key → value`.
- values: HashMap<String, String>,
-
- /// Checked toggles: `"namespace:key" → true` (only checked items are stored).
- toggles: HashMap<String, bool>,
-
- /// All toggles (checked or not): `"namespace:key" → checked`.
- all_toggles: HashMap<String, bool>,
-}
-
-impl CheckListReader {
- /// Parse a CHECKLIST.md from a file path in a single left-to-right pass
- pub fn from(path: &Path) -> Result<Self, io::Error> {
- let content = std::fs::read_to_string(path)?;
-
- let mut reader = Self {
- values: HashMap::new(),
- toggles: HashMap::new(),
- all_toggles: HashMap::new(),
- };
- reader.parse(&content);
- Ok(reader)
- }
-
- /// Parse CHECKLIST.md content in a single pass.
- fn parse(&mut self, content: &str) {
- let lines: Vec<&str> = content.lines().collect();
- let mut i = 0;
-
- while i < lines.len() {
- let line = lines[i];
-
- if let Some(key) = line.strip_prefix("```").map(|s| s.trim())
- && !key.is_empty()
- && !key.starts_with(' ')
- {
- let mut block_lines = Vec::new();
- i += 1;
- while i < lines.len() && !lines[i].trim_start().starts_with("```") {
- block_lines.push(lines[i]);
- i += 1;
- }
- let value = block_lines
- .into_iter()
- .find(|l| !l.trim().is_empty())
- .map(|l| l.trim().to_string());
- if let Some(val) = value {
- self.values.insert(key.to_string(), val);
- }
- continue;
- }
-
- if let Some(toggle_key) = Self::parse_toggle_line(line) {
- let is_checked = line.contains("[x]") || line.contains("[X]");
- self.all_toggles.insert(toggle_key.clone(), is_checked);
- if is_checked {
- self.toggles.insert(toggle_key, true);
- }
- }
-
- i += 1;
- }
- }
-
- /// Extract the `namespace:key` from a toggle line.
- ///
- /// Matches: `- [x] `namespace:key`` or `- [ ] `namespace:key``
- fn parse_toggle_line(line: &str) -> Option<String> {
- let line = line.trim();
- if !line.starts_with("- [") {
- return None;
- }
- // Find the backtick-enclosed key
- let start = line.find('`')?;
- let rest = &line[start + 1..];
- let end = rest.find('`')?;
- let key = rest[..end].trim();
- if key.is_empty() {
- return None;
- }
- Some(key.to_string())
- }
-
- /// Read a value by its key.
- ///
- /// Returns `Some(value)` if a fenced code block with that key was found,
- /// or `None` if the key does not exist.
- #[must_use]
- pub fn read_value(&self, key: &str) -> Option<String> {
- self.values.get(key).cloned()
- }
-
- /// Check if a toggle (`namespace:key`) is checked.
- ///
- /// Returns `true` if the checkbox line was `- [x]`, `false` if it was
- /// `- [ ]` or the key does not exist in the file.
- #[must_use]
- pub fn read_toggle(&self, key: &str) -> bool {
- self.toggles.contains_key(key)
- }
-
- /// Get all toggles under a given `namespace` that are checked.
- ///
- /// For example, `read_toggles("feat")` returns all checked keys starting
- /// with `"feat:"`, such as `["feat:comp", "feat:parser"]`.
- #[must_use]
- pub fn read_toggles(&self, namespace: &str) -> Vec<String> {
- let prefix = format!("{namespace}:");
- let mut keys: Vec<String> = self
- .toggles
- .keys()
- .filter(|k| k.starts_with(&prefix))
- .cloned()
- .collect();
- keys.sort();
- keys
- }
-
- /// Get ALL toggles (checked or not) under a namespace.
- ///
- /// Useful for iterating all available options.
- #[must_use]
- pub fn all_toggles(&self, namespace: &str) -> Vec<String> {
- let prefix = format!("{namespace}:");
- let mut keys: Vec<String> = self
- .all_toggles
- .keys()
- .filter(|k| k.starts_with(&prefix))
- .cloned()
- .collect();
- keys.sort();
- keys
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- fn sample_md() -> &'static str {
- r#"> Some intro
-
-## Question 1: What is your project name?
-
-```name
-my-cli
-```
-
-## Question 2: Which version?
-
-- [x] `ver:0.2`
-
-## Question 3: Features?
-
-- [ ] `feat:structural_renderer`
-- [x] `feat:comp`
-- [x] `feat:parser`
-- [ ] `feat:async`
-
-```other
-some value
-```
-"#
- }
-
- #[test]
- fn test_read_value() {
- let mut reader = CheckListReader {
- values: HashMap::new(),
- toggles: HashMap::new(),
- all_toggles: HashMap::new(),
- };
- reader.parse(sample_md());
- assert_eq!(reader.read_value("name"), Some("my-cli".into()));
- assert_eq!(reader.read_value("other"), Some("some value".into()));
- assert_eq!(reader.read_value("nonexistent"), None);
- }
-
- #[test]
- fn test_read_toggle() {
- let mut reader = CheckListReader {
- values: HashMap::new(),
- toggles: HashMap::new(),
- all_toggles: HashMap::new(),
- };
- reader.parse(sample_md());
- assert!(reader.read_toggle("ver:0.2"));
- assert!(reader.read_toggle("feat:comp"));
- assert!(reader.read_toggle("feat:parser"));
- assert!(!reader.read_toggle("feat:structural_renderer"));
- assert!(!reader.read_toggle("feat:async"));
- assert!(!reader.read_toggle("nonexistent:key"));
- }
-
- #[test]
- fn test_read_toggles() {
- let mut reader = CheckListReader {
- values: HashMap::new(),
- toggles: HashMap::new(),
- all_toggles: HashMap::new(),
- };
- reader.parse(sample_md());
- let feat_toggles = reader.read_toggles("feat");
- assert_eq!(feat_toggles, vec!["feat:comp", "feat:parser"]);
- }
-
- #[test]
- fn test_all_toggles() {
- let mut reader = CheckListReader {
- values: HashMap::new(),
- toggles: HashMap::new(),
- all_toggles: HashMap::new(),
- };
- reader.parse(sample_md());
- let all = reader.all_toggles("feat");
- assert_eq!(
- all,
- vec![
- "feat:async",
- "feat:comp",
- "feat:parser",
- "feat:structural_renderer",
- ]
- );
- }
-
- #[test]
- fn test_from_path() {
- // Write a temp CHECKLIST.md, read it, then clean up
- let dir = std::env::temp_dir().join("mling_checklist_test");
- std::fs::create_dir_all(&dir).unwrap();
- let path = dir.join("CHECKLIST.md");
- std::fs::write(&path, sample_md()).unwrap();
-
- let reader = CheckListReader::from(&path).unwrap();
- assert_eq!(reader.read_value("name"), Some("my-cli".into()));
- assert!(reader.read_toggle("ver:0.2"));
-
- let _ = std::fs::remove_dir_all(&dir);
- }
-
- #[test]
- fn test_empty_file() {
- let mut reader = CheckListReader {
- values: HashMap::new(),
- toggles: HashMap::new(),
- all_toggles: HashMap::new(),
- };
- reader.parse("");
- assert_eq!(reader.read_value("anything"), None);
- assert!(!reader.read_toggle("ns:key"));
- assert!(reader.read_toggles("ns").is_empty());
- }
-
- #[test]
- fn test_no_toggle_or_value_lines() {
- let md = "# Just a heading\n\nSome text\n\n```code\nstill not a value\n```\n";
- let mut reader = CheckListReader {
- values: HashMap::new(),
- toggles: HashMap::new(),
- all_toggles: HashMap::new(),
- };
- reader.parse(md);
- // "code" isn't a valid value key (it's used as a language tag, not a name/value key)
- // but our parser treats ANY ```key as a value block. This is correct behavior —
- // malformed CHECKLIST.md may produce unexpected values.
- assert_eq!(reader.read_value("code"), Some("still not a value".into()));
- }
-}
diff --git a/mling/src/proj_mgr/generator.rs b/mling/src/proj_mgr/generator.rs
deleted file mode 100644
index f1a6345..0000000
--- a/mling/src/proj_mgr/generator.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use std::path::{self, PathBuf};
-
-use mingling::{
- RenderResult, Routable,
- macros::{chain, pack, renderer, route},
-};
-use std::io::Write as _;
-
-use crate::{Next, proj_mgr::EntryGenerateProject, res::ResCurrentDir};
-
-pack!(StateGenerateProjectReady = PathBuf);
-pack!(ResultGenerateProjectChecklistCreated = PathBuf);
-
-pack!(StateGenerateProjectExecBegin = PathBuf);
-pack!(StateGenerateProjectExecuting = ());
-
-const CHECK_LIST_NAME: &str = "CHECKLIST.md";
-const CHECK_LIST_CONTENT: &str = include_str!("../../res/CHECKLIST.md");
-
-#[chain]
-pub fn handle_generate(_args: EntryGenerateProject, cwd: &ResCurrentDir) -> Next {
- let checklist_path = cwd.path.join(CHECK_LIST_NAME);
-
- if !checklist_path.exists() {
- StateGenerateProjectReady::new(checklist_path).to_chain()
- } else {
- StateGenerateProjectExecBegin::new(checklist_path).to_chain()
- }
-}
-
-#[chain]
-pub fn handle_state_gen_proj_ready(prev: StateGenerateProjectReady) -> Next {
- let path = prev.inner;
- route!(std::fs::write(&path, CHECK_LIST_CONTENT));
- ResultGenerateProjectChecklistCreated::new(path).to_render()
-}
-
-#[renderer]
-pub fn render_gen_proj_checklist_created(
- result: ResultGenerateProjectChecklistCreated,
-) -> RenderResult {
- let mut res = RenderResult::default();
- writeln!(
- res,
- "Successfully create {} at \"{}\"",
- CHECK_LIST_NAME,
- result.to_string_lossy()
- )
- .ok();
- writeln!(res).ok();
- writeln!(
- res,
- "Please fill in {CHECK_LIST_NAME} and run `mling gen` again to continue generating"
- )
- .ok();
- res
-}
diff --git a/mling/src/proj_mgr/metadata.rs b/mling/src/proj_mgr/metadata.rs
deleted file mode 100644
index 1ba24e1..0000000
--- a/mling/src/proj_mgr/metadata.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-use serde::Deserialize;
-use serde::Serialize;
-
-use std::path::PathBuf;
-use std::process::Command;
-
-/// Read cargo metadata by running `cargo metadata` with the given manifest path.
-pub fn read_metadata(cargo_toml: &PathBuf) -> Result<CargoLockFile, std::io::Error> {
- let output = Command::new("cargo")
- .arg("metadata")
- .arg("--format-version")
- .arg("1")
- .arg("--manifest-path")
- .arg(cargo_toml)
- .output()?;
-
- if !output.status.success() {
- let stderr = String::from_utf8_lossy(&output.stderr);
- return Err(std::io::Error::other(format!(
- "cargo metadata failed: {}",
- stderr
- )));
- }
-
- let lock_file: CargoLockFile = serde_json::from_slice(&output.stdout)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
-
- Ok(lock_file)
-}
-
-/// A cargo metadata lock file that serde can serialize and deserialize.
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct CargoLockFile {
- pub packages: Vec<Package>,
- #[serde(rename = "workspace_members")]
- pub workspace_members: Vec<String>,
- #[serde(rename = "workspace_default_members")]
- pub workspace_default_members: Vec<String>,
- pub resolve: Resolve,
- #[serde(rename = "target_directory")]
- pub target_directory: String,
- #[serde(rename = "build_directory")]
- pub build_directory: String,
- pub version: u64,
- #[serde(rename = "workspace_root")]
- pub workspace_root: String,
- pub metadata: Option<serde_json::Value>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Package {
- pub name: String,
- pub version: String,
- pub id: String,
- pub license: Option<String>,
- #[serde(rename = "license_file")]
- pub license_file: Option<String>,
- pub description: Option<String>,
- pub source: Option<String>,
- pub dependencies: Vec<Dependency>,
- pub targets: Vec<Target>,
- pub features: std::collections::BTreeMap<String, Vec<String>>,
- #[serde(rename = "manifest_path")]
- pub manifest_path: String,
- pub metadata: Option<serde_json::Value>,
- pub publish: Option<serde_json::Value>,
- pub authors: Vec<String>,
- pub categories: Vec<String>,
- pub keywords: Vec<String>,
- pub readme: Option<String>,
- pub repository: Option<String>,
- pub homepage: Option<String>,
- pub documentation: Option<String>,
- pub edition: String,
- pub links: Option<String>,
- #[serde(rename = "default_run")]
- pub default_run: Option<String>,
- #[serde(rename = "rust_version")]
- pub rust_version: Option<String>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Dependency {
- pub name: String,
- pub source: Option<String>,
- pub req: String,
- pub kind: Option<String>,
- pub rename: Option<String>,
- pub optional: bool,
- #[serde(rename = "uses_default_features")]
- pub uses_default_features: bool,
- pub features: Vec<String>,
- pub target: Option<String>,
- pub registry: Option<String>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub path: Option<String>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Target {
- pub kind: Vec<String>,
- #[serde(rename = "crate_types")]
- pub crate_types: Vec<String>,
- pub name: String,
- #[serde(rename = "src_path")]
- pub src_path: String,
- pub edition: String,
- pub doc: bool,
- pub doctest: bool,
- pub test: bool,
- #[serde(skip_serializing_if = "Option::is_none")]
- #[serde(rename = "required-features")]
- pub required_features: Option<Vec<String>>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Resolve {
- pub nodes: Vec<ResolveNode>,
- pub root: Option<String>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ResolveNode {
- pub id: String,
- pub dependencies: Vec<String>,
- pub deps: Vec<DepInfo>,
- pub features: Vec<String>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct DepInfo {
- pub name: String,
- pub pkg: String,
- #[serde(rename = "dep_kinds")]
- pub dep_kinds: Vec<DepKind>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct DepKind {
- pub kind: Option<String>,
- pub target: Option<String>,
-}
diff --git a/mling/src/proj_mgr/mod.rs b/mling/src/proj_mgr/mod.rs
deleted file mode 100644
index e0a4216..0000000
--- a/mling/src/proj_mgr/mod.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-use crate::ThisProgram;
-use mingling::{
- Program,
- macros::{dispatcher, program_setup},
-};
-
-pub mod checklist_reader;
-pub mod generator;
-pub mod metadata;
-pub mod show_binaries;
-pub mod show_directories;
-
-dispatcher!("gen", CMDGenerateProject => EntryGenerateProject);
-
-dispatcher!("show.binaries");
-dispatcher!("show.workspace-dir",
- CMDShowWorkspaceDirectory => EntryShowWorkspaceDirectory
-);
-dispatcher!("show.target-dir",
- CMDShowTargetDirectories => EntryShowTargetDirectories
-);
-
-#[program_setup]
-pub fn project_manager_setup(p: &mut Program<ThisProgram>) {
- p.with_dispatcher(CMDGenerateProject);
-
- p.with_dispatcher(CMDShowBinaries);
- p.with_dispatcher(CMDShowWorkspaceDirectory);
- p.with_dispatcher(CMDShowTargetDirectories);
-}
diff --git a/mling/src/proj_mgr/show_binaries.rs b/mling/src/proj_mgr/show_binaries.rs
deleted file mode 100644
index b08c1c3..0000000
--- a/mling/src/proj_mgr/show_binaries.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use std::path::PathBuf;
-
-use colored::Colorize;
-use mingling::{
- Grouped, RenderResult, Routable,
- macros::{chain, pack, renderer},
-};
-use serde::Serialize;
-use std::io::Write as _;
-
-use crate::{
- Next,
- proj_mgr::{
- EntryShowBinaries,
- metadata::{CargoLockFile, read_metadata},
- },
- res::ResManifestPath,
-};
-
-#[derive(Serialize, Grouped)]
-pub struct ResultBinaries {
- pub binaries: Vec<DataBinary>,
-}
-
-#[derive(Serialize)]
-pub struct DataBinary {
- pub name: String,
- pub path: PathBuf,
-}
-
-#[chain]
-pub fn handle_show_binaries(_args: EntryShowBinaries, manifest_path: &ResManifestPath) -> Next {
- let metadata = read_metadata(manifest_path.resolved()).unwrap();
- let CargoLockFile {
- packages,
- workspace_members,
- ..
- } = metadata;
-
- let binaries: Vec<DataBinary> = packages
- .into_iter()
- .filter(|pkg| workspace_members.contains(&pkg.id))
- .flat_map(|pkg| {
- pkg.targets
- .into_iter()
- .filter(|target| target.kind.iter().any(|k| k == "bin"))
- .map(move |target| DataBinary {
- name: target.name,
- path: PathBuf::from(pkg.manifest_path.clone())
- .parent()
- .unwrap_or(&PathBuf::from("."))
- .join("src")
- .join(&target.src_path),
- })
- })
- .collect();
-
- ResultBinaries { binaries }.to_render()
-}
-
-#[renderer]
-pub fn render_binaries(binaries: ResultBinaries) -> RenderResult {
- let mut result = RenderResult::default();
- writeln!(result, "{}", "Binaries:".bright_cyan().bold()).ok();
- if let Some(max_name_len) = binaries.binaries.iter().map(|b| b.name.len()).max() {
- for binary in &binaries.binaries {
- writeln!(
- result,
- " {:width$} `{}`",
- binary.name.bright_yellow().bold(),
- binary.path.display().to_string().italic(),
- width = max_name_len
- )
- .ok();
- }
- }
- result
-}
diff --git a/mling/src/proj_mgr/show_directories.rs b/mling/src/proj_mgr/show_directories.rs
deleted file mode 100644
index d3c0115..0000000
--- a/mling/src/proj_mgr/show_directories.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use colored::Colorize;
-use mingling::{
- Grouped, RenderResult, Routable,
- macros::{chain, pack, renderer},
-};
-use serde::Serialize;
-use std::io::Write as _;
-
-use crate::{
- Next,
- proj_mgr::{EntryShowTargetDirectories, EntryShowWorkspaceDirectory, metadata::read_metadata},
- res::ResManifestPath,
-};
-
-#[derive(Serialize, Grouped)]
-pub struct ResultWorkspaceDirectory {
- pub path: String,
-}
-
-#[derive(Serialize, Grouped)]
-pub struct ResultTargetDirectory {
- pub path: String,
-}
-
-#[chain]
-pub fn handle_show_workspace_directory(
- _args: EntryShowWorkspaceDirectory,
- manifest_path: &ResManifestPath,
-) -> Next {
- let metadata = read_metadata(manifest_path.resolved()).unwrap();
- ResultWorkspaceDirectory {
- path: metadata.workspace_root,
- }
- .to_render()
-}
-
-#[chain]
-pub fn handle_show_target_directory(
- _args: EntryShowTargetDirectories,
- manifest_path: &ResManifestPath,
-) -> Next {
- let metadata = read_metadata(manifest_path.resolved()).unwrap();
- ResultTargetDirectory {
- path: metadata.target_directory,
- }
- .to_render()
-}
-
-#[renderer]
-pub fn render_workspace_directory(prev: ResultWorkspaceDirectory) -> RenderResult {
- let mut result = RenderResult::default();
- writeln!(result, "{}", prev.path.bright_cyan().bold()).ok();
- result
-}
-
-#[renderer]
-pub fn render_target_directory(prev: ResultTargetDirectory) -> RenderResult {
- let mut result = RenderResult::default();
- writeln!(result, "{}", prev.path.bright_cyan().bold()).ok();
- result
-}
diff --git a/mling/src/res/current_dir.rs b/mling/src/res/current_dir.rs
deleted file mode 100644
index b928596..0000000
--- a/mling/src/res/current_dir.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use std::path::PathBuf;
-
-#[derive(Default, Clone)]
-pub struct ResCurrentDir {
- pub path: PathBuf,
-}
diff --git a/mling/src/res/manifest_path.rs b/mling/src/res/manifest_path.rs
deleted file mode 100644
index 7f1686e..0000000
--- a/mling/src/res/manifest_path.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use std::path::PathBuf;
-
-#[derive(Default, Clone)]
-pub struct ResManifestPath {
- pub raw: Option<String>,
- pub resolved: Option<PathBuf>,
-}
-
-impl ResManifestPath {
- pub fn resolved(&self) -> &PathBuf {
- self.resolved.as_ref().unwrap()
- }
-}
diff --git a/mling/src/res/mod.rs b/mling/src/res/mod.rs
deleted file mode 100644
index caa843c..0000000
--- a/mling/src/res/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-mod current_dir;
-pub use current_dir::*;
-
-mod manifest_path;
-pub use manifest_path::*;