[MVP][WIP] `less` like pager (#6984)
Run it as `explore`.
#### example
```nu
ls | explore
```
Configuration points in `config.nu` file.
```
# A 'explore' utility config
explore_config: {
highlight: { bg: 'yellow', fg: 'black' }
status_bar: { bg: '#C4C9C6', fg: '#1D1F21' }
command_bar: { fg: '#C4C9C6' }
split_line: '#404040'
cursor: true
# selected_column: 'blue'
# selected_row: { fg: 'yellow', bg: '#C1C2A3' }
# selected_cell: { fg: 'white', bg: '#777777' }
# line_shift: false,
# line_index: false,
# line_head_top: false,
# line_head_bottom: false,
}
```
You can start without a pipeline and type `explore` and it'll give you a
few tips.
![image](https://user-images.githubusercontent.com/343840/205088971-a8c0262f-f222-4641-b13a-027fbd4f5e1a.png)
If you type `:help` you an see the help screen with some information on
what tui keybindings are available.
![image](https://user-images.githubusercontent.com/343840/205089461-c4c54217-7ec4-4fa0-96c0-643d68dc0062.png)
From the `:help` screen you can now hit `i` and that puts you in
`cursor` aka `inspection` mode and you can move the cursor left right up
down and it you put it on an area such as `[table 5 rows]` and hit the
enter key, you'll see something like this, which shows all the `:`
commands. If you hit `esc` it will take you to the previous screen.
![image](https://user-images.githubusercontent.com/343840/205090155-3558a14b-87b7-4072-8dfb-dc8cc2ef4943.png)
If you then type `:try` you'll get this type of window where you can
type in the top portion and see results in the bottom.
![image](https://user-images.githubusercontent.com/343840/205089185-3c065551-0792-43d6-a13c-a52762856209.png)
The `:nu` command is interesting because you can type pipelines like
`:nu ls | sort-by type size` or another pipeline of your choosing such
as `:nu sys` and that will show the table that looks like this, which
we're calling "table mode".
![image](https://user-images.githubusercontent.com/343840/205090809-e686ff0f-6d0b-4347-8ed0-8c59adfbd741.png)
If you hit the `t` key it will now transpose the view to look like this.
![image](https://user-images.githubusercontent.com/343840/205090948-a834d7f2-1713-4dfe-92fe-5432f287df3d.png)
In table mode or transposed table mode you can use the `i` key to
inspect any collapsed field like `{record 8 fields}`, `[table 16 rows]`,
`[list x]`, etc.
One of the original benefits was that when you're in a view that has a
lot of columns, `explore` gives you the ability to scroll left, right,
up, and down.
`explore` is also smart enough to know when you're in table mode versus
preview mode. If you do `open Cargo.toml | explore` you get this.
![image](https://user-images.githubusercontent.com/343840/205091822-cac79130-3a52-4ca8-9210-eba5be30ed58.png)
If you type `open --raw Cargo.toml | explore` you get this where you can
scroll left, right, up, down. This is called preview mode.
![image](https://user-images.githubusercontent.com/343840/205091990-69455191-ab78-4fea-a961-feafafc16d70.png)
When you're in table mode, you can also type `:preview`. So, with `open
--raw Cargo.toml | explore`, if you type `:preview`, it will look like
this.
![image](https://user-images.githubusercontent.com/343840/205092569-436aa55a-0474-48d5-ab71-baddb1f43027.png)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2022-12-01 15:32:10 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
use nu_ansi_term::{Color, Style};
|
|
|
|
use nu_color_config::{get_color_config, get_color_map};
|
|
|
|
use nu_engine::CallExt;
|
|
|
|
use nu_explore::{StyleConfig, TableConfig, TableSplitLines, ViewConfig};
|
|
|
|
use nu_protocol::{
|
|
|
|
ast::Call,
|
|
|
|
engine::{Command, EngineState, Stack},
|
|
|
|
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
|
|
|
};
|
|
|
|
|
|
|
|
/// A `less` like program to render a [Value] as a table.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Explore;
|
|
|
|
|
|
|
|
impl Command for Explore {
|
|
|
|
fn name(&self) -> &str {
|
|
|
|
"explore"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn usage(&self) -> &str {
|
|
|
|
"Explore acts as a table pager, just like `less` does for text"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn signature(&self) -> nu_protocol::Signature {
|
|
|
|
// todo: Fix error message when it's empty
|
|
|
|
// if we set h i short flags it panics????
|
|
|
|
|
|
|
|
Signature::build("explore")
|
|
|
|
.named(
|
|
|
|
"head",
|
|
|
|
SyntaxShape::Boolean,
|
|
|
|
"Setting it to false makes it doesn't show column headers",
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
.switch("index", "A flag to show a index beside the rows", Some('i'))
|
|
|
|
.switch(
|
|
|
|
"reverse",
|
|
|
|
"Makes it start from the end. (like `more`)",
|
|
|
|
Some('r'),
|
|
|
|
)
|
|
|
|
.switch("peek", "Return a last seen cell content", Some('p'))
|
|
|
|
.category(Category::Viewers)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn extra_usage(&self) -> &str {
|
|
|
|
r#"Press <:> then <h> to get a help menu."#
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run(
|
|
|
|
&self,
|
|
|
|
engine_state: &EngineState,
|
|
|
|
stack: &mut Stack,
|
|
|
|
call: &Call,
|
|
|
|
input: PipelineData,
|
|
|
|
) -> Result<PipelineData, ShellError> {
|
|
|
|
let show_head: bool = call.get_flag(engine_state, stack, "head")?.unwrap_or(true);
|
|
|
|
let show_index: bool = call.has_flag("index");
|
|
|
|
let is_reverse: bool = call.has_flag("reverse");
|
|
|
|
let peek_value: bool = call.has_flag("peek");
|
|
|
|
let table_cfg = TableConfig {
|
|
|
|
show_index,
|
|
|
|
show_head,
|
|
|
|
peek_value,
|
|
|
|
reverse: is_reverse,
|
|
|
|
show_help: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
let ctrlc = engine_state.ctrlc.clone();
|
|
|
|
|
|
|
|
let config = engine_state.get_config();
|
|
|
|
let color_hm = get_color_config(config);
|
2022-12-02 06:42:18 +00:00
|
|
|
let style = theme_from_config(&config.explore);
|
[MVP][WIP] `less` like pager (#6984)
Run it as `explore`.
#### example
```nu
ls | explore
```
Configuration points in `config.nu` file.
```
# A 'explore' utility config
explore_config: {
highlight: { bg: 'yellow', fg: 'black' }
status_bar: { bg: '#C4C9C6', fg: '#1D1F21' }
command_bar: { fg: '#C4C9C6' }
split_line: '#404040'
cursor: true
# selected_column: 'blue'
# selected_row: { fg: 'yellow', bg: '#C1C2A3' }
# selected_cell: { fg: 'white', bg: '#777777' }
# line_shift: false,
# line_index: false,
# line_head_top: false,
# line_head_bottom: false,
}
```
You can start without a pipeline and type `explore` and it'll give you a
few tips.
![image](https://user-images.githubusercontent.com/343840/205088971-a8c0262f-f222-4641-b13a-027fbd4f5e1a.png)
If you type `:help` you an see the help screen with some information on
what tui keybindings are available.
![image](https://user-images.githubusercontent.com/343840/205089461-c4c54217-7ec4-4fa0-96c0-643d68dc0062.png)
From the `:help` screen you can now hit `i` and that puts you in
`cursor` aka `inspection` mode and you can move the cursor left right up
down and it you put it on an area such as `[table 5 rows]` and hit the
enter key, you'll see something like this, which shows all the `:`
commands. If you hit `esc` it will take you to the previous screen.
![image](https://user-images.githubusercontent.com/343840/205090155-3558a14b-87b7-4072-8dfb-dc8cc2ef4943.png)
If you then type `:try` you'll get this type of window where you can
type in the top portion and see results in the bottom.
![image](https://user-images.githubusercontent.com/343840/205089185-3c065551-0792-43d6-a13c-a52762856209.png)
The `:nu` command is interesting because you can type pipelines like
`:nu ls | sort-by type size` or another pipeline of your choosing such
as `:nu sys` and that will show the table that looks like this, which
we're calling "table mode".
![image](https://user-images.githubusercontent.com/343840/205090809-e686ff0f-6d0b-4347-8ed0-8c59adfbd741.png)
If you hit the `t` key it will now transpose the view to look like this.
![image](https://user-images.githubusercontent.com/343840/205090948-a834d7f2-1713-4dfe-92fe-5432f287df3d.png)
In table mode or transposed table mode you can use the `i` key to
inspect any collapsed field like `{record 8 fields}`, `[table 16 rows]`,
`[list x]`, etc.
One of the original benefits was that when you're in a view that has a
lot of columns, `explore` gives you the ability to scroll left, right,
up, and down.
`explore` is also smart enough to know when you're in table mode versus
preview mode. If you do `open Cargo.toml | explore` you get this.
![image](https://user-images.githubusercontent.com/343840/205091822-cac79130-3a52-4ca8-9210-eba5be30ed58.png)
If you type `open --raw Cargo.toml | explore` you get this where you can
scroll left, right, up, down. This is called preview mode.
![image](https://user-images.githubusercontent.com/343840/205091990-69455191-ab78-4fea-a961-feafafc16d70.png)
When you're in table mode, you can also type `:preview`. So, with `open
--raw Cargo.toml | explore`, if you type `:preview`, it will look like
this.
![image](https://user-images.githubusercontent.com/343840/205092569-436aa55a-0474-48d5-ab71-baddb1f43027.png)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2022-12-01 15:32:10 +00:00
|
|
|
|
|
|
|
let view_cfg = ViewConfig::new(config, &color_hm, &style);
|
|
|
|
|
|
|
|
let result = nu_explore::run_pager(engine_state, stack, ctrlc, table_cfg, view_cfg, input);
|
|
|
|
|
|
|
|
match result {
|
|
|
|
Ok(Some(value)) => Ok(PipelineData::Value(value, None)),
|
|
|
|
Ok(None) => Ok(PipelineData::Value(Value::default(), None)),
|
|
|
|
Err(err) => Ok(PipelineData::Value(
|
|
|
|
Value::Error { error: err.into() },
|
|
|
|
None,
|
|
|
|
)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn examples(&self) -> Vec<Example> {
|
|
|
|
vec![
|
|
|
|
Example {
|
|
|
|
description: "List the files in current directory, an looking at them via explore.",
|
|
|
|
example: r#"ls | explore"#,
|
|
|
|
result: None,
|
|
|
|
},
|
|
|
|
Example {
|
|
|
|
description: "Inspect system information (explore with index).",
|
|
|
|
example: r#"sys | explore -i"#,
|
|
|
|
result: None,
|
|
|
|
},
|
|
|
|
Example {
|
|
|
|
description: "Inspect $nu information (explore with no column names).",
|
|
|
|
example: r#"$nu | explore --head false"#,
|
|
|
|
result: None,
|
|
|
|
},
|
|
|
|
Example {
|
|
|
|
description: "Inspect $nu information and return an entity where you've stopped.",
|
|
|
|
example: r#"$nu | explore --peek"#,
|
|
|
|
result: None,
|
|
|
|
},
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn theme_from_config(config: &HashMap<String, Value>) -> StyleConfig {
|
|
|
|
let colors = get_color_map(config);
|
|
|
|
|
|
|
|
let mut style = default_style();
|
|
|
|
|
|
|
|
if let Some(s) = colors.get("status_bar") {
|
|
|
|
style.status_bar = *s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(s) = colors.get("command_bar") {
|
|
|
|
style.cmd_bar = *s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(s) = colors.get("split_line") {
|
|
|
|
style.split_line = *s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(s) = colors.get("highlight") {
|
|
|
|
style.highlight = *s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(s) = colors.get("selected_cell") {
|
|
|
|
style.selected_cell = Some(*s);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(s) = colors.get("selected_row") {
|
|
|
|
style.selected_row = Some(*s);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(s) = colors.get("selected_column") {
|
|
|
|
style.selected_column = Some(*s);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(show_cursor) = config.get("cursor").and_then(|v| v.as_bool().ok()) {
|
|
|
|
style.show_cursow = show_cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(b) = config.get("line_head_top").and_then(|v| v.as_bool().ok()) {
|
|
|
|
style.split_lines.header_top = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(b) = config
|
|
|
|
.get("line_head_bottom")
|
|
|
|
.and_then(|v| v.as_bool().ok())
|
|
|
|
{
|
|
|
|
style.split_lines.header_bottom = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(b) = config.get("line_shift").and_then(|v| v.as_bool().ok()) {
|
|
|
|
style.split_lines.shift_line = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(b) = config.get("line_index").and_then(|v| v.as_bool().ok()) {
|
|
|
|
style.split_lines.index_line = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
style
|
|
|
|
}
|
|
|
|
|
|
|
|
fn default_style() -> StyleConfig {
|
|
|
|
StyleConfig {
|
|
|
|
status_bar: Style {
|
|
|
|
background: Some(Color::Rgb(196, 201, 198)),
|
|
|
|
foreground: Some(Color::Rgb(29, 31, 33)),
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
highlight: Style {
|
|
|
|
background: Some(Color::Yellow),
|
|
|
|
foreground: Some(Color::Black),
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
split_line: Style {
|
|
|
|
foreground: Some(Color::Rgb(64, 64, 64)),
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
cmd_bar: Style {
|
|
|
|
foreground: Some(Color::Rgb(196, 201, 198)),
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
status_error: Style {
|
|
|
|
background: Some(Color::Red),
|
|
|
|
foreground: Some(Color::White),
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
status_info: Style::default(),
|
|
|
|
status_warn: Style::default(),
|
|
|
|
selected_cell: None,
|
|
|
|
selected_column: None,
|
|
|
|
selected_row: None,
|
|
|
|
show_cursow: true,
|
|
|
|
split_lines: TableSplitLines {
|
|
|
|
header_bottom: true,
|
|
|
|
header_top: true,
|
|
|
|
index_line: true,
|
|
|
|
shift_line: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|