nu_command/platform/clip/
paste.rs1use super::clipboard::provider::{Clipboard, create_clipboard};
2use crate::{
3 convert_json_string_to_value, platform::clip::get_config::get_clip_config_with_plugin_fallback,
4};
5use nu_engine::command_prelude::*;
6use nu_protocol::Config;
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::GenericError {
43 error: "Clipboard is empty.".into(),
44 msg: "No text data is currently available in the clipboard.".into(),
45 span: Some(call.head),
46 help: None,
47 inner: vec![],
48 });
49 }
50
51 let default_raw = get_default_raw(&config, engine_state, stack);
52 if default_raw != call.has_flag(engine_state, stack, "raw")? {
53 return Ok(Value::string(text, call.head).into_pipeline_data());
54 }
55
56 let trimmed = text.trim_start();
57 if trimmed.starts_with('{') || trimmed.starts_with('[') || trimmed.starts_with('"') {
58 return match convert_json_string_to_value(trimmed, call.head) {
59 Ok(value) => Ok(value.into_pipeline_data()),
60 Err(_) => Ok(Value::string(text, call.head).into_pipeline_data()),
61 };
62 }
63
64 Ok(Value::string(text, call.head).into_pipeline_data())
65 }
66
67 fn examples(&self) -> Vec<Example<'_>> {
68 vec![
69 Example {
70 example: "clip paste",
71 description: "Paste from clipboard and try to parse JSON.",
72 result: None,
73 },
74 Example {
75 example: "clip paste --raw",
76 description: "Paste raw clipboard text without JSON parsing.",
77 result: None,
78 },
79 ]
80 }
81}
82
83fn get_default_raw(config: &Config, engine_state: &EngineState, stack: &mut Stack) -> bool {
84 if config.clip.default_raw {
86 return true;
87 }
88 get_legacy_default_raw(get_clip_config_with_plugin_fallback(engine_state, stack).as_ref())
90}
91
92fn get_legacy_default_raw(value: Option<&Value>) -> bool {
93 match value {
94 Some(Value::Record { val, .. }) => {
95 if let Some(Value::Bool { val, .. }) = val
96 .get("DEFAULT_RAW")
97 .or_else(|| val.get("default_raw"))
98 .or_else(|| val.get("defaultRaw"))
99 {
100 return *val;
101 }
102 false
103 }
104 _ => false,
105 }
106}