Repository: sxyazi/yazi (language: rust)

Issue:
Show Commit Hash When Using ya pack -l
### `yazi --debug` output

```Shell
Yazi
    Version: 0.3.3 (7c445ce 2024-09-04)
    Debug  : false
    OS     : linux-x86_64 (unix)

Ya
    Version: 0.3.3 (7c445ce 2024-09-04)

Emulator
    Emulator.via_env: ("xterm-256color", "WezTerm")
    Emulator.via_csi: Ok(WezTerm)
    Emulator.detect : WezTerm

Adapter
    Adapter.matches: Iterm2

Desktop
    XDG_SESSION_TYPE           : Some("wayland")
    WAYLAND_DISPLAY            : Some("wayland-0")
    DISPLAY                    : Some(":1")
    SWAYSOCK                   : None
    HYPRLAND_INSTANCE_SIGNATURE: None
    WAYFIRE_SOCKET             : None

SSH
    shared.in_ssh_connection: false

WSL
    WSL: false

Variables
    SHELL              : Some("/usr/bin/bash")
    EDITOR             : Some("vim")
    VISUAL             : None
    YAZI_FILE_ONE      : None
    YAZI_CONFIG_HOME   : None

Text Opener
    default: Some(Opener { run: "${EDITOR:-vi} \"$@\"", block: true, orphan: false, desc: "$EDITOR", for_: None, spread: true })
    block  : Some(Opener { run: "${EDITOR:-vi} \"$@\"", block: true, orphan: false, desc: "$EDITOR", for_: None, spread: true })

Multiplexers
    TMUX               : false
    tmux version       : No such file or directory (os error 2)
    ZELLIJ_SESSION_NAME: None
    Zellij version     : No such file or directory (os error 2)

Dependencies
    file             : 5.44
    ueberzugpp       : No such file or directory (os error 2)
    ffmpegthumbnailer: No such file or directory (os error 2)
    magick           : No such file or directory (os error 2)
    fzf              : 0.54.1
    fd               : No such file or directory (os error 2)
    rg               : 13.0.0
    chafa            : 1.12.4
    zoxide           : 0.9.6
    7z               : 16.02
    7zz              : No such file or directory (os error 2)
    jq               : 1.6


--------------------------------------------------
When reporting a bug, please also upload the `yazi.log` log file - only upload the most recent content by time.
You can find it in the "/home/user/.local/state/yazi" directory.
```


### Please describe the problem you're trying to solve

When the `ya pack -l` command is executed, it shows the username and repository name.
I think that showing only the username and repository name is not very helpful. 
So, I would like to show the commit hash as well. 
Showing the commit hash is easy because it is written in package.toml.
It seems that it can be accomplished just by modifying `yazi-cli/src/package/parser.rs`. 

https://github.com/sxyazi/yazi/blob/0baccdc9aaa26bbea458f0b7fcbe7916c8b2c1df/yazi-cli/src/package/parser.rs#L69-L89

### Would you be willing to contribute this feature?

- [X] Yes, I'll give it a shot

### Describe the solution you'd like

current format
```
user/repo
```

I want to show the following format
```
user/repo (hash)
```

I would like to contribute, but I am a Rust beginner.
So it may take time.

I appreciate your help.

### Additional context

_No response_

### Validations

