mirror of
https://github.com/nushell/nushell.git
synced 2024-11-21 16:03:19 +01:00
Overhaul explore
config (#13075)
Configuration in `explore` has always been confusing to me. This PR overhauls (and simplifies, I think) how configuration is done. # Details 1. Configuration is now strongly typed. In `Explore::run()` we create an `ExploreConfig` struct from the more general Nu configuration and arguments to `explore`, then pass that struct to other parts of `explore` that need configuration. IMO this is a lot easier to reason about and trace than the previous approach of creating a `HashMap<String, Value>` and then using that to make various structs elsewhere. 2. We now inherit more configuration from the config used for regular Nu tables 1. Border/line styling now uses the `separator` style used for regular Nu tables, the special `explore.split_line` config point has been retired. 2. Cell padding in tables is now controlled by `table.padding` instead of the undocumented `column_padding_left`/`column_padding_right` config 3. The (optional, previously not enabled by default) `selected_row` and `selected_column` configuration has been removed. We now only highlight the selected cell. I could re-add this if people really like the feature but I'm guessing nobody uses it. The interface still looks the same with a default/empty config.nu: ![image](https://github.com/nushell/nushell/assets/26268125/e40161ba-a8ec-407a-932d-5ece6f4dc616)
This commit is contained in:
parent
5d163c1bcc
commit
f2f4b83886
@ -4,7 +4,6 @@ use crate::{
|
||||
views::{Orientation, RecordView},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use nu_ansi_term::Style;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Value,
|
||||
@ -19,12 +18,6 @@ pub struct TableCmd {
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct TableSettings {
|
||||
orientation: Option<Orientation>,
|
||||
split_line_s: Option<Style>,
|
||||
selected_cell_s: Option<Style>,
|
||||
selected_row_s: Option<Style>,
|
||||
selected_column_s: Option<Style>,
|
||||
padding_column_left: Option<usize>,
|
||||
padding_column_right: Option<usize>,
|
||||
turn_on_cursor_mode: bool,
|
||||
}
|
||||
|
||||
@ -64,8 +57,6 @@ impl ViewCommand for TableCmd {
|
||||
|
||||
let mut view = RecordView::new(columns, data);
|
||||
|
||||
// todo: use setup instead ????
|
||||
|
||||
if is_record {
|
||||
view.set_orientation_current(Orientation::Left);
|
||||
}
|
||||
@ -74,32 +65,6 @@ impl ViewCommand for TableCmd {
|
||||
view.set_orientation_current(o);
|
||||
}
|
||||
|
||||
if let Some(style) = self.settings.selected_cell_s {
|
||||
view.set_style_selected_cell(style);
|
||||
}
|
||||
|
||||
if let Some(style) = self.settings.selected_column_s {
|
||||
view.set_style_selected_column(style);
|
||||
}
|
||||
|
||||
if let Some(style) = self.settings.selected_row_s {
|
||||
view.set_style_selected_row(style);
|
||||
}
|
||||
|
||||
if let Some(style) = self.settings.split_line_s {
|
||||
view.set_style_split_line(style);
|
||||
}
|
||||
|
||||
if let Some(p) = self.settings.padding_column_left {
|
||||
let c = view.get_padding_column();
|
||||
view.set_padding_column((p, c.1))
|
||||
}
|
||||
|
||||
if let Some(p) = self.settings.padding_column_right {
|
||||
let c = view.get_padding_column();
|
||||
view.set_padding_column((c.0, p))
|
||||
}
|
||||
|
||||
if self.settings.turn_on_cursor_mode {
|
||||
view.set_cursor_mode();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::ViewCommand;
|
||||
use crate::views::InteractiveView;
|
||||
use crate::views::TryView;
|
||||
use anyhow::Result;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
@ -22,7 +22,7 @@ impl TryCmd {
|
||||
}
|
||||
|
||||
impl ViewCommand for TryCmd {
|
||||
type View = InteractiveView<'static>;
|
||||
type View = TryView<'static>;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
Self::NAME
|
||||
@ -45,7 +45,7 @@ impl ViewCommand for TryCmd {
|
||||
value: Option<Value>,
|
||||
) -> Result<Self::View> {
|
||||
let value = value.unwrap_or_default();
|
||||
let mut view = InteractiveView::new(value);
|
||||
let mut view = TryView::new(value);
|
||||
view.init(self.command.clone());
|
||||
view.try_run(engine_state, stack)?;
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
use crate::{
|
||||
run_pager,
|
||||
util::{create_lscolors, create_map, map_into_value},
|
||||
PagerConfig, StyleConfig,
|
||||
util::{create_lscolors, create_map},
|
||||
PagerConfig,
|
||||
};
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use nu_color_config::{get_color_map, StyleComputer};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use nu_protocol::Config;
|
||||
|
||||
/// A `less` like program to render a [`Value`] as a table.
|
||||
#[derive(Clone)]
|
||||
@ -68,19 +67,21 @@ impl Command for Explore {
|
||||
let nu_config = engine_state.get_config();
|
||||
let style_computer = StyleComputer::from_config(engine_state, stack);
|
||||
|
||||
let mut config = nu_config.explore.clone();
|
||||
include_nu_config(&mut config, &style_computer);
|
||||
update_config(&mut config, show_index, show_head);
|
||||
prepare_default_config(&mut config);
|
||||
|
||||
let style = style_from_config(&config);
|
||||
let mut explore_config = ExploreConfig::from_nu_config(nu_config);
|
||||
explore_config.table.show_header = show_head;
|
||||
explore_config.table.show_index = show_index;
|
||||
explore_config.table.separator_style = lookup_color(&style_computer, "separator");
|
||||
|
||||
let lscolors = create_lscolors(engine_state, stack);
|
||||
|
||||
let mut config = PagerConfig::new(nu_config, &style_computer, &lscolors, config);
|
||||
config.style = style;
|
||||
config.peek_value = peek_value;
|
||||
config.tail = tail;
|
||||
let config = PagerConfig::new(
|
||||
nu_config,
|
||||
&explore_config,
|
||||
&style_computer,
|
||||
&lscolors,
|
||||
peek_value,
|
||||
tail,
|
||||
);
|
||||
|
||||
let result = run_pager(engine_state, &mut stack.clone(), ctrlc, input, config);
|
||||
|
||||
@ -134,153 +135,118 @@ impl Command for Explore {
|
||||
}
|
||||
}
|
||||
|
||||
fn update_config(config: &mut HashMap<String, Value>, show_index: bool, show_head: bool) {
|
||||
let mut hm = config.get("table").and_then(create_map).unwrap_or_default();
|
||||
if show_index {
|
||||
insert_bool(&mut hm, "show_index", show_index);
|
||||
}
|
||||
|
||||
if show_head {
|
||||
insert_bool(&mut hm, "show_head", show_head);
|
||||
}
|
||||
|
||||
config.insert(String::from("table"), map_into_value(hm));
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExploreConfig {
|
||||
pub table: TableConfig,
|
||||
pub selected_cell: Style,
|
||||
pub status_info: Style,
|
||||
pub status_success: Style,
|
||||
pub status_warn: Style,
|
||||
pub status_error: Style,
|
||||
pub status_bar_background: Style,
|
||||
pub status_bar_text: Style,
|
||||
pub cmd_bar_text: Style,
|
||||
pub cmd_bar_background: Style,
|
||||
pub highlight: Style,
|
||||
/// if true, the explore view will immediately try to run the command as it is typed
|
||||
pub try_reactive: bool,
|
||||
}
|
||||
|
||||
fn style_from_config(config: &HashMap<String, Value>) -> StyleConfig {
|
||||
let mut style = StyleConfig::default();
|
||||
|
||||
let colors = get_color_map(config);
|
||||
|
||||
if let Some(s) = colors.get("status_bar_text") {
|
||||
style.status_bar_text = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("status_bar_background") {
|
||||
style.status_bar_background = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("command_bar_text") {
|
||||
style.cmd_bar_text = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("command_bar_background") {
|
||||
style.cmd_bar_background = *s;
|
||||
}
|
||||
|
||||
if let Some(hm) = config.get("status").and_then(create_map) {
|
||||
let colors = get_color_map(&hm);
|
||||
|
||||
if let Some(s) = colors.get("info") {
|
||||
style.status_info = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("success") {
|
||||
style.status_success = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("warn") {
|
||||
style.status_warn = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("error") {
|
||||
style.status_error = *s;
|
||||
impl Default for ExploreConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
table: TableConfig::default(),
|
||||
selected_cell: color(None, Some(Color::LightBlue)),
|
||||
status_info: color(None, None),
|
||||
status_success: color(Some(Color::Black), Some(Color::Green)),
|
||||
status_warn: color(None, None),
|
||||
status_error: color(Some(Color::White), Some(Color::Red)),
|
||||
status_bar_background: color(
|
||||
Some(Color::Rgb(29, 31, 33)),
|
||||
Some(Color::Rgb(196, 201, 198)),
|
||||
),
|
||||
status_bar_text: color(None, None),
|
||||
cmd_bar_text: color(Some(Color::Rgb(196, 201, 198)), None),
|
||||
cmd_bar_background: color(None, None),
|
||||
highlight: color(Some(Color::Black), Some(Color::Yellow)),
|
||||
try_reactive: false,
|
||||
}
|
||||
}
|
||||
|
||||
style
|
||||
}
|
||||
impl ExploreConfig {
|
||||
/// take the default explore config and update it with relevant values from the nu config
|
||||
pub fn from_nu_config(config: &Config) -> Self {
|
||||
let mut ret = Self::default();
|
||||
|
||||
fn prepare_default_config(config: &mut HashMap<String, Value>) {
|
||||
const STATUS_BAR: Style = color(
|
||||
Some(Color::Rgb(29, 31, 33)),
|
||||
Some(Color::Rgb(196, 201, 198)),
|
||||
);
|
||||
const INPUT_BAR: Style = color(Some(Color::Rgb(196, 201, 198)), None);
|
||||
ret.table.column_padding_left = config.table_indent.left;
|
||||
ret.table.column_padding_right = config.table_indent.right;
|
||||
|
||||
const HIGHLIGHT: Style = color(Some(Color::Black), Some(Color::Yellow));
|
||||
let explore_cfg_hash_map = config.explore.clone();
|
||||
let colors = get_color_map(&explore_cfg_hash_map);
|
||||
|
||||
const STATUS_ERROR: Style = color(Some(Color::White), Some(Color::Red));
|
||||
const STATUS_INFO: Style = color(None, None);
|
||||
const STATUS_SUCCESS: Style = color(Some(Color::Black), Some(Color::Green));
|
||||
const STATUS_WARN: Style = color(None, None);
|
||||
if let Some(s) = colors.get("status_bar_text") {
|
||||
ret.status_bar_text = *s;
|
||||
}
|
||||
|
||||
const TABLE_SPLIT_LINE: Style = color(Some(Color::Rgb(64, 64, 64)), None);
|
||||
const TABLE_SELECT_CELL: Style = color(None, None);
|
||||
const TABLE_SELECT_ROW: Style = color(None, None);
|
||||
const TABLE_SELECT_COLUMN: Style = color(None, None);
|
||||
if let Some(s) = colors.get("status_bar_background") {
|
||||
ret.status_bar_background = *s;
|
||||
}
|
||||
|
||||
const HEXDUMP_INDEX: Style = color(Some(Color::Cyan), None);
|
||||
const HEXDUMP_SEGMENT: Style = color(Some(Color::Cyan), None).bold();
|
||||
const HEXDUMP_SEGMENT_ZERO: Style = color(Some(Color::Purple), None).bold();
|
||||
const HEXDUMP_SEGMENT_UNKNOWN: Style = color(Some(Color::Green), None).bold();
|
||||
const HEXDUMP_ASCII: Style = color(Some(Color::Cyan), None).bold();
|
||||
const HEXDUMP_ASCII_ZERO: Style = color(Some(Color::Purple), None).bold();
|
||||
const HEXDUMP_ASCII_UNKNOWN: Style = color(Some(Color::Green), None).bold();
|
||||
if let Some(s) = colors.get("command_bar_text") {
|
||||
ret.cmd_bar_text = *s;
|
||||
}
|
||||
|
||||
insert_style(config, "status_bar_background", STATUS_BAR);
|
||||
insert_style(config, "command_bar_text", INPUT_BAR);
|
||||
insert_style(config, "highlight", HIGHLIGHT);
|
||||
if let Some(s) = colors.get("command_bar_background") {
|
||||
ret.cmd_bar_background = *s;
|
||||
}
|
||||
|
||||
// because how config works we need to parse a string into Value::Record
|
||||
if let Some(s) = colors.get("command_bar_background") {
|
||||
ret.cmd_bar_background = *s;
|
||||
}
|
||||
|
||||
{
|
||||
let mut hm = config
|
||||
.get("status")
|
||||
.and_then(parse_hash_map)
|
||||
.unwrap_or_default();
|
||||
if let Some(s) = colors.get("selected_cell") {
|
||||
ret.selected_cell = *s;
|
||||
}
|
||||
|
||||
insert_style(&mut hm, "info", STATUS_INFO);
|
||||
insert_style(&mut hm, "success", STATUS_SUCCESS);
|
||||
insert_style(&mut hm, "warn", STATUS_WARN);
|
||||
insert_style(&mut hm, "error", STATUS_ERROR);
|
||||
if let Some(hm) = explore_cfg_hash_map.get("status").and_then(create_map) {
|
||||
let colors = get_color_map(&hm);
|
||||
|
||||
config.insert(String::from("status"), map_into_value(hm));
|
||||
}
|
||||
if let Some(s) = colors.get("info") {
|
||||
ret.status_info = *s;
|
||||
}
|
||||
|
||||
{
|
||||
let mut hm = config
|
||||
.get("table")
|
||||
.and_then(parse_hash_map)
|
||||
.unwrap_or_default();
|
||||
if let Some(s) = colors.get("success") {
|
||||
ret.status_success = *s;
|
||||
}
|
||||
|
||||
insert_style(&mut hm, "split_line", TABLE_SPLIT_LINE);
|
||||
insert_style(&mut hm, "selected_cell", TABLE_SELECT_CELL);
|
||||
insert_style(&mut hm, "selected_row", TABLE_SELECT_ROW);
|
||||
insert_style(&mut hm, "selected_column", TABLE_SELECT_COLUMN);
|
||||
if let Some(s) = colors.get("warn") {
|
||||
ret.status_warn = *s;
|
||||
}
|
||||
|
||||
config.insert(String::from("table"), map_into_value(hm));
|
||||
}
|
||||
if let Some(s) = colors.get("error") {
|
||||
ret.status_error = *s;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut hm = config
|
||||
.get("hex-dump")
|
||||
.and_then(create_map)
|
||||
.unwrap_or_default();
|
||||
if let Some(hm) = explore_cfg_hash_map.get("try").and_then(create_map) {
|
||||
if let Some(reactive) = hm.get("reactive") {
|
||||
if let Ok(b) = reactive.as_bool() {
|
||||
ret.try_reactive = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
insert_style(&mut hm, "color_index", HEXDUMP_INDEX);
|
||||
insert_style(&mut hm, "color_segment", HEXDUMP_SEGMENT);
|
||||
insert_style(&mut hm, "color_segment_zero", HEXDUMP_SEGMENT_ZERO);
|
||||
insert_style(&mut hm, "color_segment_unknown", HEXDUMP_SEGMENT_UNKNOWN);
|
||||
insert_style(&mut hm, "color_ascii", HEXDUMP_ASCII);
|
||||
insert_style(&mut hm, "color_ascii_zero", HEXDUMP_ASCII_ZERO);
|
||||
insert_style(&mut hm, "color_ascii_unknown", HEXDUMP_ASCII_UNKNOWN);
|
||||
|
||||
insert_int(&mut hm, "segment_size", 2);
|
||||
insert_int(&mut hm, "count_segments", 8);
|
||||
|
||||
insert_bool(&mut hm, "split", true);
|
||||
|
||||
config.insert(String::from("hex-dump"), map_into_value(hm));
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_hash_map(value: &Value) -> Option<HashMap<String, Value>> {
|
||||
value.as_record().ok().map(|val| {
|
||||
val.iter()
|
||||
.map(|(col, val)| (col.clone(), val.clone()))
|
||||
.collect::<HashMap<_, _>>()
|
||||
})
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct TableConfig {
|
||||
pub separator_style: Style,
|
||||
pub show_index: bool,
|
||||
pub show_header: bool,
|
||||
pub column_padding_left: usize,
|
||||
pub column_padding_right: usize,
|
||||
}
|
||||
|
||||
const fn color(foreground: Option<Color>, background: Option<Color>) -> Style {
|
||||
@ -299,49 +265,6 @@ const fn color(foreground: Option<Color>, background: Option<Color>) -> Style {
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_style(map: &mut HashMap<String, Value>, key: &str, value: Style) {
|
||||
if map.contains_key(key) {
|
||||
return;
|
||||
}
|
||||
|
||||
if value == Style::default() {
|
||||
return;
|
||||
}
|
||||
|
||||
let value = nu_color_config::NuStyle::from(value);
|
||||
if let Ok(val) = nu_json::to_string_raw(&value) {
|
||||
map.insert(String::from(key), Value::string(val, Span::unknown()));
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_bool(map: &mut HashMap<String, Value>, key: &str, value: bool) {
|
||||
if map.contains_key(key) {
|
||||
return;
|
||||
}
|
||||
|
||||
map.insert(String::from(key), Value::bool(value, Span::unknown()));
|
||||
}
|
||||
|
||||
fn insert_int(map: &mut HashMap<String, Value>, key: &str, value: i64) {
|
||||
if map.contains_key(key) {
|
||||
return;
|
||||
}
|
||||
|
||||
map.insert(String::from(key), Value::int(value, Span::unknown()));
|
||||
}
|
||||
|
||||
fn include_nu_config(config: &mut HashMap<String, Value>, style_computer: &StyleComputer) {
|
||||
let line_color = lookup_color(style_computer, "separator");
|
||||
if line_color != nu_ansi_term::Style::default() {
|
||||
let mut map = config
|
||||
.get("table")
|
||||
.and_then(parse_hash_map)
|
||||
.unwrap_or_default();
|
||||
insert_style(&mut map, "split_line", line_color);
|
||||
config.insert(String::from("table"), map_into_value(map));
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_color(style_computer: &StyleComputer, key: &str) -> nu_ansi_term::Style {
|
||||
style_computer.compute(key, &Value::nothing(Span::unknown()))
|
||||
}
|
||||
|
@ -15,13 +15,13 @@ use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
PipelineData, Value,
|
||||
};
|
||||
use pager::{Page, Pager, PagerConfig, StyleConfig};
|
||||
use pager::{Page, Pager, PagerConfig};
|
||||
use registry::CommandRegistry;
|
||||
use terminal_size::{Height, Width};
|
||||
use views::{BinaryView, Orientation, Preview, RecordView};
|
||||
|
||||
mod util {
|
||||
pub use super::nu_common::{create_lscolors, create_map, map_into_value};
|
||||
pub use super::nu_common::{create_lscolors, create_map};
|
||||
}
|
||||
|
||||
fn run_pager(
|
||||
|
@ -18,7 +18,7 @@ pub use command::run_command_with_value;
|
||||
pub use lscolor::{create_lscolors, lscolorize};
|
||||
pub use string::{string_width, truncate_str};
|
||||
pub use table::try_build_table;
|
||||
pub use value::{collect_input, collect_pipeline, create_map, map_into_value};
|
||||
pub use value::{collect_input, collect_pipeline, create_map};
|
||||
|
||||
pub fn has_simple_value(data: &[Vec<Value>]) -> Option<&Value> {
|
||||
if data.len() == 1
|
||||
|
@ -176,10 +176,6 @@ pub fn create_map(value: &Value) -> Option<HashMap<String, Value>> {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn map_into_value(hm: HashMap<String, Value>) -> Value {
|
||||
Value::record(hm.into_iter().collect(), NuSpan::unknown())
|
||||
}
|
||||
|
||||
fn unknown_error_value() -> Value {
|
||||
Value::string(String::from("❎"), NuSpan::unknown())
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ use self::{
|
||||
};
|
||||
use super::views::{Layout, View};
|
||||
use crate::{
|
||||
nu_common::{CtrlC, NuColor, NuConfig, NuSpan, NuStyle},
|
||||
explore::ExploreConfig,
|
||||
nu_common::{CtrlC, NuColor, NuConfig, NuStyle},
|
||||
registry::{Command, CommandRegistry},
|
||||
util::map_into_value,
|
||||
views::{util::nu_style_to_tui, ViewConfig},
|
||||
};
|
||||
use anyhow::Result;
|
||||
@ -26,15 +26,14 @@ use crossterm::{
|
||||
};
|
||||
use events::UIEvents;
|
||||
use lscolors::LsColors;
|
||||
use nu_color_config::{lookup_ansi_color_style, StyleComputer};
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Record, Value,
|
||||
Value,
|
||||
};
|
||||
use ratatui::{backend::CrosstermBackend, layout::Rect, widgets::Block};
|
||||
use std::{
|
||||
cmp::min,
|
||||
collections::HashMap,
|
||||
io::{self, Stdout},
|
||||
result,
|
||||
sync::atomic::Ordering,
|
||||
@ -42,7 +41,6 @@ use std::{
|
||||
|
||||
pub type Frame<'a> = ratatui::Frame<'a>;
|
||||
pub type Terminal = ratatui::Terminal<CrosstermBackend<Stdout>>;
|
||||
pub type ConfigMap = HashMap<String, Value>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Pager<'a> {
|
||||
@ -73,19 +71,6 @@ struct CommandBuf {
|
||||
cmd_exec_info: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct StyleConfig {
|
||||
pub status_info: NuStyle,
|
||||
pub status_success: NuStyle,
|
||||
pub status_warn: NuStyle,
|
||||
pub status_error: NuStyle,
|
||||
pub status_bar_background: NuStyle,
|
||||
pub status_bar_text: NuStyle,
|
||||
pub cmd_bar_text: NuStyle,
|
||||
pub cmd_bar_background: NuStyle,
|
||||
pub highlight: NuStyle,
|
||||
}
|
||||
|
||||
impl<'a> Pager<'a> {
|
||||
pub fn new(config: PagerConfig<'a>) -> Self {
|
||||
Self {
|
||||
@ -100,27 +85,6 @@ impl<'a> Pager<'a> {
|
||||
self.message = Some(text.into());
|
||||
}
|
||||
|
||||
pub fn set_config(&mut self, path: &[String], value: Value) -> bool {
|
||||
let path = path.iter().map(|s| s.as_str()).collect::<Vec<_>>();
|
||||
|
||||
match &path[..] {
|
||||
["status_bar_text"] => value_as_style(&mut self.config.style.status_bar_text, &value),
|
||||
["status_bar_background"] => {
|
||||
value_as_style(&mut self.config.style.status_bar_background, &value)
|
||||
}
|
||||
["command_bar_text"] => value_as_style(&mut self.config.style.cmd_bar_text, &value),
|
||||
["command_bar_background"] => {
|
||||
value_as_style(&mut self.config.style.cmd_bar_background, &value)
|
||||
}
|
||||
["highlight"] => value_as_style(&mut self.config.style.highlight, &value),
|
||||
["status", "info"] => value_as_style(&mut self.config.style.status_info, &value),
|
||||
["status", "success"] => value_as_style(&mut self.config.style.status_success, &value),
|
||||
["status", "warn"] => value_as_style(&mut self.config.style.status_warn, &value),
|
||||
["status", "error"] => value_as_style(&mut self.config.style.status_error, &value),
|
||||
path => set_config(&mut self.config.config, path, value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
&mut self,
|
||||
engine_state: &EngineState,
|
||||
@ -132,8 +96,8 @@ impl<'a> Pager<'a> {
|
||||
if let Some(page) = &mut view {
|
||||
page.view.setup(ViewConfig::new(
|
||||
self.config.nu_config,
|
||||
self.config.explore_config,
|
||||
self.config.style_computer,
|
||||
&self.config.config,
|
||||
self.config.lscolors,
|
||||
))
|
||||
}
|
||||
@ -153,10 +117,9 @@ pub enum Transition {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PagerConfig<'a> {
|
||||
pub nu_config: &'a NuConfig,
|
||||
pub explore_config: &'a ExploreConfig,
|
||||
pub style_computer: &'a StyleComputer<'a>,
|
||||
pub lscolors: &'a LsColors,
|
||||
pub config: ConfigMap,
|
||||
pub style: StyleConfig,
|
||||
// If true, when quitting output the value of the cell the cursor was on
|
||||
pub peek_value: bool,
|
||||
pub tail: bool,
|
||||
@ -165,18 +128,19 @@ pub struct PagerConfig<'a> {
|
||||
impl<'a> PagerConfig<'a> {
|
||||
pub fn new(
|
||||
nu_config: &'a NuConfig,
|
||||
explore_config: &'a ExploreConfig,
|
||||
style_computer: &'a StyleComputer,
|
||||
lscolors: &'a LsColors,
|
||||
config: ConfigMap,
|
||||
peek_value: bool,
|
||||
tail: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
nu_config,
|
||||
explore_config,
|
||||
style_computer,
|
||||
config,
|
||||
lscolors,
|
||||
peek_value: false,
|
||||
tail: false,
|
||||
style: StyleConfig::default(),
|
||||
peek_value,
|
||||
tail,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -401,7 +365,7 @@ fn draw_frame(
|
||||
|
||||
draw_info(f, pager, info);
|
||||
|
||||
highlight_search_results(f, pager, layout, pager.config.style.highlight);
|
||||
highlight_search_results(f, pager, layout, pager.config.explore_config.highlight);
|
||||
set_cursor_cmd_bar(f, area, pager);
|
||||
}
|
||||
|
||||
@ -411,19 +375,24 @@ fn draw_info(f: &mut Frame, pager: &mut Pager<'_>, info: ViewInfo) {
|
||||
if let Some(report) = info.status {
|
||||
let last_2nd_line = area.bottom().saturating_sub(2);
|
||||
let area = Rect::new(area.left(), last_2nd_line, area.width, 1);
|
||||
render_status_bar(f, area, report, &pager.config.style);
|
||||
render_status_bar(f, area, report, pager.config.explore_config);
|
||||
}
|
||||
|
||||
{
|
||||
let last_line = area.bottom().saturating_sub(1);
|
||||
let area = Rect::new(area.left(), last_line, area.width, 1);
|
||||
render_cmd_bar(f, area, pager, info.report, &pager.config.style);
|
||||
render_cmd_bar(f, area, pager, info.report, pager.config.explore_config);
|
||||
}
|
||||
}
|
||||
|
||||
fn create_view_config<'a>(pager: &'a Pager<'_>) -> ViewConfig<'a> {
|
||||
let cfg = &pager.config;
|
||||
ViewConfig::new(cfg.nu_config, cfg.style_computer, &cfg.config, cfg.lscolors)
|
||||
ViewConfig::new(
|
||||
cfg.nu_config,
|
||||
cfg.explore_config,
|
||||
cfg.style_computer,
|
||||
cfg.lscolors,
|
||||
)
|
||||
}
|
||||
|
||||
fn pager_run_command(
|
||||
@ -463,16 +432,7 @@ fn run_command(
|
||||
let value = view_stack.curr_view.as_mut().and_then(|p| p.view.exit());
|
||||
let transition = command.react(engine_state, stack, pager, value)?;
|
||||
match transition {
|
||||
Transition::Ok => {
|
||||
// so we basically allow a change of a config inside a command,
|
||||
// and cause of this we wanna update all of our views.
|
||||
//
|
||||
// THOUGH: MOST LIKELY IT WON'T BE CHANGED AND WE DO A WASTE.......
|
||||
|
||||
update_view_stack_setup(view_stack, &pager.config);
|
||||
|
||||
Ok(CmdResult::new(false, false, String::new()))
|
||||
}
|
||||
Transition::Ok => Ok(CmdResult::new(false, false, String::new())),
|
||||
Transition::Exit => Ok(CmdResult::new(true, false, String::new())),
|
||||
Transition::Cmd { .. } => todo!("not used so far"),
|
||||
}
|
||||
@ -487,7 +447,8 @@ fn run_command(
|
||||
}
|
||||
}
|
||||
|
||||
update_view_setup(&mut new_view, &pager.config);
|
||||
setup_view(&mut new_view, &pager.config);
|
||||
|
||||
view_stack.curr_view = Some(Page::raw(new_view, stackable));
|
||||
|
||||
Ok(CmdResult::new(false, true, cmd.name().to_owned()))
|
||||
@ -495,18 +456,13 @@ fn run_command(
|
||||
}
|
||||
}
|
||||
|
||||
fn update_view_stack_setup(view_stack: &mut ViewStack, cfg: &PagerConfig<'_>) {
|
||||
if let Some(page) = view_stack.curr_view.as_mut() {
|
||||
update_view_setup(&mut page.view, cfg);
|
||||
}
|
||||
|
||||
for page in &mut view_stack.stack {
|
||||
update_view_setup(&mut page.view, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_view_setup(view: &mut Box<dyn View>, cfg: &PagerConfig<'_>) {
|
||||
let cfg = ViewConfig::new(cfg.nu_config, cfg.style_computer, &cfg.config, cfg.lscolors);
|
||||
fn setup_view(view: &mut Box<dyn View>, cfg: &PagerConfig<'_>) {
|
||||
let cfg = ViewConfig::new(
|
||||
cfg.nu_config,
|
||||
cfg.explore_config,
|
||||
cfg.style_computer,
|
||||
cfg.lscolors,
|
||||
);
|
||||
view.setup(cfg);
|
||||
}
|
||||
|
||||
@ -528,7 +484,7 @@ fn set_cursor_cmd_bar(f: &mut Frame, area: Rect, pager: &Pager) {
|
||||
}
|
||||
}
|
||||
|
||||
fn render_status_bar(f: &mut Frame, area: Rect, report: Report, theme: &StyleConfig) {
|
||||
fn render_status_bar(f: &mut Frame, area: Rect, report: Report, theme: &ExploreConfig) {
|
||||
let msg_style = report_msg_style(&report, theme, theme.status_bar_text);
|
||||
let mut status_bar = create_status_bar(report);
|
||||
status_bar.set_background_style(theme.status_bar_background);
|
||||
@ -549,11 +505,11 @@ fn create_status_bar(report: Report) -> StatusBar {
|
||||
)
|
||||
}
|
||||
|
||||
fn report_msg_style(report: &Report, theme: &StyleConfig, style: NuStyle) -> NuStyle {
|
||||
fn report_msg_style(report: &Report, config: &ExploreConfig, style: NuStyle) -> NuStyle {
|
||||
if matches!(report.level, Severity::Info) {
|
||||
style
|
||||
} else {
|
||||
report_level_style(report.level, theme)
|
||||
report_level_style(report.level, config)
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,15 +518,15 @@ fn render_cmd_bar(
|
||||
area: Rect,
|
||||
pager: &Pager,
|
||||
report: Option<Report>,
|
||||
theme: &StyleConfig,
|
||||
config: &ExploreConfig,
|
||||
) {
|
||||
if let Some(report) = report {
|
||||
let style = report_msg_style(&report, theme, theme.cmd_bar_text);
|
||||
let style = report_msg_style(&report, config, config.cmd_bar_text);
|
||||
let bar = CommandBar::new(
|
||||
&report.message,
|
||||
&report.context1,
|
||||
style,
|
||||
theme.cmd_bar_background,
|
||||
config.cmd_bar_background,
|
||||
);
|
||||
|
||||
f.render_widget(bar, area);
|
||||
@ -578,16 +534,16 @@ fn render_cmd_bar(
|
||||
}
|
||||
|
||||
if pager.cmd_buf.is_cmd_input {
|
||||
render_cmd_bar_cmd(f, area, pager, theme);
|
||||
render_cmd_bar_cmd(f, area, pager, config);
|
||||
return;
|
||||
}
|
||||
|
||||
if pager.search_buf.is_search_input || !pager.search_buf.buf_cmd_input.is_empty() {
|
||||
render_cmd_bar_search(f, area, pager, theme);
|
||||
render_cmd_bar_search(f, area, pager, config);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_cmd_bar_search(f: &mut Frame, area: Rect, pager: &Pager<'_>, theme: &StyleConfig) {
|
||||
fn render_cmd_bar_search(f: &mut Frame, area: Rect, pager: &Pager<'_>, config: &ExploreConfig) {
|
||||
if pager.search_buf.search_results.is_empty() && !pager.search_buf.is_search_input {
|
||||
let message = format!("Pattern not found: {}", pager.search_buf.buf_cmd_input);
|
||||
let style = NuStyle {
|
||||
@ -596,7 +552,7 @@ fn render_cmd_bar_search(f: &mut Frame, area: Rect, pager: &Pager<'_>, theme: &S
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let bar = CommandBar::new(&message, "", style, theme.cmd_bar_background);
|
||||
let bar = CommandBar::new(&message, "", style, config.cmd_bar_background);
|
||||
f.render_widget(bar, area);
|
||||
return;
|
||||
}
|
||||
@ -615,11 +571,11 @@ fn render_cmd_bar_search(f: &mut Frame, area: Rect, pager: &Pager<'_>, theme: &S
|
||||
format!("[{index}/{total}]")
|
||||
};
|
||||
|
||||
let bar = CommandBar::new(&text, &info, theme.cmd_bar_text, theme.cmd_bar_background);
|
||||
let bar = CommandBar::new(&text, &info, config.cmd_bar_text, config.cmd_bar_background);
|
||||
f.render_widget(bar, area);
|
||||
}
|
||||
|
||||
fn render_cmd_bar_cmd(f: &mut Frame, area: Rect, pager: &Pager, theme: &StyleConfig) {
|
||||
fn render_cmd_bar_cmd(f: &mut Frame, area: Rect, pager: &Pager, config: &ExploreConfig) {
|
||||
let mut input = pager.cmd_buf.buf_cmd2.as_str();
|
||||
if input.len() > area.width as usize + 1 {
|
||||
// in such case we take last max_cmd_len chars
|
||||
@ -637,7 +593,7 @@ fn render_cmd_bar_cmd(f: &mut Frame, area: Rect, pager: &Pager, theme: &StyleCon
|
||||
let prefix = ':';
|
||||
let text = format!("{prefix}{input}");
|
||||
|
||||
let bar = CommandBar::new(&text, "", theme.cmd_bar_text, theme.cmd_bar_background);
|
||||
let bar = CommandBar::new(&text, "", config.cmd_bar_text, config.cmd_bar_background);
|
||||
f.render_widget(bar, area);
|
||||
}
|
||||
|
||||
@ -998,72 +954,12 @@ fn cmd_input_key_event(buf: &mut CommandBuf, key: &KeyEvent) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn value_as_style(style: &mut nu_ansi_term::Style, value: &Value) -> bool {
|
||||
match value.coerce_str() {
|
||||
Ok(s) => {
|
||||
*style = lookup_ansi_color_style(&s);
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_config(hm: &mut HashMap<String, Value>, path: &[&str], value: Value) -> bool {
|
||||
if path.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let key = path[0];
|
||||
|
||||
if !hm.contains_key(key) {
|
||||
hm.insert(
|
||||
key.to_string(),
|
||||
Value::record(Record::new(), NuSpan::unknown()),
|
||||
);
|
||||
}
|
||||
|
||||
let val = hm.get_mut(key).expect("...");
|
||||
|
||||
if path.len() == 1 {
|
||||
*val = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
match val {
|
||||
Value::Record { val: record, .. } => {
|
||||
if path.len() == 2 {
|
||||
let key = path[1];
|
||||
|
||||
record.to_mut().insert(key, value);
|
||||
} else {
|
||||
let mut hm2: HashMap<String, Value> = HashMap::new();
|
||||
for (k, v) in record.iter() {
|
||||
hm2.insert(k.to_string(), v.clone());
|
||||
}
|
||||
|
||||
let result = set_config(&mut hm2, &path[1..], value);
|
||||
if !result {
|
||||
*val = map_into_value(hm2);
|
||||
}
|
||||
|
||||
if path.len() == 2 {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn report_level_style(level: Severity, theme: &StyleConfig) -> NuStyle {
|
||||
fn report_level_style(level: Severity, config: &ExploreConfig) -> NuStyle {
|
||||
match level {
|
||||
Severity::Info => theme.status_info,
|
||||
Severity::Success => theme.status_success,
|
||||
Severity::Warn => theme.status_warn,
|
||||
Severity::Err => theme.status_error,
|
||||
Severity::Info => config.status_info,
|
||||
Severity::Success => config.status_success,
|
||||
Severity::Warn => config.status_warn,
|
||||
Severity::Err => config.status_error,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
mod binary_widget;
|
||||
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
use nu_color_config::get_color_map;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Value,
|
||||
@ -11,12 +10,12 @@ use nu_protocol::{
|
||||
use ratatui::layout::Rect;
|
||||
|
||||
use crate::{
|
||||
explore::ExploreConfig,
|
||||
nu_common::NuText,
|
||||
pager::{
|
||||
report::{Report, Severity},
|
||||
ConfigMap, Frame, Transition, ViewInfo,
|
||||
Frame, Transition, ViewInfo,
|
||||
},
|
||||
util::create_map,
|
||||
views::cursor::Position,
|
||||
};
|
||||
|
||||
@ -90,12 +89,7 @@ impl View for BinaryView {
|
||||
}
|
||||
|
||||
fn setup(&mut self, cfg: ViewConfig<'_>) {
|
||||
let hm = match cfg.config.get("hex-dump").and_then(create_map) {
|
||||
Some(hm) => hm,
|
||||
None => return,
|
||||
};
|
||||
|
||||
self.settings = settings_from_config(&hm);
|
||||
self.settings = settings_from_config(cfg.explore_config);
|
||||
|
||||
let count_rows =
|
||||
BinaryWidget::new(&self.data, self.settings.opts, Default::default()).count_lines();
|
||||
@ -184,30 +178,18 @@ fn handle_event_view_mode(view: &mut BinaryView, key: &KeyEvent) -> Option<Trans
|
||||
}
|
||||
}
|
||||
|
||||
fn settings_from_config(config: &ConfigMap) -> Settings {
|
||||
let colors = get_color_map(config);
|
||||
|
||||
fn settings_from_config(config: &ExploreConfig) -> Settings {
|
||||
// Most of this is hardcoded for now, add it to the config later if needed
|
||||
Settings {
|
||||
opts: BinarySettings::new(
|
||||
config_get_usize(config, "segment_size", 2),
|
||||
config_get_usize(config, "count_segments", 8),
|
||||
),
|
||||
opts: BinarySettings::new(2, 8),
|
||||
style: BinaryStyle::new(
|
||||
colors.get("color_index").cloned(),
|
||||
config_get_usize(config, "column_padding_left", 1) as u16,
|
||||
config_get_usize(config, "column_padding_right", 1) as u16,
|
||||
None,
|
||||
config.table.column_padding_left as u16,
|
||||
config.table.column_padding_right as u16,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn config_get_usize(config: &ConfigMap, key: &str, default: usize) -> usize {
|
||||
config
|
||||
.get(key)
|
||||
.and_then(|v| v.coerce_str().ok())
|
||||
.and_then(|s| s.parse::<usize>().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
fn create_report(cursor: WindowCursor2D) -> Report {
|
||||
let covered_percent = report_row_position(cursor);
|
||||
let cursor = report_cursor_position(cursor);
|
||||
|
@ -1,16 +1,16 @@
|
||||
mod binary;
|
||||
mod colored_text_widget;
|
||||
mod cursor;
|
||||
mod interactive;
|
||||
mod preview;
|
||||
mod record;
|
||||
mod r#try;
|
||||
pub mod util;
|
||||
|
||||
use super::{
|
||||
nu_common::NuText,
|
||||
pager::{Frame, Transition, ViewInfo},
|
||||
};
|
||||
use crate::{nu_common::NuConfig, pager::ConfigMap};
|
||||
use crate::{explore::ExploreConfig, nu_common::NuConfig};
|
||||
use crossterm::event::KeyEvent;
|
||||
use lscolors::LsColors;
|
||||
use nu_color_config::StyleComputer;
|
||||
@ -21,8 +21,8 @@ use nu_protocol::{
|
||||
use ratatui::layout::Rect;
|
||||
|
||||
pub use binary::BinaryView;
|
||||
pub use interactive::InteractiveView;
|
||||
pub use preview::Preview;
|
||||
pub use r#try::TryView;
|
||||
pub use record::{Orientation, RecordView};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@ -55,22 +55,22 @@ impl ElementInfo {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ViewConfig<'a> {
|
||||
pub nu_config: &'a NuConfig,
|
||||
pub explore_config: &'a ExploreConfig,
|
||||
pub style_computer: &'a StyleComputer<'a>,
|
||||
pub config: &'a ConfigMap,
|
||||
pub lscolors: &'a LsColors,
|
||||
}
|
||||
|
||||
impl<'a> ViewConfig<'a> {
|
||||
pub fn new(
|
||||
nu_config: &'a NuConfig,
|
||||
explore_config: &'a ExploreConfig,
|
||||
style_computer: &'a StyleComputer<'a>,
|
||||
config: &'a ConfigMap,
|
||||
lscolors: &'a LsColors,
|
||||
) -> Self {
|
||||
Self {
|
||||
nu_config,
|
||||
explore_config,
|
||||
style_computer,
|
||||
config,
|
||||
lscolors,
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,26 @@
|
||||
mod table_widget;
|
||||
|
||||
use self::table_widget::{TableStyle, TableWidget, TableWidgetState};
|
||||
use self::table_widget::{TableWidget, TableWidgetState};
|
||||
use super::{
|
||||
cursor::{Position, WindowCursor2D},
|
||||
util::{make_styled_string, nu_style_to_tui},
|
||||
Layout, View, ViewConfig,
|
||||
};
|
||||
use crate::{
|
||||
nu_common::{collect_input, lscolorize, NuConfig, NuSpan, NuStyle, NuText},
|
||||
explore::ExploreConfig,
|
||||
nu_common::{collect_input, lscolorize, NuSpan, NuText},
|
||||
pager::{
|
||||
report::{Report, Severity},
|
||||
ConfigMap, Frame, Transition, ViewInfo,
|
||||
Frame, Transition, ViewInfo,
|
||||
},
|
||||
util::create_map,
|
||||
views::ElementInfo,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
use nu_color_config::{get_color_map, StyleComputer};
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Record, Span, Value,
|
||||
Config, Record, Span, Value,
|
||||
};
|
||||
use ratatui::{layout::Rect, widgets::Block};
|
||||
use std::{borrow::Cow, collections::HashMap};
|
||||
@ -32,7 +32,7 @@ pub struct RecordView<'a> {
|
||||
layer_stack: Vec<RecordLayer<'a>>,
|
||||
mode: UIMode,
|
||||
orientation: Orientation,
|
||||
theme: TableTheme,
|
||||
cfg: ExploreConfig,
|
||||
}
|
||||
|
||||
impl<'a> RecordView<'a> {
|
||||
@ -44,52 +44,18 @@ impl<'a> RecordView<'a> {
|
||||
layer_stack: vec![RecordLayer::new(columns, records)],
|
||||
mode: UIMode::View,
|
||||
orientation: Orientation::Top,
|
||||
theme: TableTheme::default(),
|
||||
// TODO: It's kind of gross how this temporarily has an incorrect/default config.
|
||||
// See if we can pass correct config in through the constructor
|
||||
cfg: ExploreConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tail(&mut self, width: u16, height: u16) {
|
||||
let page_size =
|
||||
estimate_page_size(Rect::new(0, 0, width, height), self.theme.table.show_header);
|
||||
estimate_page_size(Rect::new(0, 0, width, height), self.cfg.table.show_header);
|
||||
tail_data(self, page_size as usize);
|
||||
}
|
||||
|
||||
pub fn set_style_split_line(&mut self, style: NuStyle) {
|
||||
self.theme.table.splitline_style = style
|
||||
}
|
||||
|
||||
pub fn set_style_selected_cell(&mut self, style: NuStyle) {
|
||||
self.theme.cursor.selected_cell = Some(style)
|
||||
}
|
||||
|
||||
pub fn set_style_selected_row(&mut self, style: NuStyle) {
|
||||
self.theme.cursor.selected_row = Some(style)
|
||||
}
|
||||
|
||||
pub fn set_style_selected_column(&mut self, style: NuStyle) {
|
||||
self.theme.cursor.selected_column = Some(style)
|
||||
}
|
||||
|
||||
pub fn set_padding_column(&mut self, (left, right): (usize, usize)) {
|
||||
self.theme.table.column_padding_left = left;
|
||||
self.theme.table.column_padding_right = right;
|
||||
}
|
||||
|
||||
pub fn get_padding_column(&self) -> (usize, usize) {
|
||||
(
|
||||
self.theme.table.column_padding_left,
|
||||
self.theme.table.column_padding_right,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_theme(&self) -> &TableTheme {
|
||||
&self.theme
|
||||
}
|
||||
|
||||
pub fn set_theme(&mut self, theme: TableTheme) {
|
||||
self.theme = theme;
|
||||
}
|
||||
|
||||
pub fn transpose(&mut self) {
|
||||
let layer = self.get_layer_last_mut();
|
||||
transpose_table(layer);
|
||||
@ -193,7 +159,7 @@ impl<'a> RecordView<'a> {
|
||||
style_computer,
|
||||
row,
|
||||
column,
|
||||
self.theme.table,
|
||||
self.cfg.table,
|
||||
layer.orientation,
|
||||
)
|
||||
}
|
||||
@ -252,11 +218,11 @@ impl View for RecordView<'_> {
|
||||
column,
|
||||
table_layout.count_rows,
|
||||
self.get_layer_last().orientation,
|
||||
self.theme.table.show_header,
|
||||
self.cfg.table.show_header,
|
||||
);
|
||||
|
||||
if let Some(info) = info {
|
||||
highlight_cell(f, area, info.clone(), &self.theme.cursor);
|
||||
highlight_selected_cell(f, info.clone(), &self.cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -300,7 +266,7 @@ impl View for RecordView<'_> {
|
||||
|
||||
let data = convert_records_to_string(
|
||||
&self.get_layer_last().records,
|
||||
&NuConfig::default(),
|
||||
&nu_protocol::Config::default(),
|
||||
&style_computer,
|
||||
);
|
||||
|
||||
@ -338,22 +304,7 @@ impl View for RecordView<'_> {
|
||||
|
||||
// todo: move the method to Command?
|
||||
fn setup(&mut self, cfg: ViewConfig<'_>) {
|
||||
if let Some(hm) = cfg.config.get("table").and_then(create_map) {
|
||||
self.theme = theme_from_config(&hm);
|
||||
|
||||
if let Some(orientation) = hm.get("orientation").and_then(|v| v.coerce_str().ok()) {
|
||||
let orientation = match orientation.as_ref() {
|
||||
"left" => Some(Orientation::Left),
|
||||
"top" => Some(Orientation::Top),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(orientation) = orientation {
|
||||
self.set_orientation(orientation);
|
||||
self.set_orientation_current(orientation);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.cfg = cfg.explore_config.clone();
|
||||
}
|
||||
}
|
||||
|
||||
@ -660,7 +611,7 @@ fn tail_data(state: &mut RecordView<'_>, page_size: usize) {
|
||||
|
||||
fn convert_records_to_string(
|
||||
records: &[Vec<Value>],
|
||||
cfg: &NuConfig,
|
||||
cfg: &Config,
|
||||
style_computer: &StyleComputer,
|
||||
) -> Vec<Vec<NuText>> {
|
||||
records
|
||||
@ -678,31 +629,8 @@ fn convert_records_to_string(
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn highlight_cell(f: &mut Frame, area: Rect, info: ElementInfo, theme: &CursorStyle) {
|
||||
// highlight selected column
|
||||
if let Some(style) = theme.selected_column {
|
||||
let highlight_block = Block::default().style(nu_style_to_tui(style));
|
||||
let area = Rect::new(info.area.x, area.y, info.area.width, area.height);
|
||||
f.render_widget(highlight_block.clone(), area);
|
||||
}
|
||||
|
||||
// highlight selected row
|
||||
if let Some(style) = theme.selected_row {
|
||||
let highlight_block = Block::default().style(nu_style_to_tui(style));
|
||||
let area = Rect::new(area.x, info.area.y, area.width, 1);
|
||||
f.render_widget(highlight_block.clone(), area);
|
||||
}
|
||||
|
||||
// highlight selected cell
|
||||
let cell_style = match theme.selected_cell {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
let mut style = nu_ansi_term::Style::new();
|
||||
// light blue chosen somewhat arbitrarily, looks OK but I'm not set on it
|
||||
style.background = Some(nu_ansi_term::Color::LightBlue);
|
||||
style
|
||||
}
|
||||
};
|
||||
fn highlight_selected_cell(f: &mut Frame, info: ElementInfo, cfg: &ExploreConfig) {
|
||||
let cell_style = cfg.selected_cell;
|
||||
let highlight_block = Block::default().style(nu_style_to_tui(cell_style));
|
||||
let area = Rect::new(info.area.x, info.area.y, info.area.width, 1);
|
||||
f.render_widget(highlight_block.clone(), area)
|
||||
@ -842,53 +770,3 @@ fn _transpose_table(
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
fn theme_from_config(config: &ConfigMap) -> TableTheme {
|
||||
let mut theme = TableTheme::default();
|
||||
|
||||
let colors = get_color_map(config);
|
||||
|
||||
if let Some(s) = colors.get("split_line") {
|
||||
theme.table.splitline_style = *s;
|
||||
}
|
||||
|
||||
theme.cursor.selected_cell = colors.get("selected_cell").cloned();
|
||||
theme.cursor.selected_row = colors.get("selected_row").cloned();
|
||||
theme.cursor.selected_column = colors.get("selected_column").cloned();
|
||||
|
||||
theme.table.show_header = config_get_bool(config, "show_head", true);
|
||||
theme.table.show_index = config_get_bool(config, "show_index", false);
|
||||
|
||||
theme.table.column_padding_left = config_get_usize(config, "column_padding_left", 1);
|
||||
theme.table.column_padding_right = config_get_usize(config, "column_padding_right", 1);
|
||||
|
||||
theme
|
||||
}
|
||||
|
||||
fn config_get_bool(config: &ConfigMap, key: &str, default: bool) -> bool {
|
||||
config
|
||||
.get(key)
|
||||
.and_then(|v| v.as_bool().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
fn config_get_usize(config: &ConfigMap, key: &str, default: usize) -> usize {
|
||||
config
|
||||
.get(key)
|
||||
.and_then(|v| v.coerce_str().ok())
|
||||
.and_then(|s| s.parse::<usize>().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct TableTheme {
|
||||
table: TableStyle,
|
||||
cursor: CursorStyle,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct CursorStyle {
|
||||
selected_cell: Option<NuStyle>,
|
||||
selected_column: Option<NuStyle>,
|
||||
selected_row: Option<NuStyle>,
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::Layout;
|
||||
use crate::{
|
||||
explore::TableConfig,
|
||||
nu_common::{truncate_str, NuStyle, NuText},
|
||||
views::util::{nu_style_to_tui, text_style_to_tui_style},
|
||||
};
|
||||
@ -23,7 +24,7 @@ pub struct TableWidget<'a> {
|
||||
data: Cow<'a, [Vec<NuText>]>,
|
||||
index_row: usize,
|
||||
index_column: usize,
|
||||
style: TableStyle,
|
||||
config: TableConfig,
|
||||
header_position: Orientation,
|
||||
style_computer: &'a StyleComputer<'a>,
|
||||
}
|
||||
@ -35,15 +36,6 @@ pub enum Orientation {
|
||||
Left,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct TableStyle {
|
||||
pub splitline_style: NuStyle,
|
||||
pub show_index: bool,
|
||||
pub show_header: bool,
|
||||
pub column_padding_left: usize,
|
||||
pub column_padding_right: usize,
|
||||
}
|
||||
|
||||
impl<'a> TableWidget<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
@ -52,7 +44,7 @@ impl<'a> TableWidget<'a> {
|
||||
style_computer: &'a StyleComputer<'a>,
|
||||
index_row: usize,
|
||||
index_column: usize,
|
||||
style: TableStyle,
|
||||
config: TableConfig,
|
||||
header_position: Orientation,
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -61,7 +53,7 @@ impl<'a> TableWidget<'a> {
|
||||
style_computer,
|
||||
index_row,
|
||||
index_column,
|
||||
style,
|
||||
config,
|
||||
header_position,
|
||||
}
|
||||
}
|
||||
@ -100,13 +92,13 @@ impl StatefulWidget for TableWidget<'_> {
|
||||
// todo: refactoring these to methods as they have quite a bit in common.
|
||||
impl<'a> TableWidget<'a> {
|
||||
fn render_table_horizontal(self, area: Rect, buf: &mut Buffer, state: &mut TableWidgetState) {
|
||||
let padding_l = self.style.column_padding_left as u16;
|
||||
let padding_r = self.style.column_padding_right as u16;
|
||||
let padding_l = self.config.column_padding_left as u16;
|
||||
let padding_r = self.config.column_padding_right as u16;
|
||||
|
||||
let show_index = self.style.show_index;
|
||||
let show_head = self.style.show_header;
|
||||
let show_index = self.config.show_index;
|
||||
let show_head = self.config.show_header;
|
||||
|
||||
let splitline_s = self.style.splitline_style;
|
||||
let separator_s = self.config.separator_style;
|
||||
|
||||
let mut data_height = area.height;
|
||||
let mut data_y = area.y;
|
||||
@ -137,7 +129,7 @@ impl<'a> TableWidget<'a> {
|
||||
}
|
||||
|
||||
if show_head {
|
||||
render_header_borders(buf, area, 1, splitline_s);
|
||||
render_header_borders(buf, area, 1, separator_s);
|
||||
}
|
||||
|
||||
if show_index {
|
||||
@ -158,7 +150,7 @@ impl<'a> TableWidget<'a> {
|
||||
data_height,
|
||||
show_head,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
@ -250,7 +242,7 @@ impl<'a> TableWidget<'a> {
|
||||
data_height,
|
||||
show_head,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
@ -268,12 +260,12 @@ impl<'a> TableWidget<'a> {
|
||||
return;
|
||||
}
|
||||
|
||||
let padding_l = self.style.column_padding_left as u16;
|
||||
let padding_r = self.style.column_padding_right as u16;
|
||||
let padding_l = self.config.column_padding_left as u16;
|
||||
let padding_r = self.config.column_padding_right as u16;
|
||||
|
||||
let show_index = self.style.show_index;
|
||||
let show_head = self.style.show_header;
|
||||
let splitline_s = self.style.splitline_style;
|
||||
let show_index = self.config.show_index;
|
||||
let show_head = self.config.show_header;
|
||||
let separator_s = self.config.separator_style;
|
||||
|
||||
let mut left_w = 0;
|
||||
|
||||
@ -295,7 +287,7 @@ impl<'a> TableWidget<'a> {
|
||||
area.height,
|
||||
false,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
@ -327,7 +319,7 @@ impl<'a> TableWidget<'a> {
|
||||
area.height,
|
||||
false,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
@ -352,7 +344,7 @@ impl<'a> TableWidget<'a> {
|
||||
area.height,
|
||||
false,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,10 @@
|
||||
use super::{
|
||||
record::{RecordView, TableTheme},
|
||||
util::{lookup_tui_color, nu_style_to_tui},
|
||||
Layout, Orientation, View, ViewConfig,
|
||||
};
|
||||
use super::{record::RecordView, util::nu_style_to_tui, Layout, Orientation, View, ViewConfig};
|
||||
use crate::{
|
||||
nu_common::{collect_pipeline, run_command_with_value},
|
||||
pager::{report::Report, Frame, Transition, ViewInfo},
|
||||
util::create_map,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use nu_color_config::get_color_map;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
PipelineData, Value,
|
||||
@ -22,26 +16,22 @@ use ratatui::{
|
||||
};
|
||||
use std::cmp::min;
|
||||
|
||||
pub struct InteractiveView<'a> {
|
||||
pub struct TryView<'a> {
|
||||
input: Value,
|
||||
command: String,
|
||||
immediate: bool,
|
||||
reactive: bool,
|
||||
table: Option<RecordView<'a>>,
|
||||
table_theme: TableTheme,
|
||||
view_mode: bool,
|
||||
border_color: Style,
|
||||
highlighted_color: Style,
|
||||
}
|
||||
|
||||
impl<'a> InteractiveView<'a> {
|
||||
impl<'a> TryView<'a> {
|
||||
pub fn new(input: Value) -> Self {
|
||||
Self {
|
||||
input,
|
||||
table: None,
|
||||
immediate: false,
|
||||
table_theme: TableTheme::default(),
|
||||
reactive: false,
|
||||
border_color: Style::default(),
|
||||
highlighted_color: Style::default(),
|
||||
view_mode: false,
|
||||
command: String::new(),
|
||||
}
|
||||
@ -52,18 +42,15 @@ impl<'a> InteractiveView<'a> {
|
||||
}
|
||||
|
||||
pub fn try_run(&mut self, engine_state: &EngineState, stack: &mut Stack) -> Result<()> {
|
||||
let mut view = run_command(&self.command, &self.input, engine_state, stack)?;
|
||||
view.set_theme(self.table_theme.clone());
|
||||
|
||||
let view = run_command(&self.command, &self.input, engine_state, stack)?;
|
||||
self.table = Some(view);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl View for InteractiveView<'_> {
|
||||
impl View for TryView<'_> {
|
||||
fn draw(&mut self, f: &mut Frame, area: Rect, cfg: ViewConfig<'_>, layout: &mut Layout) {
|
||||
let border_color = self.border_color;
|
||||
let highlighted_color = self.highlighted_color;
|
||||
|
||||
let cmd_block = ratatui::widgets::Block::default()
|
||||
.borders(Borders::ALL)
|
||||
@ -77,7 +64,7 @@ impl View for InteractiveView<'_> {
|
||||
cmd_block
|
||||
.border_style(Style::default().add_modifier(Modifier::BOLD))
|
||||
.border_type(BorderType::Double)
|
||||
.border_style(highlighted_color)
|
||||
.border_style(border_color)
|
||||
};
|
||||
|
||||
f.render_widget(cmd_block, cmd_area);
|
||||
@ -127,7 +114,7 @@ impl View for InteractiveView<'_> {
|
||||
table_block
|
||||
.border_style(Style::default().add_modifier(Modifier::BOLD))
|
||||
.border_type(BorderType::Double)
|
||||
.border_style(highlighted_color)
|
||||
.border_style(border_color)
|
||||
} else {
|
||||
table_block
|
||||
};
|
||||
@ -135,6 +122,7 @@ impl View for InteractiveView<'_> {
|
||||
f.render_widget(table_block, table_area);
|
||||
|
||||
if let Some(table) = &mut self.table {
|
||||
table.setup(cfg);
|
||||
let area = Rect::new(
|
||||
area.x + 2,
|
||||
area.y + 4,
|
||||
@ -190,7 +178,7 @@ impl View for InteractiveView<'_> {
|
||||
if !self.command.is_empty() {
|
||||
self.command.pop();
|
||||
|
||||
if self.immediate {
|
||||
if self.reactive {
|
||||
match self.try_run(engine_state, stack) {
|
||||
Ok(_) => info.report = Some(Report::default()),
|
||||
Err(err) => info.report = Some(Report::error(format!("Error: {err}"))),
|
||||
@ -203,7 +191,7 @@ impl View for InteractiveView<'_> {
|
||||
KeyCode::Char(c) => {
|
||||
self.command.push(*c);
|
||||
|
||||
if self.immediate {
|
||||
if self.reactive {
|
||||
match self.try_run(engine_state, stack) {
|
||||
Ok(_) => info.report = Some(Report::default()),
|
||||
Err(err) => info.report = Some(Report::error(format!("Error: {err}"))),
|
||||
@ -246,31 +234,14 @@ impl View for InteractiveView<'_> {
|
||||
}
|
||||
|
||||
fn setup(&mut self, config: ViewConfig<'_>) {
|
||||
self.border_color = lookup_tui_color(config.style_computer, "separator");
|
||||
|
||||
if let Some(hm) = config.config.get("try").and_then(create_map) {
|
||||
let colors = get_color_map(&hm);
|
||||
|
||||
if let Some(color) = colors.get("highlighted_color").copied() {
|
||||
self.highlighted_color = nu_style_to_tui(color);
|
||||
}
|
||||
|
||||
if self.border_color != Style::default() && self.highlighted_color == Style::default() {
|
||||
self.highlighted_color = self.border_color;
|
||||
}
|
||||
|
||||
if let Some(val) = hm.get("reactive").and_then(|v| v.as_bool().ok()) {
|
||||
self.immediate = val;
|
||||
}
|
||||
}
|
||||
self.border_color = nu_style_to_tui(config.explore_config.table.separator_style);
|
||||
self.reactive = config.explore_config.try_reactive;
|
||||
|
||||
let mut r = RecordView::new(vec![], vec![]);
|
||||
r.setup(config);
|
||||
|
||||
self.table_theme = r.get_theme().clone();
|
||||
|
||||
if let Some(view) = &mut self.table {
|
||||
view.set_theme(self.table_theme.clone());
|
||||
view.setup(config);
|
||||
view.set_orientation(r.get_orientation_current());
|
||||
view.set_orientation_current(r.get_orientation_current());
|
||||
}
|
@ -31,11 +31,6 @@ pub fn set_span(
|
||||
text_width as u16
|
||||
}
|
||||
|
||||
pub fn lookup_tui_color(style_computer: &StyleComputer, key: &str) -> Style {
|
||||
let nu_style = style_computer.compute(key, &Value::nothing(nu_protocol::Span::unknown()));
|
||||
nu_style_to_tui(nu_style)
|
||||
}
|
||||
|
||||
pub fn nu_style_to_tui(style: NuStyle) -> ratatui::style::Style {
|
||||
let mut out = ratatui::style::Style::default();
|
||||
if let Some(clr) = style.background {
|
||||
|
@ -189,12 +189,7 @@ $env.config = {
|
||||
warn: {}
|
||||
info: {}
|
||||
},
|
||||
table: {
|
||||
split_line: { fg: "#404040" },
|
||||
selected_cell: { bg: light_blue },
|
||||
selected_row: {},
|
||||
selected_column: {},
|
||||
},
|
||||
selected_cell: { bg: light_blue },
|
||||
}
|
||||
|
||||
history: {
|
||||
|
Loading…
Reference in New Issue
Block a user