Repository: replydev/cotp (language: rust)

Issue:
index mismatch
Hi,

Just noticed that the main interactive screen show  index starting at `1`:
![image](https://github.com/user-attachments/assets/298d3400-e1e2-47ad-b936-cc4c6e83d144)

, but the `list` command starts from `0`:

![image](https://github.com/user-attachments/assets/3526d114-23f4-4765-b4e4-b9dee3a50a3b)


this brings some confusion when using the `edit` functionality, because it uses the same logic as the interactive interface, but the `list` is more convenient for the job.

Cheers,
PY


Discussion / hints:
Hello @presianbg you are totally right and I am gonna fix this.

Fix patch:
diff --git a/src/arguments/list.rs b/src/arguments/list.rs
index ace491e..961c313 100644
--- a/src/arguments/list.rs
+++ b/src/arguments/list.rs
@@ -56,6 +56,8 @@ impl<'a> TryFrom<&'a OTPElement> for JsonOtpList<'a> {
     }
 }
 
+const NO_ISSUER_TEXT: &str = "<No issuer>";
+
 impl SubcommandExecutor for ListArgs {
     fn run_command(self, otp_database: OTPDatabase) -> color_eyre::Result<OTPDatabase> {
         if self.format.unwrap_or_default().json {
@@ -69,9 +71,24 @@ impl SubcommandExecutor for ListArgs {
                 .map_err(|e| eyre!("Error during JSON serialization: {:?}", e))?;
             print!("{stringified}");
         } else {
+            let issuer_width = calculate_width(&otp_database, |element| {
+                let issuer_length = element.issuer.chars().count();
+                if issuer_length > 0 {
+                    issuer_length
+                } else {
+                    NO_ISSUER_TEXT.chars().count()
+                }
+            });
+
+            let label_width =
+                calculate_width(&otp_database, |element| element.label.chars().count());
+
             println!(
-                "{0: <6} {1: <30} {2: <70} {3: <10}",
-                "Index", "Issuer", "Label", "OTP"
+                "{0: <6} {1} {2} {3: <10}",
+                "Index",
+                "Issuer".to_owned() + " ".repeat(issuer_width - 6).as_ref(),
+                "Label".to_owned() + " ".repeat(label_width - 5).as_ref(),
+                "OTP",
             );
             otp_database
                 .elements
@@ -79,14 +96,19 @@ impl SubcommandExecutor for ListArgs {
                 .enumerate()
                 .for_each(|(index, e)| {
                     println!(
-                        "{0: <6} {1: <30} {2: <70} {3: <10}",
-                        index,
+                        "{0: <6} {1} {2} {3: <10}",
+                        index + 1,
                         if e.issuer.is_empty() {
-                            "<No issuer>"
+                            NO_ISSUER_TEXT.to_owned()
+                                + " "
+                                    .repeat(issuer_width - NO_ISSUER_TEXT.chars().count())
+                                    .as_str()
                         } else {
-                            e.issuer.as_str()
+                            e.issuer.to_owned()
+                                + " ".repeat(issuer_width - e.issuer.chars().count()).as_str()
                         },
-                        &e.label,
+                        e.label.to_owned()
+                            + " ".repeat(label_width - e.label.chars().count()).as_str(),
                         e.get_otp_code().unwrap_or("ERROR".to_string())
                     )
                 });
@@ -95,3 +117,16 @@ impl SubcommandExecutor for ListArgs {
         Ok(otp_database)
     }
 }
+
+fn calculate_width<F>(otp_database: &OTPDatabase, get_number_of_chars: F) -> usize
+where
+    F: Fn(&OTPElement) -> usize,
+{
+    otp_database
+        .elements
+        .iter()
+        .map(get_number_of_chars)
+        .max()
+        .unwrap_or_default()
+        + 3
+}


Test patch: