Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package hoard for openSUSE:Factory checked 
in at 2022-12-22 16:22:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/hoard (Old)
 and      /work/SRC/openSUSE:Factory/.hoard.new.1835 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "hoard"

Thu Dec 22 16:22:45 2022 rev:2 rq:1044110 version:1.3.0~0

Changes:
--------
--- /work/SRC/openSUSE:Factory/hoard/hoard.changes      2022-12-07 
17:37:35.281400871 +0100
+++ /work/SRC/openSUSE:Factory/.hoard.new.1835/hoard.changes    2022-12-22 
16:22:47.837933880 +0100
@@ -1,0 +2,12 @@
+Wed Dec 21 18:31:33 UTC 2022 - Michael Vetter <mvet...@suse.com>
+
+- Update to 1.3.0:
+  * Inline command editing in the GUI. Press to get started.
+    Only editing the command, its description and the tags are
+    supported for now
+  * Inline command deletion in the GUI. Press to delete a command
+    in the GUI view
+  * Inline command creation in the GUI. Press to create a new
+    command in the GUI view
+
+-------------------------------------------------------------------

Old:
----
  hoard-1.2.0~0.tar.xz

New:
----
  hoard-1.3.0~0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ hoard.spec ++++++
--- /var/tmp/diff_new_pack.h2fAdA/_old  2022-12-22 16:22:52.997963559 +0100
+++ /var/tmp/diff_new_pack.h2fAdA/_new  2022-12-22 16:22:53.005963605 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           hoard
-Version:        1.2.0~0
+Version:        1.3.0~0
 Release:        0
 Summary:        CLI command organizer
 License:        MIT

++++++ _service ++++++
--- /var/tmp/diff_new_pack.h2fAdA/_old  2022-12-22 16:22:53.049963857 +0100
+++ /var/tmp/diff_new_pack.h2fAdA/_new  2022-12-22 16:22:53.053963881 +0100
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/Hyde46/hoard.git</param>
     <param name="versionformat">@PARENT_TAG@~@TAG_OFFSET@</param>
     <param name="scm">git</param>
-    <param name="revision">v1.2.0</param>
+    <param name="revision">v1.3.0</param>
     <param name="match-tag">*</param>
     <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param>
     <param name="versionrewrite-replacement">\1</param>
@@ -20,6 +20,9 @@
      <param name="compression">xz</param>
      <param name="update">true</param>
   </service>
+  <service name="cargo_audit" mode="disabled">
+     <param name="srcdir">hoard</param>
+  </service>
 </services>
 
 

++++++ hoard-1.2.0~0.tar.xz -> hoard-1.3.0~0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/CHANGES.md new/hoard-1.3.0~0/CHANGES.md
--- old/hoard-1.2.0~0/CHANGES.md        2022-11-28 18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/CHANGES.md        2022-12-21 14:06:28.000000000 +0100
@@ -3,6 +3,10 @@
 All notable changes to this project will be documented in this file.
 This project adheres to [Semantic Versioning](http://semver.org/).
 
+## 1.3
+- ✨ Inline command editing in the GUI. Press `<TAB>` to get started. Only 
editing the command, its description and the tags are supported for now
+- ✨ Inline command deletion in the GUI. Press `<Ctrl-X>` to delete a command 
in the GUI view
+- ✨ Inline command creation in the GUI. Press `<Ctrl-W>` to create a new 
command in the GUI view
 ## 1.2
 - ✨ You can now synchronize your commands across multiple terminals! Run 
`hoard sync --help` to start
 ## 1.1.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/Cargo.lock new/hoard-1.3.0~0/Cargo.lock
--- old/hoard-1.2.0~0/Cargo.lock        2022-11-28 18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/Cargo.lock        2022-12-21 14:06:28.000000000 +0100
@@ -4,9 +4,9 @@
 
 [[package]]
 name = "anyhow"
-version = "1.0.65"
+version = "1.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
+checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
 
 [[package]]
 name = "array_tool"
@@ -20,7 +20,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
  "libc",
  "winapi",
 ]
@@ -101,14 +101,14 @@
 
 [[package]]
 name = "clap"
-version = "4.0.17"
+version = "4.0.29"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "06badb543e734a2d6568e19a40af66ed5364360b9226184926f89d229b4b4267"
+checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
 dependencies = [
- "atty",
  "bitflags",
  "clap_derive",
  "clap_lex",
+ "is-terminal",
  "once_cell",
  "strsim",
  "termcolor",
@@ -116,9 +116,9 @@
 
 [[package]]
 name = "clap_derive"
-version = "4.0.13"
+version = "4.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
+checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
 dependencies = [
  "heck",
  "proc-macro-error",
@@ -149,13 +149,13 @@
 
 [[package]]
 name = "console"
-version = "0.15.1"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "89eab4d20ce20cea182308bca13088fecea9c05f6776cf287205d41a0ed3c847"
+checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
 dependencies = [
  "encode_unicode 0.3.6",
+ "lazy_static",
  "libc",
- "once_cell",
  "terminal_size",
  "unicode-width",
  "winapi",
@@ -338,6 +338,27 @@
 ]
 
 [[package]]
+name = "errno"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
 name = "eyre"
 version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -486,8 +507,17 @@
 ]
 
 [[package]]
+name = "hermit-abi"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+dependencies = [
+ "libc",
+]
+
+[[package]]
 name = "hoard-rs"
-version = "1.2.0"
+version = "1.3.0"
 dependencies = [
  "anyhow",
  "array_tool",
@@ -623,12 +653,34 @@
 ]
 
 [[package]]
+name = "io-lifetimes"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
+dependencies = [
+ "libc",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
 name = "ipnet"
 version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
 
 [[package]]
+name = "is-terminal"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
+dependencies = [
+ "hermit-abi 0.2.6",
+ "io-lifetimes",
+ "rustix",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
 name = "itoa"
 version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -657,9 +709,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.126"
+version = "0.2.137"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
 
 [[package]]
 name = "linked-hash-map"
@@ -668,6 +720,12 @@
 checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
 
 [[package]]
+name = "linux-raw-sys"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
+
+[[package]]
 name = "lock_api"
 version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -707,7 +765,7 @@
  "libc",
  "log",
  "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys",
+ "windows-sys 0.36.1",
 ]
 
 [[package]]
@@ -753,7 +811,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
  "libc",
 ]
 
@@ -849,7 +907,7 @@
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-sys",
+ "windows-sys 0.36.1",
 ]
 
 [[package]]
