mirror of
https://github.com/nushell/nushell.git
synced 2024-11-28 19:33:47 +01:00
menu options (#748)
This commit is contained in:
parent
f9c0d223c1
commit
89d99db94f
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -2845,7 +2845,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "reedline"
|
name = "reedline"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/nushell/reedline?branch=main#56025adb65f1c27078d64e5d6220827a6f0ebdb3"
|
source = "git+https://github.com/nushell/reedline?branch=main#4c3c23c9594ab2d58015fc75beb9fd884b763614"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
|
@ -4,9 +4,9 @@ use nu_protocol::Config;
|
|||||||
use nu_table::{Alignment, TextStyle};
|
use nu_table::{Alignment, TextStyle};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn lookup_ansi_color_style(s: String) -> Style {
|
pub fn lookup_ansi_color_style(s: &str) -> Style {
|
||||||
if s.starts_with('#') {
|
if s.starts_with('#') {
|
||||||
match color_from_hex(&s) {
|
match color_from_hex(s) {
|
||||||
Ok(c) => match c {
|
Ok(c) => match c {
|
||||||
Some(c) => c.normal(),
|
Some(c) => c.normal(),
|
||||||
None => Style::default(),
|
None => Style::default(),
|
||||||
@ -14,9 +14,9 @@ pub fn lookup_ansi_color_style(s: String) -> Style {
|
|||||||
Err(_) => Style::default(),
|
Err(_) => Style::default(),
|
||||||
}
|
}
|
||||||
} else if s.starts_with('{') {
|
} else if s.starts_with('{') {
|
||||||
color_string_to_nustyle(s)
|
color_string_to_nustyle(s.to_string())
|
||||||
} else {
|
} else {
|
||||||
match s.as_str() {
|
match s {
|
||||||
"g" | "green" => Color::Green.normal(),
|
"g" | "green" => Color::Green.normal(),
|
||||||
"gb" | "green_bold" => Color::Green.bold(),
|
"gb" | "green_bold" => Color::Green.bold(),
|
||||||
"gu" | "green_underline" => Color::Green.underline(),
|
"gu" | "green_underline" => Color::Green.underline(),
|
||||||
@ -168,7 +168,7 @@ pub fn lookup_ansi_color_style(s: String) -> Style {
|
|||||||
|
|
||||||
fn update_hashmap(key: &str, val: &str, hm: &mut HashMap<String, Style>) {
|
fn update_hashmap(key: &str, val: &str, hm: &mut HashMap<String, Style>) {
|
||||||
// eprintln!("key: {}, val: {}", &key, &val);
|
// eprintln!("key: {}, val: {}", &key, &val);
|
||||||
let color = lookup_ansi_color_style(val.to_string());
|
let color = lookup_ansi_color_style(val);
|
||||||
if let Some(v) = hm.get_mut(key) {
|
if let Some(v) = hm.get_mut(key) {
|
||||||
*v = color;
|
*v = color;
|
||||||
} else {
|
} else {
|
||||||
@ -210,7 +210,10 @@ pub fn get_color_config(config: &Config) -> HashMap<String, Style> {
|
|||||||
hm.insert("hints".to_string(), Color::DarkGray.normal());
|
hm.insert("hints".to_string(), Color::DarkGray.normal());
|
||||||
|
|
||||||
for (key, value) in &config.color_config {
|
for (key, value) in &config.color_config {
|
||||||
update_hashmap(key, value, &mut hm);
|
let value = value
|
||||||
|
.as_string()
|
||||||
|
.expect("the only values for config color must be strings");
|
||||||
|
update_hashmap(key, &value, &mut hm);
|
||||||
|
|
||||||
// eprintln!(
|
// eprintln!(
|
||||||
// "config: {}:{}\t\t\thashmap: {}:{:?}",
|
// "config: {}:{}\t\t\thashmap: {}:{:?}",
|
||||||
|
@ -4,7 +4,10 @@ use nu_protocol::Config;
|
|||||||
|
|
||||||
pub fn get_shape_color(shape: String, conf: &Config) -> Style {
|
pub fn get_shape_color(shape: String, conf: &Config) -> Style {
|
||||||
match conf.color_config.get(shape.as_str()) {
|
match conf.color_config.get(shape.as_str()) {
|
||||||
Some(int_color) => lookup_ansi_color_style(int_color.to_string()),
|
Some(int_color) => match int_color.as_string() {
|
||||||
|
Ok(int_color) => lookup_ansi_color_style(&int_color),
|
||||||
|
Err(_) => Style::default(),
|
||||||
|
},
|
||||||
None => match shape.as_ref() {
|
None => match shape.as_ref() {
|
||||||
"flatshape_garbage" => Style::new().fg(Color::White).on(Color::Red).bold(),
|
"flatshape_garbage" => Style::new().fg(Color::White).on(Color::Red).bold(),
|
||||||
"flatshape_bool" => Style::new().fg(Color::LightCyan),
|
"flatshape_bool" => Style::new().fg(Color::LightCyan),
|
||||||
|
@ -43,7 +43,7 @@ pub struct Config {
|
|||||||
pub filesize_metric: bool,
|
pub filesize_metric: bool,
|
||||||
pub table_mode: String,
|
pub table_mode: String,
|
||||||
pub use_ls_colors: bool,
|
pub use_ls_colors: bool,
|
||||||
pub color_config: HashMap<String, String>,
|
pub color_config: HashMap<String, Value>,
|
||||||
pub use_grid_icons: bool,
|
pub use_grid_icons: bool,
|
||||||
pub footer_mode: FooterMode,
|
pub footer_mode: FooterMode,
|
||||||
pub animate_prompt: bool,
|
pub animate_prompt: bool,
|
||||||
@ -54,6 +54,7 @@ pub struct Config {
|
|||||||
pub edit_mode: String,
|
pub edit_mode: String,
|
||||||
pub max_history_size: i64,
|
pub max_history_size: i64,
|
||||||
pub log_level: String,
|
pub log_level: String,
|
||||||
|
pub menu_config: HashMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -73,6 +74,7 @@ impl Default for Config {
|
|||||||
edit_mode: "emacs".into(),
|
edit_mode: "emacs".into(),
|
||||||
max_history_size: 1000,
|
max_history_size: 1000,
|
||||||
log_level: String::new(),
|
log_level: String::new(),
|
||||||
|
menu_config: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,42 +109,7 @@ impl Value {
|
|||||||
config.use_ls_colors = value.as_bool()?;
|
config.use_ls_colors = value.as_bool()?;
|
||||||
}
|
}
|
||||||
"color_config" => {
|
"color_config" => {
|
||||||
let (cols, inner_vals) = value.as_record()?;
|
config.color_config = create_map(value, &config)?;
|
||||||
let mut hm = HashMap::new();
|
|
||||||
for (k, v) in cols.iter().zip(inner_vals) {
|
|
||||||
match &v {
|
|
||||||
Value::Record {
|
|
||||||
cols: inner_cols,
|
|
||||||
vals: inner_vals,
|
|
||||||
span: _,
|
|
||||||
} => {
|
|
||||||
// make a string from our config.color_config section that
|
|
||||||
// looks like this: { fg: "#rrggbb" bg: "#rrggbb" attr: "abc", }
|
|
||||||
// the real key here was to have quotes around the values but not
|
|
||||||
// require them around the keys.
|
|
||||||
|
|
||||||
// maybe there's a better way to generate this but i'm not sure
|
|
||||||
// what it is.
|
|
||||||
let key = k.to_string();
|
|
||||||
let mut val: String = inner_cols
|
|
||||||
.iter()
|
|
||||||
.zip(inner_vals)
|
|
||||||
.map(|(x, y)| {
|
|
||||||
let clony = y.clone();
|
|
||||||
format!("{}: \"{}\" ", x, clony.into_string(", ", &config))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
// now insert the braces at the front and the back to fake the json string
|
|
||||||
val.insert(0, '{');
|
|
||||||
val.push('}');
|
|
||||||
hm.insert(key, val);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
hm.insert(k.to_string(), v.as_string()?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.color_config = hm;
|
|
||||||
}
|
}
|
||||||
"use_grid_icons" => {
|
"use_grid_icons" => {
|
||||||
config.use_grid_icons = value.as_bool()?;
|
config.use_grid_icons = value.as_bool()?;
|
||||||
@ -191,6 +158,9 @@ impl Value {
|
|||||||
"log_level" => {
|
"log_level" => {
|
||||||
config.log_level = value.as_string()?;
|
config.log_level = value.as_string()?;
|
||||||
}
|
}
|
||||||
|
"menu_config" => {
|
||||||
|
config.menu_config = create_map(value, &config)?;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,3 +168,48 @@ impl Value {
|
|||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_map(value: &Value, config: &Config) -> Result<HashMap<String, Value>, ShellError> {
|
||||||
|
let (cols, inner_vals) = value.as_record()?;
|
||||||
|
let mut hm: HashMap<String, Value> = HashMap::new();
|
||||||
|
|
||||||
|
for (k, v) in cols.iter().zip(inner_vals) {
|
||||||
|
match &v {
|
||||||
|
Value::Record {
|
||||||
|
cols: inner_cols,
|
||||||
|
vals: inner_vals,
|
||||||
|
span,
|
||||||
|
} => {
|
||||||
|
// make a string from our config.color_config section that
|
||||||
|
// looks like this: { fg: "#rrggbb" bg: "#rrggbb" attr: "abc", }
|
||||||
|
// the real key here was to have quotes around the values but not
|
||||||
|
// require them around the keys.
|
||||||
|
|
||||||
|
// maybe there's a better way to generate this but i'm not sure
|
||||||
|
// what it is.
|
||||||
|
let key = k.to_string();
|
||||||
|
let val: String = inner_cols
|
||||||
|
.iter()
|
||||||
|
.zip(inner_vals)
|
||||||
|
.map(|(x, y)| {
|
||||||
|
let clony = y.clone();
|
||||||
|
format!("{}: \"{}\" ", x, clony.into_string(", ", config))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// now insert the braces at the front and the back to fake the json string
|
||||||
|
let val = Value::String {
|
||||||
|
val: format!("{{{}}}", val),
|
||||||
|
span: *span,
|
||||||
|
};
|
||||||
|
|
||||||
|
hm.insert(key, val);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
hm.insert(k.to_string(), v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(hm)
|
||||||
|
}
|
||||||
|
64
src/main.rs
64
src/main.rs
@ -9,7 +9,7 @@ use dialoguer::{
|
|||||||
use log::trace;
|
use log::trace;
|
||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
use nu_cli::{CliError, NuCompleter, NuHighlighter, NuValidator, NushellPrompt};
|
use nu_cli::{CliError, NuCompleter, NuHighlighter, NuValidator, NushellPrompt};
|
||||||
use nu_color_config::get_color_config;
|
use nu_color_config::{get_color_config, lookup_ansi_color_style};
|
||||||
use nu_command::create_default_context;
|
use nu_command::create_default_context;
|
||||||
use nu_engine::{convert_env_values, eval_block};
|
use nu_engine::{convert_env_values, eval_block};
|
||||||
use nu_parser::{lex, parse, trim_quotes, Token, TokenContents};
|
use nu_parser::{lex, parse, trim_quotes, Token, TokenContents};
|
||||||
@ -19,8 +19,8 @@ use nu_protocol::{
|
|||||||
Config, PipelineData, ShellError, Span, Value, CONFIG_VARIABLE_ID,
|
Config, PipelineData, ShellError, Span, Value, CONFIG_VARIABLE_ID,
|
||||||
};
|
};
|
||||||
use reedline::{
|
use reedline::{
|
||||||
default_emacs_keybindings, Completer, CompletionActionHandler, DefaultHinter, EditCommand,
|
default_emacs_keybindings, Completer, CompletionActionHandler, ContextMenuInput, DefaultHinter,
|
||||||
Emacs, LineBuffer, Prompt, ReedlineEvent, Vi,
|
EditCommand, Emacs, LineBuffer, Prompt, ReedlineEvent, Vi,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
io::Write,
|
||||||
@ -435,7 +435,11 @@ fn main() -> Result<()> {
|
|||||||
}))
|
}))
|
||||||
.with_edit_mode(edit_mode)
|
.with_edit_mode(edit_mode)
|
||||||
.with_ansi_colors(config.use_ansi_coloring)
|
.with_ansi_colors(config.use_ansi_coloring)
|
||||||
.with_menu_completer(Box::new(NuCompleter::new(engine_state.clone())));
|
.with_menu_completer(
|
||||||
|
Box::new(NuCompleter::new(engine_state.clone())),
|
||||||
|
create_menu_input(&config),
|
||||||
|
);
|
||||||
|
|
||||||
//FIXME: if config.use_ansi_coloring is false then we should
|
//FIXME: if config.use_ansi_coloring is false then we should
|
||||||
// turn off the hinter but I don't see any way to do that yet.
|
// turn off the hinter but I don't see any way to do that yet.
|
||||||
|
|
||||||
@ -587,6 +591,58 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This creates an input object for the context menu based on the dictionary
|
||||||
|
// stored in the config variable
|
||||||
|
fn create_menu_input(config: &Config) -> ContextMenuInput {
|
||||||
|
let mut input = ContextMenuInput::default();
|
||||||
|
|
||||||
|
input = match config
|
||||||
|
.menu_config
|
||||||
|
.get("columns")
|
||||||
|
.and_then(|value| value.as_integer().ok())
|
||||||
|
{
|
||||||
|
Some(value) => input.with_columns(value as u16),
|
||||||
|
None => input,
|
||||||
|
};
|
||||||
|
|
||||||
|
input = input.with_col_width(
|
||||||
|
config
|
||||||
|
.menu_config
|
||||||
|
.get("col_width")
|
||||||
|
.and_then(|value| value.as_integer().ok())
|
||||||
|
.map(|value| value as usize),
|
||||||
|
);
|
||||||
|
|
||||||
|
input = match config
|
||||||
|
.menu_config
|
||||||
|
.get("col_padding")
|
||||||
|
.and_then(|value| value.as_integer().ok())
|
||||||
|
{
|
||||||
|
Some(value) => input.with_col_padding(value as usize),
|
||||||
|
None => input,
|
||||||
|
};
|
||||||
|
|
||||||
|
input = match config
|
||||||
|
.menu_config
|
||||||
|
.get("text_style")
|
||||||
|
.and_then(|value| value.as_string().ok())
|
||||||
|
{
|
||||||
|
Some(value) => input.with_text_style(lookup_ansi_color_style(&value)),
|
||||||
|
None => input,
|
||||||
|
};
|
||||||
|
|
||||||
|
input = match config
|
||||||
|
.menu_config
|
||||||
|
.get("selected_text_style")
|
||||||
|
.and_then(|value| value.as_string().ok())
|
||||||
|
{
|
||||||
|
Some(value) => input.with_selected_text_style(lookup_ansi_color_style(&value)),
|
||||||
|
None => input,
|
||||||
|
};
|
||||||
|
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
// This fill collect environment variables from std::env and adds them to a stack.
|
// This fill collect environment variables from std::env and adds them to a stack.
|
||||||
//
|
//
|
||||||
// In order to ensure the values have spans, it first creates a dummy file, writes the collected
|
// In order to ensure the values have spans, it first creates a dummy file, writes the collected
|
||||||
|
Loading…
Reference in New Issue
Block a user