nu_command/platform/clip/
paste.rs1use super::clipboard::provider::{Clipboard, create_clipboard};
2use crate::{
3 platform::clip::get_config::get_clip_config_with_plugin_fallback, try_json_str_to_value,
4};
5use nu_engine::command_prelude::*;
6use nu_protocol::{Config, shell_error::generic::GenericError};
7
8#[derive(Clone)]
9pub struct ClipPaste;
10
11impl Command for ClipPaste {
12 fn name(&self) -> &str {
13 "clip paste"
14 }
15
16 fn signature(&self) -> Signature {
17 Signature::build(self.name())
18 .switch(
19 "raw",
20 "Disable JSON parsing. (act inverted if default_raw config is true).",
21 Some('r'),
22 )
23 .input_output_types(vec![(Type::Nothing, Type::Any)])
24 .category(Category::System)
25 }
26
27 fn description(&self) -> &str {
28 "Output the current clipboard content.
29 By default, it tries to parse clipboard content as JSON and outputs the corresponding Nushell value.
30 This behavior can be inverted using `$env.config.clip.default_raw = true`."
31 }
32 fn run(
33 &self,
34 engine_state: &EngineState,
35 stack: &mut Stack,
36 call: &Call,
37 _input: PipelineData,
38 ) -> Result<PipelineData, ShellError> {
39 let config = stack.get_config(engine_state);
40 let text = create_clipboard(&config, engine_state, stack).get_text()?;
41 if text.trim().is_empty() {
42 return Err(ShellError::Generic(GenericError::new(
43 "Clipboard is empty.",
44 "No text data is currently available in the clipboard.",
45 call.head,
46 )));
47 }
48
49 let default_raw = get_default_raw(&config, engine_state, stack);
50 if default_raw != call.has_flag(engine_state, stack, "raw")? {
51 return Ok(Value::string(text, call.head).into_pipeline_data());
52 }
53
54 let trimmed = text.trim_start();
55 if trimmed.starts_with('{') || trimmed.starts_with('[') || trimmed.starts_with('"') {
56 return match try_json_str_to_value(trimmed, call.head, false) {
57 Ok(value) => Ok(value.into_pipeline_data()),
58 Err(_) => Ok(Value::string(text, call.head).into_pipeline_data()),
59 };
60 }
61
62 Ok(Value::string(text, call.head).into_pipeline_data())
63 }
64
65 fn examples(&self) -> Vec<Example<'_>> {
66 vec![
67 Example {
68 example: "clip paste",
69 description: "Paste from clipboard and try to parse JSON.",
70 result: None,
71 },
72 Example {
73 example: "clip paste --raw",
74 description: "Paste raw clipboard text without JSON parsing.",
75 result: None,
76 },
77 ]
78 }
79}
80
81fn get_default_raw(config: &Config, engine_state: &EngineState, stack: &mut Stack) -> bool {
82 if config.clip.default_raw {
84 return true;
85 }
86 get_legacy_default_raw(get_clip_config_with_plugin_fallback(engine_state, stack).as_ref())
88}
89
90fn get_legacy_default_raw(value: Option<&Value>) -> bool {
91 match value {
92 Some(Value::Record { val, .. }) => {
93 if let Some(Value::Bool { val, .. }) = val
94 .get("DEFAULT_RAW")
95 .or_else(|| val.get("default_raw"))
96 .or_else(|| val.get("defaultRaw"))
97 {
98 return *val;
99 }
100 false
101 }
102 _ => false,
103 }
104}