nu_command/conversions/into/
value.rs

1use std::sync::OnceLock;
2
3use nu_engine::command_prelude::*;
4use nu_protocol::{
5    BlockId, DeprecationEntry, DeprecationType, ReportMode, debugger::WithoutDebug,
6    report_shell_warning,
7};
8
9// TODO: remove this after deprecation phase
10static DEPRECATED_REDIRECT_BLOCK_ID: OnceLock<BlockId> = OnceLock::new();
11
12#[derive(Clone)]
13pub struct IntoValue;
14
15impl Command for IntoValue {
16    fn name(&self) -> &str {
17        "into value"
18    }
19
20    fn signature(&self) -> Signature {
21        Signature::build(self.name())
22            .description(self.description())
23            .extra_description(self.extra_description())
24            .input_output_type(Type::Any, Type::Any)
25            .category(Category::Conversions)
26            // TODO: remove these after deprecation phase
27            .named(
28                "columns",
29                SyntaxShape::List(Box::new(SyntaxShape::Any)),
30                "list of columns to update",
31                Some('c'),
32            )
33            .switch(
34                "prefer-filesizes",
35                "For ints display them as human-readable file sizes",
36                Some('f'),
37            )
38    }
39
40    fn deprecation_info(&self) -> Vec<DeprecationEntry> {
41        vec![
42            DeprecationEntry {
43                ty: DeprecationType::Flag("columns".to_string()),
44                report_mode: ReportMode::EveryUse,
45                since: Some("0.108.0".into()),
46                expected_removal: Some("0.109.0".into()),
47                help: Some("Use this flag on `detect type`.".into()),
48            },
49            DeprecationEntry {
50                ty: DeprecationType::Flag("prefer-filesizes".to_string()),
51                report_mode: ReportMode::EveryUse,
52                since: Some("0.108.0".into()),
53                expected_removal: Some("0.109.0".into()),
54                help: Some("Use this flag on `detect type`.".into()),
55            },
56        ]
57    }
58
59    fn description(&self) -> &str {
60        "Convert custom values into base values."
61    }
62
63    fn extra_description(&self) -> &str {
64        "Custom values from plugins have a base value representation. \
65        This extracts that base value representation. \
66        For streams use `collect`."
67    }
68
69    fn search_terms(&self) -> Vec<&str> {
70        vec!["custom", "base", "convert", "conversion"]
71    }
72
73    fn examples(&self) -> Vec<Example<'_>> {
74        vec![]
75    }
76
77    fn run(
78        &self,
79        engine_state: &EngineState,
80        stack: &mut Stack,
81        call: &Call,
82        input: PipelineData,
83    ) -> Result<PipelineData, ShellError> {
84        if let PipelineData::Value(v @ Value::Custom { .. }, metadata) = input {
85            let span = v.span();
86            let val = v.into_custom_value()?;
87            return Ok(PipelineData::value(val.to_base_value(span)?, metadata));
88        }
89
90        if let Some(block_id) = DEPRECATED_REDIRECT_BLOCK_ID.get() {
91            report_shell_warning(
92            Some(stack),
93            engine_state,
94            &ShellWarning::Deprecated {
95                dep_type: "Moved Command".into(),
96                label: "Detecting types of tables is moved to `detect types`.".into(),
97                span: call.head,
98                help: Some("Use `update cells {detect type}` instead. In the future this will be a no-op for nushell native values.".into()),
99                report_mode: ReportMode::EveryUse,
100            },
101        );
102
103            let Some(block) = engine_state.try_get_block(*block_id) else {
104                return Err(ShellError::GenericError {
105                    error: "Block ID not found".into(),
106                    msg: format!("Block ID {} not found in this EngineState", block_id.get()),
107                    span: Some(call.head),
108                    help: Some("Make sure the same EngineState for IntoValue::add_deprecated_call was used here.".into()),
109                    inner: vec![],
110                });
111            };
112            let execution_data =
113                nu_engine::eval_block::<WithoutDebug>(engine_state, stack, block, input)?;
114            return Ok(execution_data.body);
115        }
116
117        Ok(input)
118    }
119}
120
121impl IntoValue {
122    // TODO: remove this method after deprecation phase
123    // This is a major hack to get the `update cell {detect type}` call possible without writing to
124    // much code that will be thrown away anyway.
125    pub fn add_deprecated_call(engine_state: &mut EngineState) {
126        let code = b"update cells {detect type}";
127        let mut working_set = StateWorkingSet::new(engine_state);
128        let block = nu_parser::parse(
129            &mut working_set,
130            Some("`into value` inner redirect"),
131            code,
132            false,
133        );
134        debug_assert!(
135            working_set.parse_errors.is_empty(),
136            "parsing `update cells {{detect type}}` errored"
137        );
138        debug_assert!(
139            working_set.compile_errors.is_empty(),
140            "compiling `update cells {{detect type}}` errored"
141        );
142        let block_id = working_set.add_block(block);
143        if engine_state.merge_delta(working_set.delta).is_err() {
144            log::error!("could not merge delta for deprecated redirect block of `into value`");
145            return;
146        }
147
148        if DEPRECATED_REDIRECT_BLOCK_ID.set(block_id).is_err() {
149            log::error!("could not set block id for deprecated redirect block of `into value`");
150        }
151    }
152}