aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author1992414357@qq.com <1992414357@qq.com>2025-06-09 10:26:17 +0800
committer1992414357@qq.com <1992414357@qq.com>2025-06-09 10:26:17 +0800
commitd38f9e3c3e680fb21d0dcd6e94d486bbadf8b6e9 (patch)
tree91fde277cb5346a4d9c4141d17ba84963eec1088
parent7b68281155ea7bc2f5840b921f4a2f5ab7b8ff68 (diff)
修改了 Idea 环境下的运行配置.
-rw-r--r--.gitignore5
-rw-r--r--Cargo.lock132
-rw-r--r--README.md15
-rw-r--r--export/dev/bin/padc.exebin2831360 -> 6123008 bytes
-rw-r--r--export/dev/bridge/nogamepads.h249
-rw-r--r--export/dev/bridge/nogamepads_cpp.h257
-rw-r--r--export/dev/bridge/nogamepads_lib_c.dllbin2018816 -> 0 bytes
-rw-r--r--src/convert_utils.rs10
-rw-r--r--src/file_system_utils.rs54
9 files changed, 77 insertions, 645 deletions
diff --git a/.gitignore b/.gitignore
index 20466e7..97aa567 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
/.cargo/shared/
/export/dev/
-/documents/cargo_doc/ \ No newline at end of file
+/documents/cargo_doc/
+
+/.cargo/scripts/nogamepads-console/Microsoft.DesktopAppInstaller.msixbundle
+/nogamepads.yaml
diff --git a/Cargo.lock b/Cargo.lock
index 20592ac..18ccb38 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -894,7 +894,7 @@ dependencies = [
"glam",
"itertools 0.14.0",
"libm",
- "rand 0.8.5",
+ "rand",
"rand_distr",
"serde",
"smallvec",
@@ -1992,27 +1992,6 @@ dependencies = [
]
[[package]]
-name = "csv"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
-dependencies = [
- "csv-core",
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "csv-core"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
-dependencies = [
- "memchr",
-]
-
-[[package]]
name = "ctrlc"
version = "3.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2093,27 +2072,6 @@ dependencies = [
]
[[package]]
-name = "dirs-next"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
-dependencies = [
- "cfg-if",
- "dirs-sys-next",
-]
-
-[[package]]
-name = "dirs-sys-next"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
-dependencies = [
- "libc",
- "redox_users",
- "winapi",
-]
-
-[[package]]
name = "dispatch"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2194,12 +2152,6 @@ dependencies = [
]
[[package]]
-name = "encode_unicode"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
-
-[[package]]
name = "env_home"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2514,7 +2466,7 @@ checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee"
dependencies = [
"bytemuck",
"libm",
- "rand 0.8.5",
+ "rand",
"serde",
]
@@ -3248,6 +3200,7 @@ version = "0.1.0"
dependencies = [
"bevy",
"bevy-tokio-tasks",
+ "nogamepads",
"nogamepads-core",
"tokio",
]
@@ -3261,8 +3214,6 @@ dependencies = [
"log",
"nogamepads",
"nogamepads-core",
- "prettytable-rs",
- "rand 0.9.1",
"serde",
"serde_yaml",
"tokio",
@@ -3278,7 +3229,6 @@ dependencies = [
"hex",
"log",
"nogamepads",
- "prettytable-rs",
"serde",
"sha1",
"shell-words",
@@ -3289,6 +3239,7 @@ dependencies = [
name = "nogamepads-export"
version = "0.0.0"
dependencies = [
+ "nogamepads",
"serde",
"toml",
]
@@ -3757,7 +3708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [
"phf_shared",
- "rand 0.8.5",
+ "rand",
]
[[package]]
@@ -3890,20 +3841,6 @@ dependencies = [
]
[[package]]
-name = "prettytable-rs"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a"
-dependencies = [
- "csv",
- "encode_unicode",
- "is-terminal",
- "lazy_static",
- "term",
- "unicode-width",
-]
-
-[[package]]
name = "proc-macro-crate"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3955,18 +3892,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
-dependencies = [
- "rand_chacha 0.9.0",
- "rand_core 0.9.3",
+ "rand_chacha",
+ "rand_core",
]
[[package]]
@@ -3976,17 +3903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.9.3",
+ "rand_core",
]
[[package]]
@@ -3999,22 +3916,13 @@ dependencies = [
]
[[package]]
-name = "rand_core"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
-dependencies = [
- "getrandom 0.3.3",
-]
-
-[[package]]
name = "rand_distr"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
dependencies = [
"num-traits",
- "rand 0.8.5",
+ "rand",
]
[[package]]
@@ -4070,17 +3978,6 @@ dependencies = [
]
[[package]]
-name = "redox_users"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
-dependencies = [
- "getrandom 0.2.16",
- "libredox",
- "thiserror 1.0.69",
-]
-
-[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4569,17 +4466,6 @@ dependencies = [
]
[[package]]
-name = "term"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
-dependencies = [
- "dirs-next",
- "rustversion",
- "winapi",
-]
-
-[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/README.md b/README.md
index 3e281d7..864c67e 100644
--- a/README.md
+++ b/README.md
@@ -14,14 +14,19 @@
## 构建
-### 构建当前工作区
+### 运行控制台
```shell
-cargo build --workspace --release
+cargo padc --help
```
-### 打包当前项目
+### 快速打包当前项目
```shell
-cargo run --manifest-path .\export\Cargo.toml --bin export_project
-``` \ No newline at end of file
+# 调试当前项目
+cargo dev
+
+# 发布当前项目
+cargo export
+```
+
diff --git a/export/dev/bin/padc.exe b/export/dev/bin/padc.exe
index 1f969da..e628f49 100644
--- a/export/dev/bin/padc.exe
+++ b/export/dev/bin/padc.exe
Binary files differ
diff --git a/export/dev/bridge/nogamepads.h b/export/dev/bridge/nogamepads.h
deleted file mode 100644
index f8b58cf..0000000
--- a/export/dev/bridge/nogamepads.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/* NoGamepads C Bindings. */
-
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-typedef enum ConnCallbackMsgCTag {
- Profile,
- Deny,
- Fail,
- Ok,
- Welcome,
- Err,
-} ConnCallbackMsgCTag;
-
-typedef enum ConnErrTypeC {
- ContainSamePlayer,
- PlayerBanned,
- Timeout,
- GameLocked,
- WhatTheHell,
-} ConnErrTypeC;
-
-typedef enum ConnMsgCTag {
- Connection,
- RequestProfile,
- RequestLayoutConfigure,
- RequestSkinPackage,
- Ready,
- Err,
-} ConnMsgCTag;
-
-typedef enum CtrlMsgCTag {
- Msg,
- Pressed,
- Released,
- Axis,
- Dir,
- Exit,
- Err,
-} CtrlMsgCTag;
-
-typedef enum GameMsgCTag {
- SkinEventTrigger,
- DisableKey,
- EnableKey,
- Leave,
- Err,
-} GameMsgCTag;
-
-typedef enum LeaveReasonData {
- GameOver,
- ServerClosed,
- YouAreKicked,
- YouAreBanned,
-} LeaveReasonData;
-
-typedef struct GameProfileC {
- const char *game_name;
- const char *game_description;
- const char *organization;
- const char *version;
- const char *website;
- const char *email;
-} GameProfileC;
-
-typedef struct PlayerInfoC {
- const char *account_id;
- const char *account_hash;
- const char *customize_nickname;
- int32_t customize_color_hue;
- double customize_color_saturation;
- double customize_color_value;
-} PlayerInfoC;
-
-typedef struct PadClientC {
- const char *target_address;
- uint16_t target_port;
- struct PlayerInfoC bind_player;
- bool enable_console;
- bool quiet;
-} PadClientC;
-
-typedef struct KeyData {
- uint8_t key;
-} KeyData;
-
-typedef struct AxisData {
- uint8_t key;
- double ax;
-} AxisData;
-
-typedef struct DirData {
- uint8_t key;
- double x;
- double y;
-} DirData;
-
-typedef struct StrData {
- const char *str;
-} StrData;
-
-typedef union CtrlMsgCUnion {
- void *nul;
- struct KeyData key;
- struct AxisData axis;
- struct DirData dir;
- struct StrData str;
-} CtrlMsgCUnion;
-
-typedef struct ControlMessageC {
- enum CtrlMsgCTag tag;
- union CtrlMsgCUnion data;
-} ControlMessageC;
-
-typedef union GameMsgCUnion {
- void *nul;
- struct KeyData key;
- enum LeaveReasonData reason;
-} GameMsgCUnion;
-
-typedef struct GameMessageC {
- enum GameMsgCTag tag;
- union GameMsgCUnion data;
-} GameMessageC;
-
-typedef struct PlayerList {
- struct PlayerInfoC *players;
- uintptr_t len;
- uintptr_t capacity;
-} PlayerList;
-
-typedef union ConnMsgCUnion {
- void *nul;
- PlayerInfo info;
-} ConnMsgCUnion;
-
-typedef struct ConnectionMessageC {
- enum ConnMsgCTag tag;
- union ConnMsgCUnion data;
-} ConnectionMessageC;
-
-typedef union ConnCallbackMsgCUnion {
- void *nul;
- struct GameProfileC profile;
- enum ConnErrTypeC conn_err;
-} ConnCallbackMsgCUnion;
-
-typedef struct ConnectionCallbackMessageC {
- enum ConnCallbackMsgCTag tag;
- union ConnCallbackMsgCUnion data;
-} ConnectionCallbackMessageC;
-
-struct GameProfileC init_game_profile(void);
-
-struct GameProfileC set_game_profile_name(struct GameProfileC game_profile, const char *value);
-
-struct GameProfileC set_game_profile_description(struct GameProfileC game_profile,
- const char *value);
-
-struct GameProfileC set_game_profile_organization(struct GameProfileC game_profile,
- const char *value);
-
-struct GameProfileC set_game_profile_version(struct GameProfileC game_profile, const char *value);
-
-struct GameProfileC set_game_profile_website(struct GameProfileC game_profile, const char *value);
-
-struct GameProfileC set_game_profile_email(struct GameProfileC game_profile, const char *value);
-
-struct PlayerInfoC init_player_info(void);
-
-struct PlayerInfoC set_player_info_account(struct PlayerInfoC info,
- const char *id,
- const char *password);
-
-struct PlayerInfoC set_player_info_color(struct PlayerInfoC info, int32_t h, double s, double v);
-
-struct PlayerInfoC set_player_info_nickname(struct PlayerInfoC info, const char *nickname);
-
-uint16_t get_default_port(void);
-
-struct PadClientC init_client(const char *address);
-
-struct PadClientC init_client_with_port(const char *address, uint16_t port);
-
-struct PadClientC set_client_quiet(struct PadClientC client);
-
-struct PadClientC enable_client_console(struct PadClientC client);
-
-struct PadClientC bind_player_to_client(struct PadClientC client, struct PlayerInfoC info);
-
-PadClient *complete(struct PadClientC client);
-
-void connect_client_to_server(PadClient *client);
-
-void exit_client_from_server(const PadClient *client);
-
-void put_a_msg_to_server(const PadClient *client, struct ControlMessageC msg);
-
-struct GameMessageC pop_a_msg_from_server(const PadClient *client);
-
-struct GameMessageC pop_msg_from_server_or(const PadClient *client, struct GameMessageC or);
-
-PadServer *init_server(const char *address);
-
-PadServer *init_server_with_port(const char *address, uint16_t port);
-
-void set_server_quiet(PadServer *server);
-
-void enable_server_console(PadServer *server);
-
-void bind_profile_to_server(PadServer *server, const struct GameProfileC *profile);
-
-void start_server(PadServer *server);
-
-void stop_server(PadServer *server);
-
-void lock_game_on_server(PadServer *server);
-
-void unlock_game_on_server(PadServer *server);
-
-bool is_server_game_locked(PadServer *server);
-
-void put_a_msg_to_player(PadServer *server,
- struct GameMessageC msg,
- const struct PlayerInfoC *player);
-
-void put_msg_to_all_players(PadServer *server, struct GameMessageC msg);
-
-struct ControlMessageC pop_a_msg_from_player(PadServer *server, const struct PlayerInfoC *player);
-
-struct ControlMessageC pop_msg_from_player_or(PadServer *server,
- const struct PlayerInfoC *player,
- struct ControlMessageC or);
-
-bool is_player_online(PadServer *server, const struct PlayerInfoC *player);
-
-bool is_player_banned(PadServer *server, const struct PlayerInfoC *player);
-
-void kick_player(PadServer *server, const struct PlayerInfoC *player);
-
-void ban_player(PadServer *server, const struct PlayerInfoC *player);
-
-void pardon_player(PadServer *server, const struct PlayerInfoC *player);
-
-struct PlayerList list_online_players(PadServer *server);
-
-struct PlayerList list_banned_players(PadServer *server);
diff --git a/export/dev/bridge/nogamepads_cpp.h b/export/dev/bridge/nogamepads_cpp.h
deleted file mode 100644
index cd31b65..0000000
--- a/export/dev/bridge/nogamepads_cpp.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/* NoGamepads C++ Bindings. */
-
-/* Generated with cbindgen:0.29.0 */
-
-#include <cstdarg>
-#include <cstdint>
-#include <cstdlib>
-#include <ostream>
-#include <new>
-
-namespace nogamepads {
-
-enum class ConnCallbackMsgCTag {
- Profile,
- Deny,
- Fail,
- Ok,
- Welcome,
- Err,
-};
-
-enum class ConnErrTypeC {
- ContainSamePlayer,
- PlayerBanned,
- Timeout,
- GameLocked,
- WhatTheHell,
-};
-
-enum class ConnMsgCTag {
- Connection,
- RequestProfile,
- RequestLayoutConfigure,
- RequestSkinPackage,
- Ready,
- Err,
-};
-
-enum class CtrlMsgCTag {
- Msg,
- Pressed,
- Released,
- Axis,
- Dir,
- Exit,
- Err,
-};
-
-enum class GameMsgCTag {
- SkinEventTrigger,
- DisableKey,
- EnableKey,
- Leave,
- Err,
-};
-
-enum class LeaveReasonData {
- GameOver,
- ServerClosed,
- YouAreKicked,
- YouAreBanned,
-};
-
-template<typename T = void>
-struct ManuallyDrop;
-
-struct GameProfileC {
- const char *game_name;
- const char *game_description;
- const char *organization;
- const char *version;
- const char *website;
- const char *email;
-};
-
-struct PlayerInfoC {
- const char *account_id;
- const char *account_hash;
- const char *customize_nickname;
- int32_t customize_color_hue;
- double customize_color_saturation;
- double customize_color_value;
-};
-
-struct PadClientC {
- const char *target_address;
- uint16_t target_port;
- PlayerInfoC bind_player;
- bool enable_console;
- bool quiet;
-};
-
-struct KeyData {
- uint8_t key;
-};
-
-struct AxisData {
- uint8_t key;
- double ax;
-};
-
-struct DirData {
- uint8_t key;
- double x;
- double y;
-};
-
-struct StrData {
- const char *str;
-};
-
-union CtrlMsgCUnion {
- void *nul;
- KeyData key;
- AxisData axis;
- DirData dir;
- StrData str;
-};
-
-struct ControlMessageC {
- CtrlMsgCTag tag;
- CtrlMsgCUnion data;
-};
-
-union GameMsgCUnion {
- void *nul;
- KeyData key;
- LeaveReasonData reason;
-};
-
-struct GameMessageC {
- GameMsgCTag tag;
- GameMsgCUnion data;
-};
-
-struct PlayerList {
- PlayerInfoC *players;
- uintptr_t len;
- uintptr_t capacity;
-};
-
-union ConnMsgCUnion {
- void *nul;
- ManuallyDrop<PlayerInfo> info;
-};
-
-struct ConnectionMessageC {
- ConnMsgCTag tag;
- ConnMsgCUnion data;
-};
-
-union ConnCallbackMsgCUnion {
- void *nul;
- ManuallyDrop<GameProfileC> profile;
- ConnErrTypeC conn_err;
-};
-
-struct ConnectionCallbackMessageC {
- ConnCallbackMsgCTag tag;
- ConnCallbackMsgCUnion data;
-};
-
-extern "C" {
-
-GameProfileC init_game_profile();
-
-GameProfileC set_game_profile_name(GameProfileC game_profile, const char *value);
-
-GameProfileC set_game_profile_description(GameProfileC game_profile, const char *value);
-
-GameProfileC set_game_profile_organization(GameProfileC game_profile, const char *value);
-
-GameProfileC set_game_profile_version(GameProfileC game_profile, const char *value);
-
-GameProfileC set_game_profile_website(GameProfileC game_profile, const char *value);
-
-GameProfileC set_game_profile_email(GameProfileC game_profile, const char *value);
-
-PlayerInfoC init_player_info();
-
-PlayerInfoC set_player_info_account(PlayerInfoC info, const char *id, const char *password);
-
-PlayerInfoC set_player_info_color(PlayerInfoC info, int32_t h, double s, double v);
-
-PlayerInfoC set_player_info_nickname(PlayerInfoC info, const char *nickname);
-
-uint16_t get_default_port();
-
-PadClientC init_client(const char *address);
-
-PadClientC init_client_with_port(const char *address, uint16_t port);
-
-PadClientC set_client_quiet(PadClientC client);
-
-PadClientC enable_client_console(PadClientC client);
-
-PadClientC bind_player_to_client(PadClientC client, PlayerInfoC info);
-
-PadClient *complete(PadClientC client);
-
-void connect_client_to_server(PadClient *client);
-
-void exit_client_from_server(const PadClient *client);
-
-void put_a_msg_to_server(const PadClient *client, ControlMessageC msg);
-
-GameMessageC pop_a_msg_from_server(const PadClient *client);
-
-GameMessageC pop_msg_from_server_or(const PadClient *client, GameMessageC or);
-
-PadServer *init_server(const char *address);
-
-PadServer *init_server_with_port(const char *address, uint16_t port);
-
-void set_server_quiet(PadServer *server);
-
-void enable_server_console(PadServer *server);
-
-void bind_profile_to_server(PadServer *server, const GameProfileC *profile);
-
-void start_server(PadServer *server);
-
-void stop_server(PadServer *server);
-
-void lock_game_on_server(PadServer *server);
-
-void unlock_game_on_server(PadServer *server);
-
-bool is_server_game_locked(PadServer *server);
-
-void put_a_msg_to_player(PadServer *server, GameMessageC msg, const PlayerInfoC *player);
-
-void put_msg_to_all_players(PadServer *server, GameMessageC msg);
-
-ControlMessageC pop_a_msg_from_player(PadServer *server, const PlayerInfoC *player);
-
-ControlMessageC pop_msg_from_player_or(PadServer *server,
- const PlayerInfoC *player,
- ControlMessageC or);
-
-bool is_player_online(PadServer *server, const PlayerInfoC *player);
-
-bool is_player_banned(PadServer *server, const PlayerInfoC *player);
-
-void kick_player(PadServer *server, const PlayerInfoC *player);
-
-void ban_player(PadServer *server, const PlayerInfoC *player);
-
-void pardon_player(PadServer *server, const PlayerInfoC *player);
-
-PlayerList list_online_players(PadServer *server);
-
-PlayerList list_banned_players(PadServer *server);
-
-} // extern "C"
-
-} // namespace nogamepads
diff --git a/export/dev/bridge/nogamepads_lib_c.dll b/export/dev/bridge/nogamepads_lib_c.dll
deleted file mode 100644
index 6c376db..0000000
--- a/export/dev/bridge/nogamepads_lib_c.dll
+++ /dev/null
Binary files differ
diff --git a/src/convert_utils.rs b/src/convert_utils.rs
deleted file mode 100644
index fccd01e..0000000
--- a/src/convert_utils.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use std::collections::VecDeque;
-
-pub fn convert_deque_to_vec <V: Clone>(deque: &VecDeque<V>) -> Vec<V> {
- let vec_deque_ref = deque;
- let mut vec = Vec::new();
- for item in vec_deque_ref {
- vec.push(item.clone())
- }
- vec
-} \ No newline at end of file
diff --git a/src/file_system_utils.rs b/src/file_system_utils.rs
new file mode 100644
index 0000000..3296324
--- /dev/null
+++ b/src/file_system_utils.rs
@@ -0,0 +1,54 @@
+use std::io::Error;
+use std::path::PathBuf;
+use std::process::Command;
+
+pub fn open_in_explorer(path: PathBuf) -> Result<(), Error> {
+ let absolute_path = if path.is_relative() {
+ std::env::current_dir()?.join(path)
+ } else {
+ path
+ };
+
+ let absolute_path = absolute_path.canonicalize().unwrap_or(absolute_path);
+
+ if !absolute_path.exists() {
+ return Err(Error::new(
+ std::io::ErrorKind::NotFound,
+ format!("Path does not exist: {}", absolute_path.display())
+ ));
+ }
+
+ if cfg!(target_os = "windows") {
+ if absolute_path.is_file() {
+ absolute_path.parent()
+ .ok_or_else(|| Error::new(
+ std::io::ErrorKind::InvalidInput,
+ "File has no parent directory"
+ ))?;
+
+ Command::new("explorer")
+ .args(&["/select,", absolute_path.to_str().unwrap()])
+ .spawn()?;
+ } else {
+ Command::new("explorer")
+ .arg(absolute_path.to_str().unwrap())
+ .spawn()?;
+ }
+ } else if cfg!(target_os = "macos") {
+ if absolute_path.is_file() {
+ Command::new("open")
+ .args(&["-R", absolute_path.to_str().unwrap()])
+ .spawn()?;
+ } else {
+ Command::new("open")
+ .arg(absolute_path.to_str().unwrap())
+ .spawn()?;
+ }
+ } else {
+ Command::new("xdg-open")
+ .arg(absolute_path.to_str().unwrap())
+ .spawn()?;
+ }
+
+ Ok(())
+} \ No newline at end of file