@@ -1050,6 +1108,20 @@
 ]
 
 [[package]]
+name = "rustix"
+version = "0.36.4"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23"
+dependencies = [
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
 name = "rustversion"
 version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -1068,7 +1140,7 @@
 checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
 dependencies = [
  "lazy_static",
- "windows-sys",
+ "windows-sys 0.36.1",
 ]
 
 [[package]]
@@ -1295,18 +1367,18 @@
 
 [[package]]
 name = "thiserror"
-version = "1.0.35"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.35"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1660,44 +1732,101 @@
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
 dependencies = [
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_msvc",
+ "windows_aarch64_msvc 0.36.1",
+ "windows_i686_gnu 0.36.1",
+ "windows_i686_msvc 0.36.1",
+ "windows_x86_64_gnu 0.36.1",
+ "windows_x86_64_msvc 0.36.1",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc 0.42.0",
+ "windows_i686_gnu 0.42.0",
+ "windows_i686_msvc 0.42.0",
+ "windows_x86_64_gnu 0.42.0",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc 0.42.0",
 ]
 
 [[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
+[[package]]
 name = "windows_aarch64_msvc"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
 
 [[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+
+[[package]]
 name = "windows_i686_gnu"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
 
 [[package]]
+name = "windows_i686_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+
+[[package]]
 name = "windows_i686_msvc"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
 
 [[package]]
+name = "windows_i686_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+
+[[package]]
 name = "windows_x86_64_gnu"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
 
 [[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+
+[[package]]
 name = "windows_x86_64_msvc"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
 
 [[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+
+[[package]]
 name = "winreg"
 version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/Cargo.toml new/hoard-1.3.0~0/Cargo.toml
--- old/hoard-1.2.0~0/Cargo.toml        2022-11-28 18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/Cargo.toml        2022-12-21 14:06:28.000000000 +0100
@@ -1,6 +1,6 @@
 [package]
 name = "hoard-rs"
-version = "1.2.0"
+version = "1.3.0"
 edition = "2021"
 readme = "README.md"
 license = "MIT"
@@ -28,7 +28,7 @@
 
 [dependencies]
 # Command line argument parser
-clap = { version = "4.0.7", features = ["derive"] }
+clap = { version = "4.0.29", features = ["derive"] }
 # pretty dialogues in terminal
 dialoguer = "0.10.2"
 termion = "1.5.6"
@@ -36,7 +36,7 @@
 serde = { version = "1.0", features = ["derive"] }
 serde_yaml = "0.8"
 serde_json = "1.0"
-anyhow = "1.0.65"
+anyhow = "1.0.68"
 dirs = "4.0.0"
 log = "0.4"
 eyre = "0.6"
@@ -51,7 +51,7 @@
 array_tool = "1.0.3"
 reqwest = { version = "0.11.12", features = ["blocking"] }
 url = {version="2.3.1"}
-console = "0.15.1"
+console = "0.15.2"
 enum-iterator = "1.2.0"
 base64 = "0.13.1"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/README.md new/hoard-1.3.0~0/README.md
--- old/hoard-1.2.0~0/README.md 2022-11-28 18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/README.md 2022-12-21 14:06:28.000000000 +0100
@@ -92,7 +92,7 @@
 If you are running `fish` shell
 
 ```
-LATEST_RELEASE=1.2.0 ./install.fish
+LATEST_RELEASE=1.3.0 ./install.fish
 ```
 
 ### Brew on MacOS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/example_troves/git.yml 
new/hoard-1.3.0~0/example_troves/git.yml
--- old/hoard-1.2.0~0/example_troves/git.yml    2022-11-28 18:38:14.000000000 
+0100
+++ new/hoard-1.3.0~0/example_troves/git.yml    2022-12-21 14:06:28.000000000 
+0100
@@ -1,5 +1,5 @@
 ---
-version: 1.2.0
+version: 1.3.0
 commands:
   - name: git_status
     namespace: git
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/install.sh new/hoard-1.3.0~0/install.sh
--- old/hoard-1.2.0~0/install.sh        2022-11-28 18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/install.sh        2022-12-21 14:06:28.000000000 +0100
@@ -42,7 +42,7 @@
 
 __hoard_install_ubuntu(){
        echo "Assuming Ubuntu distro. Trying to install .deb package"
-       
ARTIFACT_URL="https://github.com/hyde46/hoard/releases/download/v1.2.0/hoard_1.2.0.deb";
+       
ARTIFACT_URL="https://github.com/hyde46/hoard/releases/download/v1.3.0/hoard_1.3.0.deb";
 
        TEMP_DEB="$(mktemp)" &&
        wget -O "$TEMP_DEB" "$ARTIFACT_URL"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/command/hoard_command.rs 
new/hoard-1.3.0~0/src/command/hoard_command.rs
--- old/hoard-1.2.0~0/src/command/hoard_command.rs      2022-11-28 
18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/src/command/hoard_command.rs      2022-12-21 
14:06:28.000000000 +0100
@@ -24,6 +24,30 @@
         }
     }
 
+    pub fn is_command_valid(c: &str) -> (bool, String) {
+        if c.is_empty() {
+            return (false, String::from("Command can't be empty"));
+        }
+        (true, String::new())
+    }
+
+    pub fn is_name_valid(c: &str) -> (bool, String) {
+        if c.is_empty() {
+            return (false, String::from("Name can't be empty"));
+        }
+        if c.contains(' ') {
+            return (false, String::from("Name can't contain whitespaces"));
+        }
+        (true, String::new())
+    }
+
+    pub fn are_tags_valid(c: &str) -> (bool, String) {
+        if c.is_empty() {
+            return (false, String::from("Tags can't be empty"));
+        }
+        (true, String::new())
+    }
+
     #[allow(dead_code)]
     pub fn is_complete(&self) -> bool {
         if self.name.is_empty()
@@ -77,14 +101,7 @@
         Self {
             name: self.name,
             namespace: self.namespace,
-            tags: Some(
-                tags.chars()
-                    .filter(|c| !c.is_whitespace())
-                    .collect::<String>()
-                    .split(',')
-                    .map(std::string::ToString::to_string)
-                    .collect(),
-            ),
+            tags: Some(string_to_tags(tags)),
             command: self.command,
             description: self.description,
         }
@@ -207,6 +224,15 @@
     }
 }
 
+pub fn string_to_tags(tags: &str) -> Vec<String> {
+    tags.chars()
+        .filter(|c| !c.is_whitespace())
+        .collect::<String>()
+        .split(',')
+        .map(std::string::ToString::to_string)
+        .collect()
+}
+
 pub trait Parameterized {
     // Check if parameter pointers are present
     fn is_parameterized(&self, token: &str) -> bool;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/command/trove.rs 
new/hoard-1.3.0~0/src/command/trove.rs
--- old/hoard-1.2.0~0/src/command/trove.rs      2022-11-28 18:38:14.000000000 
+0100
+++ new/hoard-1.3.0~0/src/command/trove.rs      2022-12-21 14:06:28.000000000 
+0100
@@ -12,7 +12,7 @@
 const CARGO_VERSION: &str = env!("CARGO_PKG_VERSION");
 
 #[allow(clippy::module_name_repetitions)]
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Clone, Deserialize)]
 pub struct CommandTrove {
     pub version: String,
     pub commands: Vec<HoardCommand>,
@@ -81,7 +81,7 @@
         fs::write(path, s).expect("Unable to write config file");
     }
 
-    fn check_name_collision(&self, command: &HoardCommand) -> 
Option<HoardCommand> {
+    pub fn check_name_collision(&self, command: &HoardCommand) -> 
Option<HoardCommand> {
         let colliding_commands = self
             .commands
             .iter()
@@ -176,6 +176,15 @@
         )
     }
 
+    pub fn update_command_by_name(&mut self, command: &HoardCommand) -> &mut 
Self {
+        for c in &mut self.commands.iter_mut() {
+            if c.name == command.name {
+                *c = command.clone();
+            }
+        }
+        self
+    }
+
     pub fn is_empty(&self) -> bool {
         self.commands.is_empty()
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/commands_gui.rs 
new/hoard-1.3.0~0/src/gui/commands_gui.rs
--- old/hoard-1.2.0~0/src/gui/commands_gui.rs   2022-11-28 18:38:14.000000000 
+0100
+++ new/hoard-1.3.0~0/src/gui/commands_gui.rs   2022-12-21 14:06:28.000000000 
+0100
@@ -3,11 +3,15 @@
 use crate::config::HoardConfig;
 use crate::gui::event::{Config, Event, Events};
 use crate::gui::help::{draw as draw_help, key_handler as key_handler_help};
+use crate::gui::inline_edit::controls::key_handler as key_handler_inline_edit;
 use crate::gui::list_search::controls::key_handler as key_handler_list_search;
 use crate::gui::list_search::render::draw as draw_list_search;
+use crate::gui::new_command::controls::key_handler as 
key_handler_create_command;
+use crate::gui::new_command::render::draw as draw_new_command_input;
 use crate::gui::parameter_input::controls::key_handler as 
key_handler_parameter_input;
 use crate::gui::parameter_input::render::draw as draw_parameter_input;
 use eyre::Result;
+use std::fmt;
 use std::io::stdout;
 use std::time::Duration;
 use termion::{raw::IntoRawMode, screen::AlternateScreen};
@@ -19,11 +23,35 @@
     pub command_list_state: ListState,
     pub namespace_tab_state: ListState,
     pub should_exit: bool,
+    pub should_delete: bool,
     pub draw_state: DrawState,
+    pub control_state: ControlState,
+    pub edit_selection: EditSelection,
+    pub new_command: Option<HoardCommand>,
+    pub string_to_edit: String,
     pub parameter_token: String,
     pub parameter_ending_token: String,
     pub selected_command: Option<HoardCommand>,
     pub provided_parameter_count: u16,
+    pub error_message: String,
+}
+
+impl State {
+    pub fn update_string_to_edit(&mut self) -> &mut Self {
+        let selected_idx = self.command_list_state.selected().unwrap();
+        let cloned_selected_command = 
self.commands.get(selected_idx).unwrap().clone();
+        match self.edit_selection {
+            EditSelection::Name => self.string_to_edit = 
cloned_selected_command.name,
+            EditSelection::Tags => self.string_to_edit = 
cloned_selected_command.tags_as_string(),
+            EditSelection::Description => {
+                self.string_to_edit = 
cloned_selected_command.description.unwrap_or_default();
+            }
+
+            EditSelection::Command => self.string_to_edit = 
cloned_selected_command.command,
+            EditSelection::Namespace => (),
+        };
+        self
+    }
 }
 
 #[derive(Debug, Eq, PartialEq)]
@@ -31,6 +59,65 @@
     Search,
     ParameterInput,
     Help,
+    Create,
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub enum ControlState {
+    Search,
+    Edit,
+}
+
+impl fmt::Display for ControlState {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::Search => write!(f, "Search (<Tab>/<Ctrl-E> to edit)"),
+            Self::Edit => write!(
+                f,
+                "Edit (<Enter> to confirm. <Tab> to switch. <Esc> to abort)"
+            ),
+        }
+    }
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub enum EditSelection {
+    Name,
+    Tags,
+    Description,
+    Command,
+    Namespace,
+}
+
+impl fmt::Display for EditSelection {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::Name => write!(f, "Name"),
+            Self::Tags => write!(f, "Tags"),
+            Self::Description => write!(f, "Description"),
+            Self::Command => write!(f, "Command"),
+            Self::Namespace => write!(f, "Namespace"),
+        }
+    }
+}
+
+impl EditSelection {
+    pub const fn next(&self) -> Self {
+        match self {
+            Self::Name | Self::Namespace | Self::Command => Self::Tags,
+            Self::Tags => Self::Description,
+            Self::Description => Self::Command,
+        }
+    }
+    pub const fn edit_next(&self) -> Self {
+        match self {
+            Self::Command => Self::Namespace,
+            Self::Namespace => Self::Name,
+            Self::Name => Self::Description,
+            Self::Description => Self::Tags,
+            Self::Tags => Self::Command,
+        }
+    }
 }
 
 #[allow(clippy::too_many_lines)]
@@ -38,19 +125,25 @@
     let events = Events::with_config(Config {
         tick_rate: Duration::from_millis(200),
     });
-
+    let trove_clone = trove.clone();
     let mut app_state = State {
         input: String::new(),
-        commands: trove.commands.clone(),
+        commands: trove_clone.commands.clone(),
         command_list_state: ListState::default(),
         namespace_tab_state: ListState::default(),
         should_exit: false,
+        should_delete: false,
         draw_state: DrawState::Search,
+        control_state: ControlState::Search,
+        edit_selection: EditSelection::Command,
+        new_command: None,
+        string_to_edit: String::new(),
         parameter_token: config.parameter_token.as_ref().unwrap().clone(),
         parameter_ending_token: 
config.parameter_ending_token.as_ref().unwrap().clone(),
 
         selected_command: None,
         provided_parameter_count: 0,
+        error_message: String::new(),
     };
 
     app_state.command_list_state.select(Some(0));
@@ -63,7 +156,7 @@
     terminal.clear()?;
 
     //let menu_titles = vec!["List", "Search", "Add", "Delete", "Quit"];
-    let mut namespace_tabs: Vec<&str> = trove.namespaces();
+    let mut namespace_tabs: Vec<&str> = trove_clone.namespaces();
     namespace_tabs.insert(0, "All");
     loop {
         // Draw GUI
@@ -77,20 +170,53 @@
             DrawState::Help => {
                 draw_help(config, &mut terminal)?;
             }
+            DrawState::Create => {
+                draw_new_command_input(
+                    &mut app_state,
+                    config,
+                    &mut terminal,
+                    &config.default_namespace,
+                )?;
+            }
         }
 
         if let Event::Input(input) = events.next()? {
             let command = match app_state.draw_state {
-                DrawState::Search => {
-                    key_handler_list_search(input, &mut app_state, 
&trove.commands, &namespace_tabs)
-                }
+                DrawState::Search => match app_state.control_state {
+                    ControlState::Search => key_handler_list_search(
+                        input,
+                        &mut app_state,
+                        &trove.commands,
+                        &namespace_tabs,
+                    ),
+                    ControlState::Edit => key_handler_inline_edit(input, &mut 
app_state),
+                },
                 DrawState::ParameterInput => 
key_handler_parameter_input(input, &mut app_state),
                 DrawState::Help => key_handler_help(input, &mut app_state),
+                DrawState::Create => {
+                    key_handler_create_command(input, &mut app_state, 
&config.default_namespace)
+                }
             };
 
             if let Some(output) = command {
-                terminal.show_cursor()?;
-                return Ok(Some(output));
+                if app_state.draw_state == DrawState::Create {
+                    trove.add_command(output);
+                    app_state.commands = trove.commands.clone();
+                    app_state.draw_state = DrawState::Search;
+                } else if app_state.control_state == ControlState::Edit {
+                    // Command has been edited
+                    trove.update_command_by_name(&output);
+                    app_state.commands = trove.commands.clone();
+                    app_state.control_state = ControlState::Search;
+                } else if app_state.should_delete {
+                    trove.remove_command(&output.name).ok();
+                    app_state.commands = trove.commands.clone();
+                    app_state.should_delete = false;
+                } else {
+                    // Command has been selected
+                    terminal.show_cursor()?;
+                    return Ok(Some(output));
+                }
             }
 
             if app_state.should_exit {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/help.rs 
new/hoard-1.3.0~0/src/gui/help.rs
--- old/hoard-1.2.0~0/src/gui/help.rs   2022-11-28 18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/src/gui/help.rs   2022-12-21 14:06:28.000000000 +0100
@@ -19,6 +19,11 @@
     ("Next namespace tab", "<Ctrl-L> / <Right-Arrow>"),
     ("Previous namespace tab", "<Ctrl-H> / <Left-Arrow>"),
     ("Select command", "<Enter>"),
+    ("Create new command", "<Ctrl-W>"),
+    ("Delete command", "<Ctrl-X>"),
+    ("Toggle search/edit mode", "<Tab> / <Ctrl-E>"),
+    ("Toggle Command to edit in edit mode", "<Tab>"),
+    ("Exit edit mode", "<Esc>"),
     ("Quit", "<Ctrl-D> / <Ctrl-C> / <Ctrl-G>"),
     ("Show help", HELP_KEY),
     ("Close help", "<Any key>"),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/inline_edit/controls.rs 
new/hoard-1.3.0~0/src/gui/inline_edit/controls.rs
--- old/hoard-1.2.0~0/src/gui/inline_edit/controls.rs   1970-01-01 
01:00:00.000000000 +0100
+++ new/hoard-1.3.0~0/src/gui/inline_edit/controls.rs   2022-12-21 
14:06:28.000000000 +0100
@@ -0,0 +1,45 @@
+use crate::command::hoard_command::{string_to_tags, HoardCommand};
+use crate::gui::commands_gui::{ControlState, EditSelection, State};
+use termion::event::Key;
+
+pub fn key_handler(input: Key, state: &mut State) -> Option<HoardCommand> {
+    match input {
+        // Quit command
+        Key::Esc => {
+            // Only exit the edit mode
+            state.control_state = ControlState::Search;
+            None
+        }
+        Key::Char('\n') => {
+            let mut edited_command = state.selected_command.clone().unwrap();
+            let new_string = state.string_to_edit.clone();
+            match state.edit_selection {
+                EditSelection::Description => edited_command.description = 
Some(new_string),
+                EditSelection::Command => edited_command.command = new_string,
+                EditSelection::Tags => edited_command.tags = 
Some(string_to_tags(&new_string)),
+                EditSelection::Name | EditSelection::Namespace => (),
+            };
+            Some(edited_command)
+        }
+        Key::Char('\t') => {
+            state.edit_selection = state.edit_selection.next();
+            state.update_string_to_edit();
+            None
+        }
+        Key::Ctrl('c' | 'd' | 'g') => {
+            // Definitely exit program
+            state.should_exit = true;
+            None
+        }
+        // Handle query input
+        Key::Backspace => {
+            state.string_to_edit.pop();
+            None
+        }
+        Key::Char(c) => {
+            state.string_to_edit.push(c);
+            None
+        }
+        _ => None,
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/inline_edit/mod.rs 
new/hoard-1.3.0~0/src/gui/inline_edit/mod.rs
--- old/hoard-1.2.0~0/src/gui/inline_edit/mod.rs        1970-01-01 
01:00:00.000000000 +0100
+++ new/hoard-1.3.0~0/src/gui/inline_edit/mod.rs        2022-12-21 
14:06:28.000000000 +0100
@@ -0,0 +1 @@
+pub mod controls;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/list_search/controls.rs 
new/hoard-1.3.0~0/src/gui/list_search/controls.rs
--- old/hoard-1.2.0~0/src/gui/list_search/controls.rs   2022-11-28 
18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/src/gui/list_search/controls.rs   2022-12-21 
14:06:28.000000000 +0100
@@ -1,7 +1,8 @@
 use crate::command::hoard_command::{HoardCommand, Parameterized};
-use crate::gui::commands_gui::{DrawState, State};
+use crate::gui::commands_gui::{ControlState, DrawState, EditSelection, State};
 use termion::event::Key;
 
+#[allow(clippy::too_many_lines)]
 pub fn key_handler(
     input: Key,
     state: &mut State,
@@ -9,8 +10,9 @@
     namespace_tabs: &[&str],
 ) -> Option<HoardCommand> {
     match input {
-        // Quit command
         Key::Esc | Key::Ctrl('c' | 'd' | 'g') => {
+            // Definitely exit program
+            state.control_state = ControlState::Search;
             state.should_exit = true;
             None
         }
@@ -19,6 +21,31 @@
             state.draw_state = DrawState::Help;
             None
         }
+        // Show help
+        Key::Ctrl('w') => {
+            state.draw_state = DrawState::Create;
+            state.edit_selection = EditSelection::Command;
+            state.new_command = Some(HoardCommand::default());
+            None
+        }
+        // Switch to edit command mode
+        Key::Ctrl('e') | Key::Char('\t') => {
+            let selected_command = state
+                .commands
+                .clone()
+                .get(
+                    state
+                        .command_list_state
+                        .selected()
+                        .expect("there is always a selected command"),
+                )
+                .expect("exists")
+                .clone();
+            state.control_state = ControlState::Edit;
+            state.selected_command = Some(selected_command);
+            state.update_string_to_edit();
+            None
+        }
         // Switch namespace
         Key::Left | Key::Ctrl('h') => {
             if let Some(selected) = state.namespace_tab_state.selected() {
@@ -53,6 +80,24 @@
             }
             None
         }
+        Key::Ctrl('x') => {
+            if state.commands.is_empty() {
+                return None;
+            }
+            let selected_command = state
+                .commands
+                .clone()
+                .get(
+                    state
+                        .command_list_state
+                        .selected()
+                        .expect("there is always a selected command"),
+                )
+                .expect("exists")
+                .clone();
+            state.should_delete = true;
+            Some(selected_command)
+        }
         // Select command
         Key::Char('\n') => {
             if state.commands.is_empty() {
@@ -193,11 +238,17 @@
             command_list_state: ListState::default(),
             namespace_tab_state: ListState::default(),
             should_exit: false,
+            should_delete: false,
             draw_state: DrawState::Search,
+            control_state: ControlState::Search,
+            new_command: None,
+            edit_selection: crate::gui::commands_gui::EditSelection::Command,
+            string_to_edit: String::new(),
             parameter_token: "#".to_string(),
             parameter_ending_token: "!".to_string(),
             selected_command: None,
             provided_parameter_count: 0,
+            error_message: String::new(),
         };
 
         state.command_list_state.select(Some(0));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/list_search/render.rs 
new/hoard-1.3.0~0/src/gui/list_search/render.rs
--- old/hoard-1.2.0~0/src/gui/list_search/render.rs     2022-11-28 
18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/src/gui/list_search/render.rs     2022-12-21 
14:06:28.000000000 +0100
@@ -1,6 +1,7 @@
 use crate::command::hoard_command::HoardCommand;
 use crate::config::HoardConfig;
 use crate::gui::commands_gui::State;
+use crate::gui::commands_gui::{ControlState, EditSelection};
 use crate::gui::help::HELP_KEY;
 use termion::screen::AlternateScreen;
 use tui::backend::TermionBackend;
@@ -12,6 +13,7 @@
 
 const VERSION: &str = env!("CARGO_PKG_VERSION");
 
+#[allow(clippy::too_many_lines)]
 pub fn draw(
     app_state: &mut State,
     config: &HoardConfig,
@@ -102,19 +104,80 @@
         rect.render_widget(command, command_detail_chunks[2]);
         rect.render_widget(input, chunks[2]);
 
-        let help_hint = Paragraph::new(format!("Show help - {HELP_KEY} "))
+        let (footer_left, footer_right) = 
get_footer_constraints(&app_state.control_state);
+        let footer_chunk = Layout::default()
+            .direction(Direction::Horizontal)
+            .margin(0)
+            .constraints([
+                Constraint::Percentage(footer_left),
+                Constraint::Percentage(footer_right),
+            ])
+            .split(chunks[3]);
+
+        let control_state_str = &app_state.control_state;
+        let help_hint_l = Paragraph::new(format!("{control_state_str}"))
             .style(Style::default().fg(Color::Rgb(
                 config.primary_color.unwrap().0,
                 config.primary_color.unwrap().1,
                 config.primary_color.unwrap().2,
             )))
-            .alignment(Alignment::Right);
+            .alignment(Alignment::Left);
+        let help_hint = Paragraph::new(format!(
+            "Create <Ctrl-W> | Delete <Ctrl-X> | Help {HELP_KEY}"
+        ))
+        .style(Style::default().fg(Color::Rgb(
+            config.primary_color.unwrap().0,
+            config.primary_color.unwrap().1,
+            config.primary_color.unwrap().2,
+        )))
+        .alignment(Alignment::Right);
 
-        rect.render_widget(help_hint, chunks[3]);
+        rect.render_widget(help_hint_l, footer_chunk[0]);
+        if app_state.control_state == ControlState::Search {
+            rect.render_widget(help_hint, footer_chunk[1]);
+        }
     })?;
     Ok(())
 }
 
+fn get_color(
+    app: &mut State,
+    config: &HoardConfig,
+    command_render: &EditSelection,
+) -> tui::style::Color {
+    let highlighted = Color::Rgb(
+        config.secondary_color.unwrap().0,
+        config.secondary_color.unwrap().1,
+        config.secondary_color.unwrap().2,
+    );
+    let normal = Color::Rgb(
+        config.primary_color.unwrap().0,
+        config.primary_color.unwrap().1,
+        config.primary_color.unwrap().2,
+    );
+    match app.control_state {
+        ControlState::Search => normal,
+        ControlState::Edit => {
+            if command_render == &app.edit_selection {
+                return highlighted;
+            }
+            normal
+        }
+    }
+}
+
+fn coerce_string_by_mode(s: String, app: &State, command_render: 
&EditSelection) -> String {
+    match app.control_state {
+        ControlState::Search => s,
+        ControlState::Edit => {
+            if command_render == &app.edit_selection {
+                return app.string_to_edit.clone();
+            }
+            s
+        }
+    }
+}
+
 #[allow(clippy::too_many_lines)]
 fn render_commands<'a>(
     commands_list: &[HoardCommand],
@@ -129,11 +192,7 @@
 ) {
     let commands = Block::default()
         .borders(Borders::ALL)
-        .style(Style::default().fg(Color::Rgb(
-            config.primary_color.unwrap().0,
-            config.primary_color.unwrap().1,
-            config.primary_color.unwrap().2,
-        )))
+        .style(Style::default().fg(get_color(app, config, 
&EditSelection::Name)))
         .title(" Commands ")
         .border_type(BorderType::Plain);
 
@@ -181,64 +240,64 @@
             .add_modifier(Modifier::BOLD),
     );
 
-    let command = Paragraph::new(selected_command.command.clone())
-        .style(Style::default().fg(Color::Rgb(
-            config.command_color.unwrap().0,
-            config.command_color.unwrap().1,
-            config.command_color.unwrap().2,
-        )))
-        .alignment(Alignment::Left)
-        .wrap(Wrap { trim: true })
-        .block(
-            Block::default()
-                .borders(Borders::ALL)
-                .style(Style::default().fg(Color::Rgb(
-                    config.primary_color.unwrap().0,
-                    config.primary_color.unwrap().1,
-                    config.primary_color.unwrap().2,
-                )))
-                .title(" Hoarded command ")
-                .border_type(BorderType::Plain),
-        );
+    let command = Paragraph::new(coerce_string_by_mode(
+        selected_command.command.clone(),
+        app,
+        &EditSelection::Command,
+    ))
+    .style(Style::default().fg(Color::Rgb(
+        config.primary_color.unwrap().0,
+        config.primary_color.unwrap().1,
+        config.primary_color.unwrap().2,
+    )))
+    .alignment(Alignment::Left)
+    .wrap(Wrap { trim: true })
+    .block(
+        Block::default()
+            .borders(Borders::ALL)
+            .style(Style::default().fg(get_color(app, config, 
&EditSelection::Command)))
+            .title(" Hoarded command ")
+            .border_type(BorderType::Plain),
+    );
 
-    let tags = Paragraph::new(selected_command.tags_as_string())
-        .style(Style::default().fg(Color::Rgb(
-            config.primary_color.unwrap().0,
-            config.primary_color.unwrap().1,
-            config.primary_color.unwrap().2,
-        )))
-        .alignment(Alignment::Left)
-        .block(
-            Block::default()
-                .borders(Borders::ALL)
-                .style(Style::default().fg(Color::Rgb(
-                    config.primary_color.unwrap().0,
-                    config.primary_color.unwrap().1,
-                    config.primary_color.unwrap().2,
-                )))
-                .title(" Tags ")
-                .border_type(BorderType::Plain),
-        );
+    let tags = Paragraph::new(coerce_string_by_mode(
+        selected_command.tags_as_string(),
+        app,
+        &EditSelection::Tags,
+    ))
+    .style(Style::default().fg(Color::Rgb(
+        config.primary_color.unwrap().0,
+        config.primary_color.unwrap().1,
+        config.primary_color.unwrap().2,
+    )))
+    .alignment(Alignment::Left)
+    .block(
+        Block::default()
+            .borders(Borders::ALL)
+            .style(Style::default().fg(get_color(app, config, 
&EditSelection::Tags)))
+            .title(" Tags ")
+            .border_type(BorderType::Plain),
+    );
 
-    let description = 
Paragraph::new(selected_command.description.unwrap_or_default())
-        .style(Style::default().fg(Color::Rgb(
-            config.primary_color.unwrap().0,
-            config.primary_color.unwrap().1,
-            config.primary_color.unwrap().2,
-        )))
-        .alignment(Alignment::Left)
-        .wrap(Wrap { trim: true })
-        .block(
-            Block::default()
-                .borders(Borders::ALL)
-                .style(Style::default().fg(Color::Rgb(
-                    config.primary_color.unwrap().0,
-                    config.primary_color.unwrap().1,
-                    config.primary_color.unwrap().2,
-                )))
-                .title(" Description ")
-                .border_type(BorderType::Plain),
-        );
+    let description = Paragraph::new(coerce_string_by_mode(
+        selected_command.description.unwrap_or_default(),
+        app,
+        &EditSelection::Description,
+    ))
+    .style(Style::default().fg(Color::Rgb(
+        config.primary_color.unwrap().0,
+        config.primary_color.unwrap().1,
+        config.primary_color.unwrap().2,
+    )))
+    .alignment(Alignment::Left)
+    .wrap(Wrap { trim: true })
+    .block(
+        Block::default()
+            .borders(Borders::ALL)
+            .style(Style::default().fg(get_color(app, config, 
&EditSelection::Description)))
+            .title(" Description ")
+            .border_type(BorderType::Plain),
+    );
 
     let mut query_string = config.query_prefix.clone();
     query_string.push_str(&app.input.clone()[..]);
@@ -256,3 +315,10 @@
 
     (list, command, tags, description, input)
 }
+
+const fn get_footer_constraints(control_state: &ControlState) -> (u16, u16) {
+    match control_state {
+        ControlState::Search => (50, 50),
+        ControlState::Edit => (99, 1),
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/mod.rs 
new/hoard-1.3.0~0/src/gui/mod.rs
--- old/hoard-1.2.0~0/src/gui/mod.rs    2022-11-28 18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/src/gui/mod.rs    2022-12-21 14:06:28.000000000 +0100
@@ -3,8 +3,10 @@
 pub mod event;
 #[allow(clippy::module_name_repetitions)]
 mod help;
+mod inline_edit;
 mod list_search;
 pub mod merge;
+mod new_command;
 mod parameter_input;
 pub mod prompts;
 pub mod theme;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/new_command/controls.rs 
new/hoard-1.3.0~0/src/gui/new_command/controls.rs
--- old/hoard-1.2.0~0/src/gui/new_command/controls.rs   1970-01-01 
01:00:00.000000000 +0100
+++ new/hoard-1.3.0~0/src/gui/new_command/controls.rs   2022-12-21 
14:06:28.000000000 +0100
@@ -0,0 +1,87 @@
+use crate::command::hoard_command::{string_to_tags, HoardCommand};
+use crate::command::trove::CommandTrove;
+use crate::gui::commands_gui::{DrawState, EditSelection, State};
+use termion::event::Key;
+
+pub fn key_handler(input: Key, app: &mut State, default_namespace: &str) -> 
Option<HoardCommand> {
+    // Make sure there is an empty command set
+    if app.new_command.is_none() {
+        app.new_command = Some(HoardCommand::default());
+    }
+    match input {
+        Key::Esc => {
+            app.draw_state = DrawState::Search;
+            app.new_command = None;
+            app.edit_selection = EditSelection::Command;
+            None
+        }
+        // Quit command
+        Key::Ctrl('c' | 'd' | 'g') => {
+            app.should_exit = true;
+            app.new_command = None;
+            app.edit_selection = EditSelection::Command;
+            None
+        }
+        Key::Char('\n') => {
+            let mut command = app.new_command.clone().unwrap();
+            let parameter = app.input.clone();
+            app.error_message = match app.edit_selection {
+                EditSelection::Command => {
+                    let (_, msg) = HoardCommand::is_command_valid(&parameter);
+                    command.command = parameter;
+                    msg
+                }
+                EditSelection::Name => {
+                    let (_, mut msg) = HoardCommand::is_name_valid(&parameter);
+                    command.name = parameter;
+                    let trove = CommandTrove::from_commands(&app.commands);
+                    if trove.check_name_collision(&command).is_some() {
+                        msg = String::from(
+                            "Command with that name already exists in another 
namespace",
+                        );
+                    }
+                    msg
+                }
+                EditSelection::Namespace => {
+                    if parameter.is_empty() {
+                        command.namespace = default_namespace.into();
+                    } else {
+                        command.namespace = parameter;
+                    }
+                    String::new()
+                }
+                EditSelection::Description => {
+                    command.description = Some(parameter);
+                    String::new()
+                }
+                EditSelection::Tags => {
+                    let (is_valid, msg) = 
HoardCommand::are_tags_valid(&parameter);
+                    if is_valid {
+                        command.tags = Some(string_to_tags(&parameter));
+                    }
+                    msg
+                }
+            };
+            app.input = String::new();
+            if !app.error_message.is_empty() {
+                return None;
+            }
+            app.edit_selection = app.edit_selection.edit_next();
+            if app.edit_selection == EditSelection::Command {
+                return Some(command);
+            }
+            app.new_command = Some(command);
+            None
+        }
+        // Handle query input
+        Key::Backspace => {
+            app.input.pop();
+            None
+        }
+        Key::Char(c) => {
+            app.input.push(c);
+            None
+        }
+        _ => None,
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/new_command/mod.rs 
new/hoard-1.3.0~0/src/gui/new_command/mod.rs
--- old/hoard-1.2.0~0/src/gui/new_command/mod.rs        1970-01-01 
01:00:00.000000000 +0100
+++ new/hoard-1.3.0~0/src/gui/new_command/mod.rs        2022-12-21 
14:06:28.000000000 +0100
@@ -0,0 +1,2 @@
+pub mod controls;
+pub mod render;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/gui/new_command/render.rs 
new/hoard-1.3.0~0/src/gui/new_command/render.rs
--- old/hoard-1.2.0~0/src/gui/new_command/render.rs     1970-01-01 
01:00:00.000000000 +0100
+++ new/hoard-1.3.0~0/src/gui/new_command/render.rs     2022-12-21 
14:06:28.000000000 +0100
@@ -0,0 +1,80 @@
+use crate::config::HoardConfig;
+use crate::gui::commands_gui::State;
+use termion::screen::AlternateScreen;
+use tui::backend::TermionBackend;
+use tui::layout::{Constraint, Direction, Layout};
+use tui::style::{Color, Style};
+use tui::widgets::{Block, Paragraph};
+use tui::Terminal;
+
+pub fn draw(
+    app_state: &mut State,
+    config: &HoardConfig,
+    terminal: &mut Terminal<
+        
TermionBackend<AlternateScreen<termion::raw::RawTerminal<std::io::Stdout>>>,
+    >,
+    default_namespace: &str,
+) -> Result<(), eyre::Error> {
+    terminal.draw(|rect| {
+        let size = rect.size();
+        // Overlay
+        let overlay_chunks = Layout::default()
+            .direction(Direction::Vertical)
+            .margin(1)
+            .constraints(
+                [
+                    Constraint::Percentage(30),
+                    Constraint::Percentage(30),
+                    Constraint::Percentage(10),
+                    Constraint::Percentage(20),
+                    Constraint::Percentage(10),
+                ]
+                .as_ref(),
+            )
+            .split(size);
+
+        let mut query_string = config.query_prefix.clone();
+        query_string.push_str(&app_state.input.clone()[..]);
+        let title_string = format!("Provide {} for the command", 
app_state.edit_selection);
+
+        let command_style = Style::default().fg(Color::Rgb(
+            config.command_color.unwrap().0,
+            config.command_color.unwrap().1,
+            config.command_color.unwrap().2,
+        ));
+
+        let primary_style = Style::default().fg(Color::Rgb(
+            config.primary_color.unwrap().0,
+            config.primary_color.unwrap().1,
+            config.primary_color.unwrap().2,
+        ));
+
+        let input = Paragraph::new(query_string)
+            .style(primary_style)
+            .block(Block::default().style(command_style).title(title_string));
+        let new_command = app_state.new_command.clone().unwrap();
+        let command_render = format!(
+            "Command: {}\nNamespace: {}(\"{}\" if empty)\nName: 
{}\nDescription: {}\nTags: {}",
+            new_command.command,
+            new_command.namespace,
+            default_namespace,
+            new_command.name,
+            new_command.clone().description.unwrap_or_default(),
+            new_command.tags_as_string()
+        );
+        let new_command = Paragraph::new(command_render)
+            .style(primary_style)
+            .block(Block::default().style(command_style).title("New 
command:"));
+
+        let error_message = Paragraph::new(app_state.error_message.clone())
+            .style(primary_style)
+            .block(Block::default().style(command_style).title("Error:"));
+
+        rect.render_widget(new_command, overlay_chunks[1]);
+        rect.render_widget(input, overlay_chunks[2]);
+        if !app_state.error_message.is_empty() {
+            rect.render_widget(error_message, overlay_chunks[3]);
+        }
+    })?;
+    Ok(())
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/hoard.rs 
new/hoard-1.3.0~0/src/hoard.rs
--- old/hoard-1.2.0~0/src/hoard.rs      2022-11-28 18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/src/hoard.rs      2022-12-21 14:06:28.000000000 +0100
@@ -176,6 +176,7 @@
         } else {
             match commands_gui::run(&mut self.trove, 
self.config.as_ref().unwrap()) {
                 Ok(selected_command) => {
+                    self.save_trove(None);
                     if let Some(c) = selected_command {
                         // Is set if a command is selected in GUI
                         if !c.command.is_empty() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hoard-1.2.0~0/src/util.rs 
new/hoard-1.3.0~0/src/util.rs
--- old/hoard-1.2.0~0/src/util.rs       2022-11-28 18:38:14.000000000 +0100
+++ new/hoard-1.3.0~0/src/util.rs       2022-12-21 14:06:28.000000000 +0100
@@ -32,37 +32,30 @@
 }
 
 pub fn split_with_delim(s: &str, delim: &str) -> Vec<String> {
-    let mut result: Vec<String> = Vec::new();
-    let s: String = s.to_string();
-
-    let matched_indices: Vec<(usize, usize)> = s
-        .match_indices(delim)
-        .map(|(i, _)| (i, i + delim.len() - 1))
-        .collect();
-    let mut split_indices: Vec<(usize, usize)> = Vec::new();
-
-    // string starts with delimiter
-    if matched_indices.first().unwrap().0 != 0 {
-        split_indices.push((0, matched_indices.first().unwrap().0 - 1));
+    //Credits to chatGPT for simplifying this wtf
+    let mut result = Vec::new();
+    let mut start = 0;
+
+    for (i, _) in s.match_indices(delim) {
+        if i > start {
+            result.push(s[start..i].to_string());
+        }
+        result.push(delim.to_string());
+        start = i + delim.len();
     }
 
-    for (i, indices) in matched_indices.iter().enumerate() {
-        split_indices.push((indices.0, indices.1));
-        if let Some(peeked_index) = matched_indices.get(i + 1) {
-            split_indices.push((indices.1 + 1, peeked_index.0 - 1));
-        }
+    if start < s.len() {
+        result.push(s[start..].to_string());
     }
 
-    // Delimiter is at the end
-    if matched_indices.last().unwrap().1 != s.len() - 1 {
-        split_indices.push((matched_indices.last().unwrap().1 + 1, s.len() - 
1));
+    while result.first().map_or(false, std::string::String::is_empty) {
+        result.remove(0);
     }
 
-    // What the hell was I thinking
-    for (i, k) in &split_indices {
-        let slice = &s[(*i)..=(*k)];
-        result.push(slice.to_string());
+    while result.last().map_or(false, std::string::String::is_empty) {
+        result.pop();
     }
+
     result
 }
 

++++++ vendor.tar.xz ++++++
/work/SRC/openSUSE:Factory/hoard/vendor.tar.xz 
/work/SRC/openSUSE:Factory/.hoard.new.1835/vendor.tar.xz differ: char 26, line 1

Reply via email to