Repository: ynqa/jnv (language: rust)

Issue:
Feature Request: Copy current JSON displayed
This would be very useful, for example when entering `.[].timestamp` copy the JSON shown:

<img width="249" alt="image" src="https://github.com/ynqa/jnv/assets/61319150/d3362572-43b8-49b9-90dc-27aa310d9b0e">



Discussion / hints:
Hey, more than that we could have 2 bindings:
- One for copying the highlighted one
- One for copying the whole output
Related crates
- https://github.com/1Password/arboard
- https://github.com/aweinstock314/rust-clipboard
I was close to creating a question or feature request, but here we are! Yeah, I definitely would like to see this feature as well. 😊

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 6c4778c..a5ad41f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -117,6 +117,12 @@ version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
 
+[[package]]
+name = "block"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -172,6 +178,28 @@ version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
 
+[[package]]
+name = "clipboard"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25a904646c0340239dcf7c51677b33928bf24fdf424b79a57909c0109075b2e7"
+dependencies = [
+ "clipboard-win",
+ "objc",
+ "objc-foundation",
+ "objc_id",
+ "x11-clipboard",
+]
+
+[[package]]
+name = "clipboard-win"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3a093d6fed558e5fe24c3dfc85a68bb68f1c824f440d3ba5aca189e2998786b"
+dependencies = [
+ "winapi",
+]
+
 [[package]]
 name = "colorchoice"
 version = "1.0.0"
@@ -359,6 +387,7 @@ version = "0.3.0"
 dependencies = [
  "anyhow",
  "clap",
+ "clipboard",
  "jaq-core",
  "jaq-interpret",
  "jaq-parse",
@@ -395,6 +424,15 @@ version = "0.4.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
 
+[[package]]
+name = "malloc_buf"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "memchr"
 version = "2.7.2"
@@ -428,6 +466,35 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
 
+[[package]]
+name = "objc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+dependencies = [
+ "malloc_buf",
+]
+
+[[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+dependencies = [
+ "block",
+ "objc",
+ "objc_id",
+]
+
+[[package]]
+name = "objc_id"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
+dependencies = [
+ "objc",
+]
+
 [[package]]
 name = "once_cell"
 version = "1.19.0"
@@ -474,9 +541,9 @@ dependencies = [
 
 [[package]]
 name = "promkit"
-version = "0.4.3"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e56210f382d72931a48f2e14013b7543cb4a2e524a70cf8924cf81ef8fa4f338"
+checksum = "9b38c2009e68f40ed01ab371eecc0a46307f2010458363966824799ff9b7caa8"
 dependencies = [
  "anyhow",
  "crossterm",
@@ -889,6 +956,25 @@ version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 
+[[package]]
+name = "x11-clipboard"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89bd49c06c9eb5d98e6ba6536cf64ac9f7ee3a009b2f53996d405b3944f6bcea"
+dependencies = [
+ "xcb",
+]
+
+[[package]]
+name = "xcb"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e917a3f24142e9ff8be2414e36c649d47d6cc2ba81f16201cdef96e533e02de"
+dependencies = [
+ "libc",
+ "log",
+]
+
 [[package]]
 name = "zerocopy"
 version = "0.7.32"
diff --git a/Cargo.toml b/Cargo.toml
index c89c896..acf3797 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,11 +11,12 @@ readme = "README.md"
 [dependencies]
 anyhow = "1.0.82"
 clap = { version = "4.5.4", features = ["derive"] }
+clipboard = "0.5.0"
 jaq-core = "1.2.1"
 jaq-interpret = "1.2.1"
 jaq-parse = "1.0.2"
 jaq-std = "1.2.1"
-promkit = "0.4.3"
+promkit = "0.4.5"
 radix_trie = "0.2.1"
 
 # The profile that 'cargo dist' will build with
diff --git a/src/jnv.rs b/src/jnv.rs
index 792b921..c8040d4 100644
--- a/src/jnv.rs
+++ b/src/jnv.rs
@@ -2,6 +2,7 @@ use std::cell::RefCell;
 
 use anyhow::Result;
 
+use clipboard::{ClipboardContext, ClipboardProvider};
 use jaq_interpret::{Ctx, FilterT, ParseCtx, RcIter, Val};
 
 use promkit::{
@@ -107,6 +108,7 @@ pub struct Jnv {
 
     json_expand_depth: Option<usize>,
     no_hint: bool,
+    clipboard: ClipboardContext
 }
 
 impl Jnv {
@@ -181,6 +183,7 @@ impl Jnv {
                 json_expand_depth,
                 no_hint,
                 input_stream,
+                clipboard: ClipboardProvider::new().unwrap()
             },
         })
     }
@@ -192,6 +195,33 @@ impl Jnv {
                 .replace(text::State { text, style })
         }
     }
+
+    fn content_to_clipboard(&mut self) {
+        let content = self.json.json_str();
+        let _ = self.clipboard.set_contents(content);
+
+        let clipboard_hint = String::from("Copied selected content to clipboard!");
+        let style = StyleBuilder::new()
+            .fgc(Color::Grey)
+            .attrs(Attributes::from(Attribute::Italic))
+            .build();
+
+        self.update_hint_message(clipboard_hint, style);
+    }
+
+    fn query_to_clipboard(&mut self) {
+        let query = self.filter_editor.after().texteditor.text_without_cursor().to_string();
+        let _ = self.clipboard.set_contents(query);
+
+        let clipboard_hint = String::from("Copied jq query to clipboard!");
+        let style = StyleBuilder::new()
+            .fgc(Color::Grey)
+            .attrs(Attributes::from(Attribute::Italic))
+            .build();
+
+        self.update_hint_message(clipboard_hint, style);
+    }
+
 }
 
 impl promkit::Finalizer for Jnv {
diff --git a/src/jnv/keymap.rs b/src/jnv/keymap.rs
index 08d4439..9d1a703 100644
--- a/src/jnv/keymap.rs
+++ b/src/jnv/keymap.rs
@@ -1,7 +1,5 @@
 use promkit::{
-    crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers},
-    listbox::Listbox,
-    text_editor, PromptSignal,
+    crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}, listbox::Listbox, text_editor, PromptSignal
 };
 
 pub type Keymap = fn(&Event, &mut crate::jnv::Jnv) -> anyhow::Result<PromptSignal>;
@@ -188,6 +186,24 @@ pub fn default(event: &Event, jnv: &mut crate::jnv::Jnv) -> anyhow::Result<Promp
             jnv.json.stream.expand_all();
         }
 
+        Event::Key(KeyEvent {
+            code: KeyCode::Char('o'),
+            modifiers: KeyModifiers::CONTROL,
+            kind: KeyEventKind::Press,
+            state: KeyEventState::NONE,
+        }) => {
+            jnv.content_to_clipboard();
+        }
+
+        Event::Key(KeyEvent {
+            code: KeyCode::Char('q'),
+            modifiers: KeyModifiers::CONTROL,
+            kind: KeyEventKind::Press,
+            state: KeyEventState::NONE,
+        }) => {
+            jnv.query_to_clipboard();
+        }
+
         Event::Key(KeyEvent {
             code: KeyCode::Char('n'),
             modifiers: KeyModifiers::CONTROL,


Test patch: