explore: remove :config, :show-config, :tweak commands (#10259)

More trimming of underused `explore` functionality.

The `explore` command has subcommands that can be run like `:config` or
`:try` or whatnot. This PR removes the `:config`, `:show-config`, and
`:tweak` commands which are all for viewing+modifying config.

These are interesting commands and they were cool experiments, but
ultimately I don't think they fit with our plans for a simplified
`explore`. They'd need a lot more polish if we want to keep them and I
don't think we do. Happy to discuss if I've missed a good reason to keep
these.

cc @fdncred
This commit is contained in:
Reilly Wood
2023-09-07 08:34:08 -07:00
committed by GitHub
parent c7c6445b03
commit b6189879e3
16 changed files with 2 additions and 1010 deletions

View File

@@ -1,172 +0,0 @@
use std::io::Result;
use nu_protocol::{
engine::{EngineState, Stack},
record, Value,
};
use crate::{
nu_common::{nu_str, NuSpan},
registry::Command,
views::{configuration, ConfigurationView, Preview},
};
use super::{default_color_list, ConfigOption, HelpManual, ViewCommand};
#[derive(Default, Clone)]
pub struct ConfigCmd {
commands: Vec<Command>,
groups: Vec<ConfigOption>,
}
impl ConfigCmd {
pub const NAME: &'static str = "config";
pub fn from_commands(commands: Vec<Command>) -> Self {
Self {
commands,
groups: Vec::new(),
}
}
pub fn register_group(&mut self, group: ConfigOption) {
self.groups.push(group);
}
}
impl ViewCommand for ConfigCmd {
type View = ConfigurationView;
fn name(&self) -> &'static str {
Self::NAME
}
fn usage(&self) -> &'static str {
""
}
fn help(&self) -> Option<HelpManual> {
let config_options = vec![
ConfigOption::new(
":config options",
"A border color of menus",
"config.border_color",
default_color_list(),
),
ConfigOption::new(
":config options",
"Set a color of entries in a list",
"config.list_color",
default_color_list(),
),
ConfigOption::new(
":config options",
"Set a color of a chosen entry in a list",
"config.cursor_color",
default_color_list(),
),
];
Some(HelpManual {
name: Self::NAME,
description:
"Interactive configuration manager.\nCan be used to set various explore settings.\n\nLike an interactive version of :tweak",
config_options,
arguments: vec![],
examples: vec![],
input: vec![],
})
}
fn parse(&mut self, _: &str) -> Result<()> {
Ok(())
}
fn display_config_option(&mut self, _: String, _: String, _: String) -> bool {
false
}
fn spawn(
&mut self,
engine_state: &EngineState,
stack: &mut Stack,
_: Option<Value>,
) -> Result<Self::View> {
let mut options = vec![];
let default_table = create_default_value();
for cmd in &self.commands {
let cmd = match cmd {
Command::Reactive(_) => continue,
Command::View { cmd, .. } => cmd,
};
let help = match cmd.help() {
Some(help) => help,
None => continue,
};
for opt in help.config_options {
let mut values = vec![];
for value in opt.values {
let mut cmd = cmd.clone();
let can_be_displayed = cmd.display_config_option(
opt.group.clone(),
opt.key.clone(),
value.example.to_string(),
);
let view = if can_be_displayed {
cmd.spawn(engine_state, stack, Some(default_table.clone()))?
} else {
Box::new(Preview::new(&opt.description))
};
let option = configuration::ConfigOption::new(value.example.to_string(), view);
values.push(option);
}
let group = configuration::ConfigGroup::new(opt.key, values, opt.description);
options.push((opt.group, group));
}
}
for opt in &self.groups {
let mut values = vec![];
for value in &opt.values {
let view = Box::new(Preview::new(&opt.description));
let option = configuration::ConfigOption::new(value.example.to_string(), view);
values.push(option);
}
let group =
configuration::ConfigGroup::new(opt.key.clone(), values, opt.description.clone());
options.push((opt.group.clone(), group));
}
options.sort_by(|(group1, opt1), (group2, opt2)| {
group1.cmp(group2).then(opt1.group().cmp(opt2.group()))
});
let options = options.into_iter().map(|(_, opt)| opt).collect();
Ok(ConfigurationView::new(options))
}
}
fn create_default_value() -> Value {
let span = NuSpan::unknown();
let record = |i: usize| {
Value::record(
record! {
"key" => nu_str(format!("key-{i}")),
"value" => nu_str(format!("{i}")),
},
span,
)
};
Value::list(vec![record(0), record(1), record(2)], span)
}

