forked from extern/nushell
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:
parent
c7c6445b03
commit
b6189879e3
@ -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)
|
||||
}
|
@ -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(),
|
||||
))
|
||||
}
|
@ -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(())
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
@ -11,10 +11,7 @@ pub use explore::Explore;
|
||||
|
||||
use std::io;
|
||||
|
||||
use commands::{
|
||||
config::ConfigCmd, default_color_list, ConfigOption, ConfigShowCmd, ExpandCmd, HelpCmd,
|
||||
HelpManual, NuCmd, QuitCmd, TableCmd, TryCmd, TweakCmd,
|
||||
};
|
||||
use commands::{ExpandCmd, HelpCmd, HelpManual, NuCmd, QuitCmd, TableCmd, TryCmd};
|
||||
use nu_common::{collect_pipeline, has_simple_value, CtrlC};
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
@ -96,10 +93,8 @@ fn create_command_registry() -> CommandRegistry {
|
||||
let aliases = registry.get_aliases().collect::<Vec<_>>();
|
||||
|
||||
let help_cmd = create_help_command(&commands, &aliases);
|
||||
let config_cmd = create_config_command(&commands);
|
||||
|
||||
registry.register_command_view(help_cmd, true);
|
||||
registry.register_command_view(config_cmd, true);
|
||||
|
||||
registry
|
||||
}
|
||||
@ -110,12 +105,9 @@ fn create_commands(registry: &mut CommandRegistry) {
|
||||
|
||||
registry.register_command_view(ExpandCmd::new(), true);
|
||||
registry.register_command_view(TryCmd::new(), true);
|
||||
registry.register_command_view(ConfigShowCmd::new(), true);
|
||||
registry.register_command_view(ConfigCmd::default(), true);
|
||||
registry.register_command_view(HelpCmd::default(), true);
|
||||
|
||||
registry.register_command_reactive(QuitCmd);
|
||||
registry.register_command_reactive(TweakCmd::default());
|
||||
}
|
||||
|
||||
fn create_aliases(registry: &mut CommandRegistry) {
|
||||
@ -125,28 +117,6 @@ fn create_aliases(registry: &mut CommandRegistry) {
|
||||
registry.create_aliases("q!", QuitCmd::NAME);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn create_config_command(commands: &[Command]) -> ConfigCmd {
|
||||
const GROUP: &str = "Explore configuration";
|
||||
|
||||
let mut config = ConfigCmd::from_commands(commands.to_vec());
|
||||
|
||||
config.register_group(ConfigOption::new(GROUP, "Status bar information color", "status.info", default_color_list()));
|
||||
config.register_group(ConfigOption::new(GROUP, "Status bar success color", "status.success", default_color_list()));
|
||||
config.register_group(ConfigOption::new(GROUP, "Status bar warning color", "status.warn", default_color_list()));
|
||||
config.register_group(ConfigOption::new(GROUP, "Status bar error color", "status.error", default_color_list()));
|
||||
|
||||
config.register_group(ConfigOption::new(GROUP, "Status bar default text color", "status_bar_text", default_color_list()));
|
||||
config.register_group(ConfigOption::new(GROUP, "Status bar background", "status_bar_background", default_color_list()));
|
||||
|
||||
config.register_group(ConfigOption::new(GROUP, "Command bar text color", "command_bar_text", default_color_list()));
|
||||
config.register_group(ConfigOption::new(GROUP, "Command bar background", "command_bar_background", default_color_list()));
|
||||
|
||||
config.register_group(ConfigOption::new(GROUP, "Highlight color in search", "highlight", default_color_list()));
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
fn create_help_command(commands: &[Command], aliases: &[(&str, &str)]) -> HelpCmd {
|
||||
let help_manuals = create_help_manuals(commands);
|
||||
|
||||
|
@ -19,7 +19,7 @@ pub use command::{is_ignored_command, run_command_with_value, run_nu_command};
|
||||
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, nu_str};
|
||||
pub use value::{collect_input, collect_pipeline, create_map, map_into_value};
|
||||
|
||||
pub fn has_simple_value(data: &[Vec<Value>]) -> Option<&Value> {
|
||||
if data.len() == 1
|
||||
|
@ -194,10 +194,6 @@ pub fn map_into_value(hm: HashMap<String, Value>) -> Value {
|
||||
Value::record(hm.into_iter().collect(), NuSpan::unknown())
|
||||
}
|
||||
|
||||
pub fn nu_str<S: AsRef<str>>(s: S) -> Value {
|
||||
Value::string(s.as_ref().to_owned(), NuSpan::unknown())
|
||||
}
|
||||
|
||||
fn unknown_error_value() -> Value {
|
||||
Value::string(String::from("❎"), NuSpan::unknown())
|
||||
}
|
||||
|
@ -72,10 +72,6 @@ where
|
||||
self.0.help()
|
||||
}
|
||||
|
||||
fn display_config_option(&mut self, group: String, key: String, value: String) -> bool {
|
||||
self.0.display_config_option(group, key, value)
|
||||
}
|
||||
|
||||
fn parse(&mut self, args: &str) -> std::io::Result<()> {
|
||||
self.0.parse(args)
|
||||
}
|
||||
|
@ -1,427 +0,0 @@
|
||||
use std::{cmp::Ordering, fmt::Debug, ptr::addr_of};
|
||||
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use nu_color_config::get_color_map;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Value,
|
||||
};
|
||||
use nu_table::TextStyle;
|
||||
use ratatui::{
|
||||
layout::Rect,
|
||||
style::Style,
|
||||
widgets::{BorderType, Borders, Paragraph},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
nu_common::{truncate_str, NuText},
|
||||
pager::{Frame, Transition, ViewInfo},
|
||||
util::create_map,
|
||||
views::util::nu_style_to_tui,
|
||||
};
|
||||
|
||||
use super::{cursor::WindowCursor, Layout, View, ViewConfig};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ConfigurationView {
|
||||
options: Vec<ConfigGroup>,
|
||||
peeked_cursor: Option<WindowCursor>,
|
||||
cursor: WindowCursor,
|
||||
border_color: Style,
|
||||
cursor_color: Style,
|
||||
list_color: Style,
|
||||
}
|
||||
|
||||
impl ConfigurationView {
|
||||
pub fn new(options: Vec<ConfigGroup>) -> Self {
|
||||
let cursor = WindowCursor::new(options.len(), options.len()).expect("...");
|
||||
|
||||
Self {
|
||||
options,
|
||||
cursor,
|
||||
peeked_cursor: None,
|
||||
border_color: Style::default(),
|
||||
cursor_color: Style::default(),
|
||||
list_color: Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_cursors(&mut self, height: usize) {
|
||||
self.cursor.set_window(height);
|
||||
|
||||
if let Some(cursor) = &mut self.peeked_cursor {
|
||||
cursor.set_window(height);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_option_list(
|
||||
&mut self,
|
||||
f: &mut Frame,
|
||||
area: Rect,
|
||||
list_color: Style,
|
||||
cursor_color: Style,
|
||||
layout: &mut Layout,
|
||||
) {
|
||||
let (data, data_c) = match self.peeked_cursor {
|
||||
Some(cursor) => {
|
||||
let i = self.cursor.index();
|
||||
let opt = &self.options[i];
|
||||
let data = opt
|
||||
.options
|
||||
.iter()
|
||||
.map(|e| e.name.clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(data, cursor)
|
||||
}
|
||||
None => {
|
||||
let data = self
|
||||
.options
|
||||
.iter()
|
||||
.map(|o| o.group.clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(data, self.cursor)
|
||||
}
|
||||
};
|
||||
|
||||
render_list(f, area, &data, data_c, list_color, cursor_color, layout);
|
||||
}
|
||||
|
||||
fn peek_current(&self) -> Option<(&ConfigGroup, &ConfigOption)> {
|
||||
let cursor = match self.peeked_cursor {
|
||||
Some(cursor) => cursor,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let i = self.cursor.index();
|
||||
let j = cursor.index();
|
||||
let group = &self.options[i];
|
||||
let opt = &group.options[j];
|
||||
|
||||
Some((group, opt))
|
||||
}
|
||||
|
||||
fn peek_current_group(&self) -> &ConfigGroup {
|
||||
let i = self.cursor.index();
|
||||
&self.options[i]
|
||||
}
|
||||
|
||||
fn peek_current_opt(&mut self) -> Option<&mut ConfigOption> {
|
||||
let cursor = match self.peeked_cursor {
|
||||
Some(cursor) => cursor,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let i = self.cursor.index();
|
||||
let j = cursor.index();
|
||||
|
||||
Some(&mut self.options[i].options[j])
|
||||
}
|
||||
|
||||
fn get_cursor_mut(&mut self) -> &mut WindowCursor {
|
||||
self.peeked_cursor.as_mut().unwrap_or(&mut self.cursor)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ConfigGroup {
|
||||
group: String,
|
||||
description: String,
|
||||
options: Vec<ConfigOption>,
|
||||
}
|
||||
|
||||
impl ConfigGroup {
|
||||
pub fn new(group: String, options: Vec<ConfigOption>, description: String) -> Self {
|
||||
Self {
|
||||
group,
|
||||
options,
|
||||
description,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn group(&self) -> &str {
|
||||
self.group.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConfigOption {
|
||||
name: String,
|
||||
view: Box<dyn View>,
|
||||
}
|
||||
|
||||
impl ConfigOption {
|
||||
pub fn new(name: String, view: Box<dyn View>) -> Self {
|
||||
Self { name, view }
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for ConfigOption {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ConfigOption")
|
||||
.field("name", &self.name)
|
||||
.field("view", &addr_of!(self.view))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl View for ConfigurationView {
|
||||
fn draw(&mut self, f: &mut Frame, area: Rect, cfg: ViewConfig<'_>, layout: &mut Layout) {
|
||||
const LEFT_PADDING: u16 = 1;
|
||||
const BLOCK_PADDING: u16 = 1;
|
||||
const OPTION_BLOCK_WIDTH: u16 = 30;
|
||||
const USED_HEIGHT_BY_BORDERS: u16 = 2;
|
||||
|
||||
if area.width < 40 {
|
||||
return;
|
||||
}
|
||||
|
||||
let list_color = self.list_color;
|
||||
let border_color = self.border_color;
|
||||
let cursor_color = self.cursor_color;
|
||||
|
||||
let height = area.height - USED_HEIGHT_BY_BORDERS;
|
||||
|
||||
let option_b_x1 = area.x + LEFT_PADDING;
|
||||
let option_b_x2 = area.x + LEFT_PADDING + OPTION_BLOCK_WIDTH;
|
||||
|
||||
let view_b_x1 = option_b_x2 + BLOCK_PADDING;
|
||||
let view_b_w = area.width - (LEFT_PADDING + BLOCK_PADDING + OPTION_BLOCK_WIDTH);
|
||||
|
||||
let option_content_x1 = option_b_x1 + 1;
|
||||
let option_content_w = OPTION_BLOCK_WIDTH - 2;
|
||||
let option_content_h = height;
|
||||
|
||||
let option_content_area =
|
||||
Rect::new(option_content_x1, 1, option_content_w, option_content_h);
|
||||
|
||||
let view_content_x1 = view_b_x1 + 1;
|
||||
let view_content_w = view_b_w - 2;
|
||||
let view_content_h = height;
|
||||
|
||||
let view_content_area = Rect::new(view_content_x1, 1, view_content_w, view_content_h);
|
||||
|
||||
let option_block = ratatui::widgets::Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Plain)
|
||||
.border_style(border_color);
|
||||
let option_area = Rect::new(option_b_x1, area.y, OPTION_BLOCK_WIDTH, area.height);
|
||||
|
||||
let view_block = ratatui::widgets::Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Plain)
|
||||
.border_style(border_color);
|
||||
let view_area = Rect::new(view_b_x1, area.y, view_b_w, area.height);
|
||||
|
||||
f.render_widget(option_block, option_area);
|
||||
f.render_widget(view_block, view_area);
|
||||
|
||||
self.render_option_list(f, option_content_area, list_color, cursor_color, layout);
|
||||
|
||||
if let Some(opt) = self.peek_current_opt() {
|
||||
let mut layout = Layout::default();
|
||||
opt.view.draw(f, view_content_area, cfg, &mut layout);
|
||||
} else {
|
||||
let group = self.peek_current_group();
|
||||
let description = &group.description;
|
||||
|
||||
f.render_widget(Paragraph::new(description.as_str()), view_content_area);
|
||||
}
|
||||
|
||||
self.update_cursors(height as usize);
|
||||
}
|
||||
|
||||
fn handle_input(
|
||||
&mut self,
|
||||
_: &EngineState,
|
||||
_: &mut Stack,
|
||||
_: &Layout,
|
||||
_: &mut ViewInfo,
|
||||
key: KeyEvent,
|
||||
) -> Option<Transition> {
|
||||
match key.code {
|
||||
KeyCode::Esc => {
|
||||
if self.peeked_cursor.is_some() {
|
||||
self.peeked_cursor = None;
|
||||
Some(Transition::Ok)
|
||||
} else {
|
||||
Some(Transition::Exit)
|
||||
}
|
||||
}
|
||||
KeyCode::Up => {
|
||||
let cursor = self.get_cursor_mut();
|
||||
cursor.prev(1);
|
||||
|
||||
Some(transition_tweak_if(self))
|
||||
}
|
||||
KeyCode::Down => {
|
||||
let cursor = self.get_cursor_mut();
|
||||
cursor.next(1);
|
||||
|
||||
Some(transition_tweak_if(self))
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
let cursor = self.get_cursor_mut();
|
||||
cursor.prev_window();
|
||||
|
||||
Some(transition_tweak_if(self))
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
let cursor = self.get_cursor_mut();
|
||||
cursor.next_window();
|
||||
|
||||
Some(transition_tweak_if(self))
|
||||
}
|
||||
KeyCode::Home => {
|
||||
let cursor = self.get_cursor_mut();
|
||||
cursor.prev(cursor.index());
|
||||
|
||||
Some(transition_tweak_if(self))
|
||||
}
|
||||
KeyCode::End => {
|
||||
let cursor = self.get_cursor_mut();
|
||||
cursor.next(cursor.cap());
|
||||
|
||||
Some(transition_tweak_if(self))
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
if self.peeked_cursor.is_some() {
|
||||
return Some(Transition::Ok);
|
||||
}
|
||||
|
||||
self.peeked_cursor = Some(WindowCursor::default());
|
||||
let length = self.peek_current().expect("...").0.options.len();
|
||||
self.peeked_cursor = WindowCursor::new(length, length);
|
||||
|
||||
let (group, opt) = self.peek_current().expect("...");
|
||||
|
||||
Some(Transition::Cmd(build_tweak_cmd(group, opt)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn exit(&mut self) -> Option<Value> {
|
||||
None
|
||||
}
|
||||
|
||||
fn collect_data(&self) -> Vec<NuText> {
|
||||
if self.peeked_cursor.is_some() {
|
||||
let i = self.cursor.index();
|
||||
let opt = &self.options[i];
|
||||
opt.options
|
||||
.iter()
|
||||
.map(|e| (e.name.clone(), TextStyle::default()))
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
self.options
|
||||
.iter()
|
||||
.map(|s| (s.group.to_string(), TextStyle::default()))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn show_data(&mut self, i: usize) -> bool {
|
||||
if let Some(c) = &mut self.peeked_cursor {
|
||||
let i = self.cursor.index();
|
||||
if i > self.options[i].options.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
loop {
|
||||
let p = c.index();
|
||||
match i.cmp(&p) {
|
||||
Ordering::Equal => return true,
|
||||
Ordering::Less => c.prev(1),
|
||||
Ordering::Greater => c.next(1),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if i > self.options.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
loop {
|
||||
let p = self.cursor.index();
|
||||
match i.cmp(&p) {
|
||||
Ordering::Equal => return true,
|
||||
Ordering::Less => self.cursor.prev(1),
|
||||
Ordering::Greater => self.cursor.next(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn setup(&mut self, config: ViewConfig<'_>) {
|
||||
if let Some(hm) = config.config.get("config").and_then(create_map) {
|
||||
let colors = get_color_map(&hm);
|
||||
|
||||
if let Some(style) = colors.get("border_color").copied() {
|
||||
self.border_color = nu_style_to_tui(style);
|
||||
}
|
||||
|
||||
if let Some(style) = colors.get("cursor_color").copied() {
|
||||
self.cursor_color = nu_style_to_tui(style);
|
||||
}
|
||||
|
||||
if let Some(style) = colors.get("list_color").copied() {
|
||||
self.list_color = nu_style_to_tui(style);
|
||||
}
|
||||
}
|
||||
|
||||
for group in &mut self.options {
|
||||
for opt in &mut group.options {
|
||||
opt.view.setup(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_tweak_cmd(group: &ConfigGroup, opt: &ConfigOption) -> String {
|
||||
format!("tweak {} {}", group.group(), opt.name)
|
||||
}
|
||||
|
||||
fn render_list(
|
||||
f: &mut Frame,
|
||||
area: Rect,
|
||||
data: &[String],
|
||||
cursor: WindowCursor,
|
||||
not_picked_s: Style,
|
||||
picked_s: Style,
|
||||
layout: &mut Layout,
|
||||
) {
|
||||
let height = area.height as usize;
|
||||
let width = area.width as usize;
|
||||
|
||||
let mut data = &data[cursor.starts_at()..];
|
||||
if data.len() > height {
|
||||
data = &data[..height];
|
||||
}
|
||||
|
||||
let selected_row = cursor.offset();
|
||||
|
||||
for (i, name) in data.iter().enumerate() {
|
||||
let mut name = name.to_owned();
|
||||
truncate_str(&mut name, width);
|
||||
|
||||
let area = Rect::new(area.x, area.y + i as u16, area.width, 1);
|
||||
|
||||
let mut text = Paragraph::new(name.clone());
|
||||
|
||||
if i == selected_row {
|
||||
text = text.style(picked_s);
|
||||
} else {
|
||||
text = text.style(not_picked_s);
|
||||
}
|
||||
|
||||
f.render_widget(text, area);
|
||||
|
||||
layout.push(&name, area.x, area.y, area.width, 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn transition_tweak_if(view: &ConfigurationView) -> Transition {
|
||||
view.peek_current().map_or(Transition::Ok, |(group, opt)| {
|
||||
Transition::Cmd(build_tweak_cmd(group, opt))
|
||||
})
|
||||
}
|
@ -22,9 +22,6 @@ use super::{
|
||||
pager::{Frame, Transition, ViewInfo},
|
||||
};
|
||||
|
||||
pub mod configuration;
|
||||
|
||||
pub use configuration::ConfigurationView;
|
||||
pub use information::InformationView;
|
||||
pub use interactive::InteractiveView;
|
||||
pub use preview::Preview;
|
||||
|
@ -37,10 +37,6 @@ impl Preview {
|
||||
underlying_value: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_value(&mut self, value: Value) {
|
||||
self.underlying_value = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
impl View for Preview {
|
||||
|
Loading…
Reference in New Issue
Block a user