Skip to main content

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