View File

@@ -1,180 +0,0 @@
use nu_protocol::{
engine::{EngineState, Stack},
record, Value,
};
use ratatui::layout::Rect;
use std::collections::HashMap;
use std::io::Result;
use crate::{
nu_common::{try_build_table, NuSpan},
pager::Frame,
util::map_into_value,
views::{Layout, Preview, View, ViewConfig},
};
use super::{HelpExample, HelpManual, ViewCommand};
#[derive(Clone)]
pub struct ConfigShowCmd {
format: ConfigFormat,
}
#[derive(Clone)]
enum ConfigFormat {
Table,
Nu,
}
impl ConfigShowCmd {
pub fn new() -> Self {
ConfigShowCmd {
format: ConfigFormat::Table,
}
}
}
impl ConfigShowCmd {
pub const NAME: &'static str = "config-show";
}
impl ViewCommand for ConfigShowCmd {
type View = ConfigView;
fn name(&self) -> &'static str {
Self::NAME
}
fn usage(&self) -> &'static str {
""
}
fn help(&self) -> Option<HelpManual> {
Some(HelpManual {
name: Self::NAME,
description:
"Show the current `explore` configuration.\nSome default fields might be missing.",
arguments: vec![HelpExample::new("nu", "Use a nuon format instead")],
config_options: vec![],
input: vec![],
examples: vec![],
})
}
fn display_config_option(&mut self, _: String, _: String, _: String) -> bool {
false
}
fn parse(&mut self, args: &str) -> Result<()> {
if args.trim() == "nu" {
self.format = ConfigFormat::Nu;
}
Ok(())
}
fn spawn(&mut self, _: &EngineState, _: &mut Stack, _: Option<Value>) -> Result<Self::View> {
Ok(ConfigView {
preview: Preview::new(""),
format: self.format.clone(),
})
}
}
pub struct ConfigView {
preview: Preview,
format: ConfigFormat,
}
impl View for ConfigView {
fn draw(&mut self, f: &mut Frame, area: Rect, cfg: ViewConfig<'_>, layout: &mut Layout) {
self.preview.draw(f, area, cfg, layout)
}
fn handle_input(
&mut self,
engine_state: &EngineState,
stack: &mut Stack,
layout: &Layout,
info: &mut crate::pager::ViewInfo,
key: crossterm::event::KeyEvent,
) -> Option<crate::pager::Transition> {
self.preview
.handle_input(engine_state, stack, layout, info, key)
}
fn setup(&mut self, config: ViewConfig<'_>) {
let text = self.create_output_string(config);
self.preview = Preview::new(&text);
self.preview
.set_value(map_into_value(config.config.clone()));
}
fn exit(&mut self) -> Option<Value> {
self.preview.exit()
}
fn collect_data(&self) -> Vec<crate::nu_common::NuText> {
self.preview.collect_data()
}
fn show_data(&mut self, i: usize) -> bool {
self.preview.show_data(i)
}
}
impl ConfigView {
fn create_output_string(&mut self, config: ViewConfig) -> String {
match self.format {
ConfigFormat::Table => {
let mut m = config.config.clone();
convert_styles(&mut m);
let value = map_into_value(m);
try_build_table(None, config.nu_config, config.style_computer, value)
}
ConfigFormat::Nu => nu_json::to_string(&config.config).unwrap_or_default(),
}
}
}
fn convert_styles(m: &mut HashMap<String, Value>) {
for value in m.values_mut() {
convert_styles_value(value);
}
}
fn convert_styles_value(value: &mut Value) {
match value {
Value::String { val, .. } => {
if let Some(v) = convert_style_from_string(val) {
*value = v;
}
}
Value::List { vals, .. } => {
for value in vals {
convert_styles_value(value);
}
}
Value::Record { val, .. } => {
for value in &mut val.vals {
convert_styles_value(value);
}
}
_ => (),
}
}
fn convert_style_from_string(s: &str) -> Option<Value> {
let style = nu_json::from_str::<nu_color_config::NuStyle>(s).ok()?;
Some(Value::record(
record! {
"bg" => Value::string(style.bg.unwrap_or_default(), NuSpan::unknown()),
"fg" => Value::string(style.fg.unwrap_or_default(), NuSpan::unknown()),
"attr" => Value::string(style.attr.unwrap_or_default(), NuSpan::unknown()),
},
NuSpan::unknown(),
))
}