- [X] I have searched the existing issues/discussions
- [X] The [latest nightly build](https://yazi-rs.github.io/docs/installation/#official-binaries) doesn't already have this feature


Discussion / hints:
In the future, I would like to display the commit message.
And I am also interested in implementing that feature.
Nice to have! 

To achieve this we need to add a new `rev` field getting process alongside the existing `use`, and print it out here:

https://github.com/sxyazi/yazi/blob/e42c621070759c602d2a3630cc51f834dbd95ee7/yazi-cli/src/package/parser.rs#L84-L86

@yudai0804 Would you like to give it a go? 
Thank you!
I'll try it.

Fix patch:
diff --git a/yazi-cli/src/package/parser.rs b/yazi-cli/src/package/parser.rs
index 49a22a403..7322ebf9d 100644
--- a/yazi-cli/src/package/parser.rs
+++ b/yazi-cli/src/package/parser.rs
@@ -46,8 +46,8 @@ impl Package {
 		let deps = deps.as_array_mut().context("`deps` must be an array")?;
 		for dep in deps.iter_mut() {
 			let dep = dep.as_inline_table_mut().context("Dependency must be an inline table")?;
-			let use_ = dep.get("use").and_then(|d| d.as_str()).context("Missing `use` field")?;
-			let rev = dep.get("rev").and_then(|d| d.as_str());
+			let use_ = dep.get("use").and_then(Value::as_str).context("Missing `use` field")?;
+			let rev = dep.get("rev").and_then(Value::as_str);
 
 			let mut package = Package::new(use_, rev);
 			if upgrade {
@@ -81,8 +81,11 @@ impl Package {
 		println!("{section}s:");
 
 		for dep in deps {
-			if let Some(Value::String(use_)) = dep.as_inline_table().and_then(|t| t.get("use")) {
-				println!("\t{}", use_.value());
+			let Some(dep) = dep.as_inline_table() else { continue };
+			match (dep.get("use").and_then(Value::as_str), dep.get("rev").and_then(Value::as_str)) {
+				(Some(use_), None) => println!("\t{use_}"),
+				(Some(use_), Some(rev)) => println!("\t{use_} ({rev})"),
+				_ => {}
 			}
 		}
 		Ok(())
@@ -119,7 +122,7 @@ impl Package {
 		fn same(v: &Value, name: &str) -> bool {
 			v.as_inline_table()
 				.and_then(|t| t.get("use"))
-				.and_then(|v| v.as_str())
+				.and_then(Value::as_str)
 				.is_some_and(|s| Package::new(s, None).name() == Some(name))
 		}
 
diff --git a/yazi-shared/src/event/cmd.rs b/yazi-shared/src/event/cmd.rs
index 66701b7bf..251adb417 100644
--- a/yazi-shared/src/event/cmd.rs
+++ b/yazi-shared/src/event/cmd.rs
@@ -57,20 +57,16 @@ impl Cmd {
 	pub fn get(&self, name: &str) -> Option<&Data> { self.args.get(name) }
 
 	#[inline]
-	pub fn str(&self, name: &str) -> Option<&str> { self.args.get(name).and_then(Data::as_str) }
+	pub fn str(&self, name: &str) -> Option<&str> { self.get(name).and_then(Data::as_str) }
 
 	#[inline]
-	pub fn bool(&self, name: &str) -> bool {
-		self.args.get(name).and_then(Data::as_bool).unwrap_or(false)
-	}
+	pub fn bool(&self, name: &str) -> bool { self.maybe_bool(name).unwrap_or(false) }
 
 	#[inline]
-	pub fn maybe_bool(&self, name: &str) -> Option<bool> {
-		self.args.get(name).and_then(Data::as_bool)
-	}
+	pub fn maybe_bool(&self, name: &str) -> Option<bool> { self.get(name).and_then(Data::as_bool) }
 
 	#[inline]
-	pub fn first(&self) -> Option<&Data> { self.args.get("0") }
+	pub fn first(&self) -> Option<&Data> { self.get("0") }
 
 	// --- Take
 	#[inline]
@@ -78,15 +74,15 @@ impl Cmd {
 
 	#[inline]
 	pub fn take_str(&mut self, name: &str) -> Option<String> {
-		if let Some(Data::String(s)) = self.args.remove(name) { Some(s) } else { None }
+		if let Some(Data::String(s)) = self.take(name) { Some(s) } else { None }
 	}
 
 	#[inline]
-	pub fn take_first(&mut self) -> Option<Data> { self.args.remove("0") }
+	pub fn take_first(&mut self) -> Option<Data> { self.take("0") }
 
 	#[inline]
 	pub fn take_first_str(&mut self) -> Option<String> {
-		if let Some(Data::String(s)) = self.args.remove("0") { Some(s) } else { None }
+		if let Some(Data::String(s)) = self.take_first() { Some(s) } else { None }
 	}
 
 	#[inline]


Test patch: