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            engine_state,
93            &ShellWarning::Deprecated {
94                dep_type: "Moved Command".into(),
95                label: "Detecting types of tables is moved to `detect types`.".into(),
96                span: call.head,
97                help: Some("Use `update cells {detect type}` instead. In the future this will be a no-op for nushell native values.".into()),
98                report_mode: ReportMode::EveryUse,
99            },
100        );
101
102            let Some(block) = engine_state.try_get_block(*block_id) else {
103                return Err(ShellError::GenericError {
104                    error: "Block ID not found".into(),
105                    msg: format!("Block ID {} not found in this EngineState", block_id.get()),
106                    span: Some(call.head),
107                    help: Some("Make sure the same EngineState for IntoValue::add_deprecated_call was used here.".into()),
108                    inner: vec![],
109                });
110            };
111            let execution_data =
112                nu_engine::eval_block::<WithoutDebug>(engine_state, stack, block, input)?;
113            return Ok(execution_data.body);
114        }
115
116        Ok(input)
117    }
118}
119
120impl IntoValue {
121    // TODO: remove this method after deprecation phase
122    // This is a major hack to get the `update cell {detect type}` call possible without writing to
123    // much code that will be thrown away anyway.
124    pub fn add_deprecated_call(engine_state: &mut EngineState) {
125        let code = b"update cells {detect type}";
126        let mut working_set = StateWorkingSet::new(engine_state);
127        let block = nu_parser::parse(
128            &mut working_set,
129            Some("`into value` inner redirect"),
130            code,
131            false,
132        );
133        debug_assert!(
134            working_set.parse_errors.is_empty(),
135            "parsing `update cells {{detect type}}` errored"
136        );
137        debug_assert!(
138            working_set.compile_errors.is_empty(),
139            "compiling `update cells {{detect type}}` errored"
140        );
141        let block_id = working_set.add_block(block);
142        if engine_state.merge_delta(working_set.delta).is_err() {
143            log::error!("could not merge delta for deprecated redirect block of `into value`");
144            return;
145        }
146
147        if DEPRECATED_REDIRECT_BLOCK_ID.set(block_id).is_err() {
148            log::error!("could not set block id for deprecated redirect block of `into value`");
149        }
150    }
151}