diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-26 07:44:31 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-26 07:44:31 +0800 |
| commit | a73f0f692968a04fb6f99ffbf6a2538cb482815f (patch) | |
| tree | ab9afd18913ca113ff6cc577077eb682b7edc01b /mling/src | |
| parent | 30e8275059fc66ddc996513f60f536732378d6cf (diff) | |
feat(proj_mgr): add project generation with interactive checklist
Diffstat (limited to 'mling/src')
| -rw-r--r-- | mling/src/errors.rs | 2 | ||||
| -rw-r--r-- | mling/src/errors/io_error.rs | 212 | ||||
| -rw-r--r-- | mling/src/lib.rs | 3 | ||||
| -rw-r--r-- | mling/src/proj_mgr/generator.rs | 39 | ||||
| -rw-r--r-- | mling/src/proj_mgr/mod.rs | 7 |
5 files changed, 263 insertions, 0 deletions
diff --git a/mling/src/errors.rs b/mling/src/errors.rs new file mode 100644 index 0000000..ece80ce --- /dev/null +++ b/mling/src/errors.rs @@ -0,0 +1,2 @@ +mod io_error; +pub use io_error::*; diff --git a/mling/src/errors/io_error.rs b/mling/src/errors/io_error.rs new file mode 100644 index 0000000..9f93ad7 --- /dev/null +++ b/mling/src/errors/io_error.rs @@ -0,0 +1,212 @@ +use mingling::{macros::{group, r_println, renderer}, res::ResExitCode}; + +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) { + match err.kind() { + std::io::ErrorKind::NotFound => { + r_println!("{}", eformat_cargo!("file or directory not found")); + ec.exit_code = EC_IO_ERR_NOT_FOUND; + } + std::io::ErrorKind::PermissionDenied => { + r_println!("{}", eformat_cargo!("permission denied")); + ec.exit_code = EC_IO_ERR_PERMISSION_DENIED; + } + std::io::ErrorKind::ConnectionRefused => { + r_println!("{}", eformat_cargo!("connection refused")); + ec.exit_code = EC_IO_ERR_CONNECTION_REFUSED; + } + std::io::ErrorKind::ConnectionReset => { + r_println!("{}", eformat_cargo!("connection reset")); + ec.exit_code = EC_IO_ERR_CONNECTION_RESET; + } + std::io::ErrorKind::HostUnreachable => { + r_println!("{}", eformat_cargo!("host unreachable")); + ec.exit_code = EC_IO_ERR_HOST_UNREACHABLE; + } + std::io::ErrorKind::NetworkUnreachable => { + r_println!("{}", eformat_cargo!("network unreachable")); + ec.exit_code = EC_IO_ERR_NETWORK_UNREACHABLE; + } + std::io::ErrorKind::ConnectionAborted => { + r_println!("{}", eformat_cargo!("connection aborted")); + ec.exit_code = EC_IO_ERR_CONNECTION_ABORTED; + } + std::io::ErrorKind::NotConnected => { + r_println!("{}", eformat_cargo!("not connected")); + ec.exit_code = EC_IO_ERR_NOT_CONNECTED; + } + std::io::ErrorKind::AddrInUse => { + r_println!("{}", eformat_cargo!("address in use")); + ec.exit_code = EC_IO_ERR_ADDR_IN_USE; + } + std::io::ErrorKind::AddrNotAvailable => { + r_println!("{}", eformat_cargo!("address not available")); + ec.exit_code = EC_IO_ERR_ADDR_NOT_AVAILABLE; + } + std::io::ErrorKind::NetworkDown => { + r_println!("{}", eformat_cargo!("network down")); + ec.exit_code = EC_IO_ERR_NETWORK_DOWN; + } + std::io::ErrorKind::BrokenPipe => { + r_println!("{}", eformat_cargo!("broken pipe")); + ec.exit_code = EC_IO_ERR_BROKEN_PIPE; + } + std::io::ErrorKind::AlreadyExists => { + r_println!("{}", eformat_cargo!("file or directory already exists")); + ec.exit_code = EC_IO_ERR_ALREADY_EXISTS; + } + std::io::ErrorKind::WouldBlock => { + r_println!("{}", eformat_cargo!("operation would block")); + ec.exit_code = EC_IO_ERR_WOULD_BLOCK; + } + std::io::ErrorKind::NotADirectory => { + r_println!("{}", eformat_cargo!("not a directory")); + ec.exit_code = EC_IO_ERR_NOT_A_DIRECTORY; + } + std::io::ErrorKind::IsADirectory => { + r_println!("{}", eformat_cargo!("is a directory")); + ec.exit_code = EC_IO_ERR_IS_A_DIRECTORY; + } + std::io::ErrorKind::DirectoryNotEmpty => { + r_println!("{}", eformat_cargo!("directory not empty")); + ec.exit_code = EC_IO_ERR_DIRECTORY_NOT_EMPTY; + } + std::io::ErrorKind::ReadOnlyFilesystem => { + r_println!("{}", eformat_cargo!("read-only filesystem")); + ec.exit_code = EC_IO_ERR_READ_ONLY_FILESYSTEM; + } + std::io::ErrorKind::StaleNetworkFileHandle => { + r_println!("{}", eformat_cargo!("stale network file handle")); + ec.exit_code = EC_IO_ERR_STALE_NETWORK_FILE_HANDLE; + } + std::io::ErrorKind::InvalidInput => { + r_println!("{}", eformat_cargo!("invalid input")); + ec.exit_code = EC_IO_ERR_INVALID_INPUT; + } + std::io::ErrorKind::InvalidData => { + r_println!("{}", eformat_cargo!("invalid data")); + ec.exit_code = EC_IO_ERR_INVALID_DATA; + } + std::io::ErrorKind::TimedOut => { + r_println!("{}", eformat_cargo!("timed out")); + ec.exit_code = EC_IO_ERR_TIMED_OUT; + } + std::io::ErrorKind::WriteZero => { + r_println!("{}", eformat_cargo!("write zero")); + ec.exit_code = EC_IO_ERR_WRITE_ZERO; + } + std::io::ErrorKind::StorageFull => { + r_println!("{}", eformat_cargo!("storage full")); + ec.exit_code = EC_IO_ERR_STORAGE_FULL; + } + std::io::ErrorKind::NotSeekable => { + r_println!("{}", eformat_cargo!("not seekable")); + ec.exit_code = EC_IO_ERR_NOT_SEEKABLE; + } + std::io::ErrorKind::QuotaExceeded => { + r_println!("{}", eformat_cargo!("quota exceeded")); + ec.exit_code = EC_IO_ERR_QUOTA_EXCEEDED; + } + std::io::ErrorKind::FileTooLarge => { + r_println!("{}", eformat_cargo!("file too large")); + ec.exit_code = EC_IO_ERR_FILE_TOO_LARGE; + } + std::io::ErrorKind::ResourceBusy => { + r_println!("{}", eformat_cargo!("resource busy")); + ec.exit_code = EC_IO_ERR_RESOURCE_BUSY; + } + std::io::ErrorKind::ExecutableFileBusy => { + r_println!("{}", eformat_cargo!("executable file busy")); + ec.exit_code = EC_IO_ERR_EXECUTABLE_FILE_BUSY; + } + std::io::ErrorKind::Deadlock => { + r_println!("{}", eformat_cargo!("deadlock")); + ec.exit_code = EC_IO_ERR_DEADLOCK; + } + std::io::ErrorKind::CrossesDevices => { + r_println!("{}", eformat_cargo!("crosses devices")); + ec.exit_code = EC_IO_ERR_CROSSES_DEVICES; + } + std::io::ErrorKind::TooManyLinks => { + r_println!("{}", eformat_cargo!("too many links")); + ec.exit_code = EC_IO_ERR_TOO_MANY_LINKS; + } + std::io::ErrorKind::InvalidFilename => { + r_println!("{}", eformat_cargo!("invalid filename")); + ec.exit_code = EC_IO_ERR_INVALID_FILENAME; + } + std::io::ErrorKind::ArgumentListTooLong => { + r_println!("{}", eformat_cargo!("argument list too long")); + ec.exit_code = EC_IO_ERR_ARGUMENT_LIST_TOO_LONG; + } + std::io::ErrorKind::Interrupted => { + r_println!("{}", eformat_cargo!("interrupted")); + ec.exit_code = EC_IO_ERR_INTERRUPTED; + } + std::io::ErrorKind::Unsupported => { + r_println!("{}", eformat_cargo!("unsupported")); + ec.exit_code = EC_IO_ERR_UNSUPPORTED; + } + std::io::ErrorKind::UnexpectedEof => { + r_println!("{}", eformat_cargo!("unexpected end of file")); + ec.exit_code = EC_IO_ERR_UNEXPECTED_EOF; + } + std::io::ErrorKind::OutOfMemory => { + r_println!("{}", eformat_cargo!("out of memory")); + ec.exit_code = EC_IO_ERR_OUT_OF_MEMORY; + } + std::io::ErrorKind::Other => { + r_println!("{}", eformat_cargo!(err.to_string())); + ec.exit_code = EC_IO_ERR_OTHER; + } + _ => { + r_println!("{}", eformat_cargo!(err.to_string())); + ec.exit_code = EC_IO_ERR_OTHER; + } + } +} diff --git a/mling/src/lib.rs b/mling/src/lib.rs index 560380a..0e122f3 100644 --- a/mling/src/lib.rs +++ b/mling/src/lib.rs @@ -19,6 +19,9 @@ pub use pkg_mgr::*; mod proj_mgr; pub use proj_mgr::*; +mod errors; +pub use errors::*; + use crate::display::markdown; gen_program!(); diff --git a/mling/src/proj_mgr/generator.rs b/mling/src/proj_mgr/generator.rs new file mode 100644 index 0000000..bcc6e5b --- /dev/null +++ b/mling/src/proj_mgr/generator.rs @@ -0,0 +1,39 @@ +use std::path::{self, PathBuf}; + +use mingling::{Groupped, macros::{chain, pack, r_println, renderer, route}}; + +use crate::{EntryGenerateProject, Next, 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) { + r_println!("Successfully create {} at \"{}\"", CHECK_LIST_NAME, result.to_string_lossy()); + r_println!(""); + r_println!("Please fill in {CHECK_LIST_NAME} and run `mling gen` again to continue generating"); +} diff --git a/mling/src/proj_mgr/mod.rs b/mling/src/proj_mgr/mod.rs index b282203..04353b7 100644 --- a/mling/src/proj_mgr/mod.rs +++ b/mling/src/proj_mgr/mod.rs @@ -4,6 +4,9 @@ use mingling::{ macros::{dispatcher, program_setup}, }; +mod generator; +pub use generator::*; + pub mod metadata; mod show_binaries; @@ -12,6 +15,8 @@ pub use show_binaries::*; mod show_directories; pub use show_directories::*; +dispatcher!("gen", CMDGenerateProject => EntryGenerateProject); + dispatcher!("show.binaries"); dispatcher!("show.workspace-dir", CMDShowWorkspaceDirectory => EntryShowWorkspaceDirectory @@ -22,6 +27,8 @@ dispatcher!("show.target-dir", #[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); |
