aboutsummaryrefslogtreecommitdiff
path: root/mling
diff options
context:
space:
mode:
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.rs195
-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, 1997 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 67d2ef0..0000000
--- a/mling/src/cli.rs
+++ /dev/null
@@ -1,195 +0,0 @@
-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::{
- Groupped, Program, RenderResult,
- 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 4f965d9..0000000
--- a/mling/src/proj_mgr/generator.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use std::path::{self, PathBuf};
-
-use mingling::{
- Groupped, RenderResult,
- 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 9d5caf0..0000000
--- a/mling/src/proj_mgr/show_binaries.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use std::path::PathBuf;
-
-use colored::Colorize;
-use mingling::{
- Groupped, RenderResult,
- 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, Groupped)]
-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 7d7c074..0000000
--- a/mling/src/proj_mgr/show_directories.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use colored::Colorize;
-use mingling::{
- Groupped, RenderResult,
- 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, Groupped)]
-pub struct ResultWorkspaceDirectory {
- pub path: String,
-}
-
-#[derive(Serialize, Groupped)]
-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::*;