nu_explore/explore/
command.rs

1//! The explore command implementation.
2
3use crate::explore::config::ExploreConfig;
4use crate::explore::nu_common::create_lscolors;
5use crate::explore::pager::PagerConfig;
6use crate::explore::run_pager;
7use nu_ansi_term::Style;
8use nu_color_config::StyleComputer;
9use nu_engine::command_prelude::*;
10
11/// A `less` like program to render a [`Value`] as a table.
12#[derive(Clone)]
13pub struct Explore;
14
15impl Command for Explore {
16    fn name(&self) -> &str {
17        "explore"
18    }
19
20    fn description(&self) -> &str {
21        "Explore acts as a table pager, just like `less` does for text."
22    }
23
24    fn signature(&self) -> nu_protocol::Signature {
25        // todo: Fix error message when it's empty
26        // if we set h i short flags it panics????
27
28        Signature::build("explore")
29            .input_output_types(vec![(Type::Any, Type::Any)])
30            .named(
31                "head",
32                SyntaxShape::Boolean,
33                "Show or hide column headers (default true)",
34                None,
35            )
36            .switch("index", "Show row indexes when viewing a list", Some('i'))
37            .switch(
38                "tail",
39                "Start with the viewport scrolled to the bottom",
40                Some('t'),
41            )
42            .switch(
43                "peek",
44                "When quitting, output the value of the cell the cursor was on",
45                Some('p'),
46            )
47            .category(Category::Viewers)
48    }
49
50    fn extra_description(&self) -> &str {
51        r#"Press `:` then `h` to get a help menu."#
52    }
53
54    fn run(
55        &self,
56        engine_state: &EngineState,
57        stack: &mut Stack,
58        call: &Call,
59        input: PipelineData,
60    ) -> Result<PipelineData, ShellError> {
61        let show_head: bool = call.get_flag(engine_state, stack, "head")?.unwrap_or(true);
62        let show_index: bool = call.has_flag(engine_state, stack, "index")?;
63        let tail: bool = call.has_flag(engine_state, stack, "tail")?;
64        let peek_value: bool = call.has_flag(engine_state, stack, "peek")?;
65
66        let nu_config = stack.get_config(engine_state);
67        let style_computer = StyleComputer::from_config(engine_state, stack);
68
69        let mut explore_config = ExploreConfig::from_nu_config(&nu_config);
70        explore_config.table.show_header = show_head;
71        explore_config.table.show_index = show_index;
72        explore_config.table.separator_style = lookup_color(&style_computer, "separator");
73
74        let lscolors = create_lscolors(engine_state, stack);
75        let cwd = engine_state.cwd(Some(stack)).map_or(String::new(), |path| {
76            path.to_str().unwrap_or("").to_string()
77        });
78
79        let config = PagerConfig::new(
80            &nu_config,
81            &explore_config,
82            &style_computer,
83            &lscolors,
84            peek_value,
85            tail,
86            &cwd,
87        );
88
89        let result = run_pager(engine_state, &mut stack.clone(), input, config);
90
91        match result {
92            Ok(Some(value)) => Ok(PipelineData::value(value, None)),
93            Ok(None) => Ok(PipelineData::value(Value::default(), None)),
94            Err(err) => {
95                let shell_error = match err.downcast::<ShellError>() {
96                    Ok(e) => e,
97                    Err(e) => ShellError::GenericError {
98                        error: e.to_string(),
99                        msg: "".into(),
100                        span: None,
101                        help: None,
102                        inner: vec![],
103                    },
104                };
105
106                Ok(PipelineData::value(
107                    Value::error(shell_error, call.head),
108                    None,
109                ))
110            }
111        }
112    }
113
114    fn examples(&self) -> Vec<Example<'_>> {
115        vec![
116            Example {
117                description: "Explore the system host information record",
118                example: r#"sys host | explore"#,
119                result: None,
120            },
121            Example {
122                description: "Explore the output of `ls` without column names",
123                example: r#"ls | explore --head false"#,
124                result: None,
125            },
126            Example {
127                description: "Explore a list of Markdown files' contents, with row indexes",
128                example: r#"glob *.md | each {|| open } | explore --index"#,
129                result: None,
130            },
131            Example {
132                description: "Explore a JSON file, then save the last visited sub-structure to a file",
133                example: r#"open file.json | explore --peek | to json | save part.json"#,
134                result: None,
135            },
136        ]
137    }
138}
139
140fn lookup_color(style_computer: &StyleComputer, key: &str) -> Style {
141    style_computer.compute(key, &Value::nothing(Span::unknown()))
142}