View File

@@ -60,10 +60,6 @@ impl ViewCommand for ExpandCmd {
})
}
fn display_config_option(&mut self, _: String, _: String, _: String) -> bool {
false
}
fn parse(&mut self, _: &str) -> Result<()> {
Ok(())
}

View File

@@ -104,10 +104,6 @@ impl ViewCommand for HelpCmd {
})
}
fn display_config_option(&mut self, _: String, _: String, _: String) -> bool {
false
}
fn parse(&mut self, args: &str) -> Result<()> {
self.input_command = args.trim().to_owned();

View File

@@ -13,19 +13,13 @@ mod nu;
mod quit;
mod table;
mod r#try;
mod tweak;
pub mod config;
mod config_show;
pub use config_show::ConfigShowCmd;
pub use expand::ExpandCmd;
pub use help::HelpCmd;
pub use nu::NuCmd;
pub use quit::QuitCmd;
pub use r#try::TryCmd;
pub use table::TableCmd;
pub use tweak::TweakCmd;
pub trait SimpleCommand {
fn name(&self) -> &'static str;
@@ -56,8 +50,6 @@ pub trait ViewCommand {
fn parse(&mut self, args: &str) -> Result<()>;
fn display_config_option(&mut self, group: String, key: String, value: String) -> bool;
fn spawn(
&mut self,
engine_state: &EngineState,

View File

@@ -64,10 +64,6 @@ impl ViewCommand for NuCmd {
})
}
fn display_config_option(&mut self, _: String, _: String, _: String) -> bool {
false
}
fn parse(&mut self, args: &str) -> Result<()> {
self.command = args.trim().to_owned();

View File

@@ -1,7 +1,6 @@
use std::io::Result;
use nu_ansi_term::Style;
use nu_color_config::lookup_ansi_color_style;
use nu_protocol::{
engine::{EngineState, Stack},
Value,
@@ -122,51 +121,6 @@ impl ViewCommand for TableCmd {
})
}
fn display_config_option(&mut self, _group: String, key: String, value: String) -> bool {
match key.as_str() {
"table.orientation" => self.settings.orientation = orientation_from_str(&value),
"table.line_head_top" => self.settings.line_head_top = bool_from_str(&value),
"table.line_head_bottom" => self.settings.line_head_bottom = bool_from_str(&value),
"table.line_shift" => self.settings.line_shift = bool_from_str(&value),
"table.line_index" => self.settings.line_index = bool_from_str(&value),
"table.show_cursor" => {
self.settings.show_cursor = bool_from_str(&value);
self.settings.turn_on_cursor_mode = true;
}
"table.split_line" => {
self.settings.split_line_s = Some(lookup_ansi_color_style(&value));
self.settings.turn_on_cursor_mode = true;
}
"table.selected_cell" => {
self.settings.selected_cell_s = Some(lookup_ansi_color_style(&value));
self.settings.turn_on_cursor_mode = true;
}
"table.selected_row" => {
self.settings.selected_row_s = Some(lookup_ansi_color_style(&value));
self.settings.turn_on_cursor_mode = true;
}
"table.selected_column" => {
self.settings.selected_column_s = Some(lookup_ansi_color_style(&value));
self.settings.turn_on_cursor_mode = true;
}
"table.padding_column_left" => {
self.settings.padding_column_left = usize_from_str(&value);
}
"table.padding_column_right" => {
self.settings.padding_column_right = usize_from_str(&value);
}
"table.padding_index_left" => {
self.settings.padding_index_left = usize_from_str(&value);
}
"table.padding_index_right" => {
self.settings.padding_index_right = usize_from_str(&value);
}
_ => return false,
}
true
}
fn parse(&mut self, _: &str) -> Result<()> {
Ok(())
}
@@ -257,25 +211,3 @@ impl ViewCommand for TableCmd {
Ok(view)
}
}
fn bool_from_str(s: &str) -> Option<bool> {
match s {
"true" => Some(true),
"false" => Some(false),
_ => None,
}
}
fn usize_from_str(s: &str) -> Option<usize> {
s.parse::<usize>().ok()
}
fn orientation_from_str(s: &str) -> Option<Orientation> {
match s {
"left" => Some(Orientation::Left),
"right" => Some(Orientation::Right),
"top" => Some(Orientation::Top),
"bottom" => Some(Orientation::Bottom),
_ => None,
}
}

View File

@@ -67,10 +67,6 @@ impl ViewCommand for TryCmd {
})
}
fn display_config_option(&mut self, _: String, _: String, _: String) -> bool {
false
}
fn parse(&mut self, args: &str) -> Result<()> {
self.command = args.trim().to_owned();

View File

@@ -1,92 +0,0 @@
use std::io::{self, Result};
use nu_protocol::{
engine::{EngineState, Stack},
Value,
};
use crate::{
nu_common::NuSpan,
pager::{Pager, Transition},
};
use super::{HelpExample, HelpManual, SimpleCommand};
#[derive(Default, Clone)]
pub struct TweakCmd {
path: Vec<String>,
value: Value,
}
impl TweakCmd {
pub const NAME: &'static str = "tweak";
}
impl SimpleCommand for TweakCmd {
fn name(&self) -> &'static str {
Self::NAME
}
fn usage(&self) -> &'static str {
""
}
fn help(&self) -> Option<HelpManual> {
Some(HelpManual {
name: "tweak",
description: "Set `explore` settings.\nLike a non-interactive version of :config",
arguments: vec![],
examples: vec![
HelpExample::new(":tweak table.show_index false", "Don't show index anymore"),
HelpExample::new(":tweak table.show_head false", "Don't show header anymore"),
HelpExample::new(
":tweak try.border_color {bg: '#FFFFFF', fg: '#F213F1'}",
"Make a different color for borders in :try",
),
],
config_options: vec![],
input: vec![],
})
}
fn parse(&mut self, input: &str) -> Result<()> {
let input = input.trim();
let args = input.split_once(' ');
let (key, value) = args.ok_or_else(|| {
io::Error::new(
io::ErrorKind::Other,
"expected to get 2 arguments 'key value'",
)
})?;
self.value = parse_value(value);
self.path = key
.split_terminator('.')
.map(|s| s.to_string())
.collect::<Vec<_>>();
Ok(())
}
fn react(
&mut self,
_: &EngineState,
_: &mut Stack,
p: &mut Pager<'_>,
_: Option<Value>,
) -> Result<Transition> {
p.set_config(&self.path, self.value.clone());
Ok(Transition::Ok)
}
}
fn parse_value(value: &str) -> Value {
match value {
"true" => Value::bool(true, NuSpan::unknown()),
"false" => Value::bool(false, NuSpan::unknown()),
s => Value::string(s.to_owned(), NuSpan::unknown()),
}
}