2022-02-20 15:27:59 +01:00
use crate ::{ ShellError , Span , Value } ;
2021-11-20 14:12:35 +01:00
use serde ::{ Deserialize , Serialize } ;
use std ::collections ::HashMap ;
2021-11-14 20:25:57 +01:00
2022-07-12 18:23:50 +02:00
const TRIM_STRATEGY_DEFAULT : TrimStrategy = TrimStrategy ::Wrap {
try_to_keep_words : true ,
} ;
2022-01-18 09:48:28 +01:00
/// Definition of a parsed keybinding from the config object
#[ derive(Serialize, Deserialize, Clone, Debug) ]
pub struct ParsedKeybinding {
2022-01-19 14:28:08 +01:00
pub modifier : Value ,
pub keycode : Value ,
pub event : Value ,
pub mode : Value ,
2022-01-18 09:48:28 +01:00
}
2022-04-04 16:54:48 +02:00
/// Definition of a parsed menu from the config object
#[ derive(Serialize, Deserialize, Clone, Debug) ]
pub struct ParsedMenu {
pub name : Value ,
pub marker : Value ,
pub only_buffer_difference : Value ,
pub style : Value ,
pub menu_type : Value ,
pub source : Value ,
}
2022-05-08 21:28:39 +02:00
/// Definition of a parsed menu from the config object
#[ derive(Serialize, Deserialize, Clone, Debug) ]
pub struct Hooks {
pub pre_prompt : Option < Value > ,
pub pre_execution : Option < Value > ,
2022-05-20 23:49:42 +02:00
pub env_change : Option < Value > ,
2022-11-06 01:46:40 +01:00
pub display_output : Option < Value > ,
2022-05-08 21:28:39 +02:00
}
impl Hooks {
pub fn new ( ) -> Self {
Self {
pre_prompt : None ,
pre_execution : None ,
2022-05-20 23:49:42 +02:00
env_change : None ,
2022-11-06 01:46:40 +01:00
display_output : None ,
2022-05-08 21:28:39 +02:00
}
}
}
impl Default for Hooks {
fn default ( ) -> Self {
Self ::new ( )
}
}
2021-11-14 20:25:57 +01:00
#[ derive(Serialize, Deserialize, Clone, Debug) ]
pub struct Config {
2022-08-22 20:38:51 +02:00
pub external_completer : Option < usize > ,
2021-11-14 20:25:57 +01:00
pub filesize_metric : bool ,
pub table_mode : String ,
2021-11-15 21:09:17 +01:00
pub use_ls_colors : bool ,
2022-01-15 18:01:44 +01:00
pub color_config : HashMap < String , Value > ,
2021-11-29 21:37:09 +01:00
pub use_grid_icons : bool ,
2021-12-01 20:20:23 +01:00
pub footer_mode : FooterMode ,
2021-12-07 21:06:14 +01:00
pub float_precision : i64 ,
2022-07-19 19:39:50 +02:00
pub max_external_completion_results : i64 ,
2021-12-09 20:19:36 +01:00
pub filesize_format : String ,
2021-12-09 23:06:26 +01:00
pub use_ansi_coloring : bool ,
2022-02-04 16:30:21 +01:00
pub quick_completions : bool ,
2022-03-03 10:13:44 +01:00
pub partial_completions : bool ,
2022-04-24 23:43:18 +02:00
pub completion_algorithm : String ,
2021-12-23 10:31:16 +01:00
pub edit_mode : String ,
2021-12-23 20:59:00 +01:00
pub max_history_size : i64 ,
2022-03-31 23:25:48 +02:00
pub sync_history_on_enter : bool ,
2022-06-14 22:53:33 +02:00
pub history_file_format : HistoryFileFormat ,
2022-01-01 22:42:50 +01:00
pub log_level : String ,
2022-01-18 09:48:28 +01:00
pub keybindings : Vec < ParsedKeybinding > ,
2022-04-04 16:54:48 +02:00
pub menus : Vec < ParsedMenu > ,
2022-05-08 21:28:39 +02:00
pub hooks : Hooks ,
2022-02-09 15:56:27 +01:00
pub rm_always_trash : bool ,
2022-04-24 02:53:12 +02:00
pub shell_integration : bool ,
2022-04-30 16:40:41 +02:00
pub buffer_editor : String ,
2022-09-29 00:07:33 +02:00
pub table_index_mode : TableIndexMode ,
2022-05-06 14:58:32 +02:00
pub cd_with_abbreviations : bool ,
2022-05-26 16:22:20 +02:00
pub case_sensitive_completions : bool ,
2022-06-14 21:28:11 +02:00
pub enable_external_completion : bool ,
2022-07-12 18:23:50 +02:00
pub trim_strategy : TrimStrategy ,
2022-07-29 19:50:12 +02:00
pub show_banner : bool ,
2022-08-18 12:45:49 +02:00
pub show_clickable_links_in_ls : bool ,
2022-10-23 16:18:26 +02:00
pub render_right_prompt_on_last_line : bool ,
2022-12-02 07:42:18 +01:00
pub explore : HashMap < String , Value > ,
2021-11-14 20:25:57 +01:00
}
impl Default for Config {
fn default ( ) -> Config {
Config {
filesize_metric : false ,
table_mode : " rounded " . into ( ) ,
2022-08-22 20:38:51 +02:00
external_completer : None ,
2021-11-15 21:09:17 +01:00
use_ls_colors : true ,
2021-11-20 14:12:35 +01:00
color_config : HashMap ::new ( ) ,
2021-11-29 21:37:09 +01:00
use_grid_icons : false ,
2022-02-20 21:20:41 +01:00
footer_mode : FooterMode ::RowCount ( 25 ) ,
2021-12-07 21:06:14 +01:00
float_precision : 4 ,
2022-07-19 19:39:50 +02:00
max_external_completion_results : 100 ,
2021-12-09 20:19:36 +01:00
filesize_format : " auto " . into ( ) ,
2021-12-09 23:06:26 +01:00
use_ansi_coloring : true ,
2022-02-20 21:20:41 +01:00
quick_completions : true ,
2022-03-03 10:13:44 +01:00
partial_completions : true ,
2022-04-24 23:43:18 +02:00
completion_algorithm : " prefix " . into ( ) ,
2021-12-23 10:31:16 +01:00
edit_mode : " emacs " . into ( ) ,
2022-05-19 19:42:41 +02:00
max_history_size : i64 ::MAX ,
2022-03-31 23:25:48 +02:00
sync_history_on_enter : true ,
2022-06-14 22:53:33 +02:00
history_file_format : HistoryFileFormat ::PlainText ,
2022-01-01 22:42:50 +01:00
log_level : String ::new ( ) ,
2022-03-27 15:01:04 +02:00
keybindings : Vec ::new ( ) ,
2022-04-04 16:54:48 +02:00
menus : Vec ::new ( ) ,
2022-05-08 21:28:39 +02:00
hooks : Hooks ::new ( ) ,
2022-02-09 15:56:27 +01:00
rm_always_trash : false ,
2022-04-24 02:53:12 +02:00
shell_integration : false ,
2022-04-30 16:40:41 +02:00
buffer_editor : String ::new ( ) ,
2022-09-29 00:07:33 +02:00
table_index_mode : TableIndexMode ::Always ,
2022-05-06 14:58:32 +02:00
cd_with_abbreviations : false ,
2022-05-26 16:22:20 +02:00
case_sensitive_completions : false ,
2022-06-14 21:28:11 +02:00
enable_external_completion : true ,
2022-07-12 18:23:50 +02:00
trim_strategy : TRIM_STRATEGY_DEFAULT ,
2022-07-29 19:50:12 +02:00
show_banner : true ,
2022-08-18 12:45:49 +02:00
show_clickable_links_in_ls : true ,
2022-10-23 16:18:26 +02:00
render_right_prompt_on_last_line : false ,
2022-12-02 07:42:18 +01:00
explore : HashMap ::new ( ) ,
2021-11-14 20:25:57 +01:00
}
}
}
2021-12-01 20:20:23 +01:00
#[ derive(Serialize, Deserialize, Clone, Debug) ]
pub enum FooterMode {
/// Never show the footer
Never ,
/// Always show the footer
Always ,
/// Only show the footer if there are more than RowCount rows
RowCount ( u64 ) ,
/// Calculate the screen height, calculate row count, if display will be bigger than screen, add the footer
Auto ,
}
2022-06-14 22:53:33 +02:00
#[ derive(Serialize, Deserialize, Clone, Debug, Copy) ]
pub enum HistoryFileFormat {
/// Store history as an SQLite database with additional context
Sqlite ,
/// store history as a plain text file where every line is one command (without any context such as timestamps)
PlainText ,
}
2022-09-29 00:07:33 +02:00
#[ derive(Serialize, Deserialize, Clone, Debug) ]
pub enum TableIndexMode {
/// Always show indexes
Always ,
/// Never show indexes
Never ,
/// Show indexes when a table has "index" column
Auto ,
}
2022-07-12 18:23:50 +02:00
/// A Table view configuration, for a situation where
/// we need to limit cell width in order to adjust for a terminal size.
#[ derive(Serialize, Deserialize, Clone, Debug) ]
pub enum TrimStrategy {
/// Wrapping strategy.
///
/// It it's simmilar to original nu_table, strategy.
Wrap {
/// A flag which indicates whether is it necessary to try
/// to keep word bounderies.
try_to_keep_words : bool ,
} ,
/// Truncating strategy, where we just cut the string.
/// And append the suffix if applicable.
Truncate {
/// Suffix which can be appended to a truncated string after being cut.
///
/// It will be applied only when there's enough room for it.
/// For example in case where a cell width must be 12 chars, but
/// the suffix takes 13 chars it won't be used.
suffix : Option < String > ,
} ,
}
[MVP][WIP] `less` like pager (#6984)
Run it as `explore`.
#### example
```nu
ls | explore
```
Configuration points in `config.nu` file.
```
# A 'explore' utility config
explore_config: {
highlight: { bg: 'yellow', fg: 'black' }
status_bar: { bg: '#C4C9C6', fg: '#1D1F21' }
command_bar: { fg: '#C4C9C6' }
split_line: '#404040'
cursor: true
# selected_column: 'blue'
# selected_row: { fg: 'yellow', bg: '#C1C2A3' }
# selected_cell: { fg: 'white', bg: '#777777' }
# line_shift: false,
# line_index: false,
# line_head_top: false,
# line_head_bottom: false,
}
```
You can start without a pipeline and type `explore` and it'll give you a
few tips.
![image](https://user-images.githubusercontent.com/343840/205088971-a8c0262f-f222-4641-b13a-027fbd4f5e1a.png)
If you type `:help` you an see the help screen with some information on
what tui keybindings are available.
![image](https://user-images.githubusercontent.com/343840/205089461-c4c54217-7ec4-4fa0-96c0-643d68dc0062.png)
From the `:help` screen you can now hit `i` and that puts you in
`cursor` aka `inspection` mode and you can move the cursor left right up
down and it you put it on an area such as `[table 5 rows]` and hit the
enter key, you'll see something like this, which shows all the `:`
commands. If you hit `esc` it will take you to the previous screen.
![image](https://user-images.githubusercontent.com/343840/205090155-3558a14b-87b7-4072-8dfb-dc8cc2ef4943.png)
If you then type `:try` you'll get this type of window where you can
type in the top portion and see results in the bottom.
![image](https://user-images.githubusercontent.com/343840/205089185-3c065551-0792-43d6-a13c-a52762856209.png)
The `:nu` command is interesting because you can type pipelines like
`:nu ls | sort-by type size` or another pipeline of your choosing such
as `:nu sys` and that will show the table that looks like this, which
we're calling "table mode".
![image](https://user-images.githubusercontent.com/343840/205090809-e686ff0f-6d0b-4347-8ed0-8c59adfbd741.png)
If you hit the `t` key it will now transpose the view to look like this.
![image](https://user-images.githubusercontent.com/343840/205090948-a834d7f2-1713-4dfe-92fe-5432f287df3d.png)
In table mode or transposed table mode you can use the `i` key to
inspect any collapsed field like `{record 8 fields}`, `[table 16 rows]`,
`[list x]`, etc.
One of the original benefits was that when you're in a view that has a
lot of columns, `explore` gives you the ability to scroll left, right,
up, and down.
`explore` is also smart enough to know when you're in table mode versus
preview mode. If you do `open Cargo.toml | explore` you get this.
![image](https://user-images.githubusercontent.com/343840/205091822-cac79130-3a52-4ca8-9210-eba5be30ed58.png)
If you type `open --raw Cargo.toml | explore` you get this where you can
scroll left, right, up, down. This is called preview mode.
![image](https://user-images.githubusercontent.com/343840/205091990-69455191-ab78-4fea-a961-feafafc16d70.png)
When you're in table mode, you can also type `:preview`. So, with `open
--raw Cargo.toml | explore`, if you type `:preview`, it will look like
this.
![image](https://user-images.githubusercontent.com/343840/205092569-436aa55a-0474-48d5-ab71-baddb1f43027.png)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2022-12-01 16:32:10 +01:00
#[ derive(Serialize, Deserialize, Clone, Debug) ]
pub struct ExploreConfig {
pub color_config : HashMap < String , Value > ,
}
2021-11-14 20:25:57 +01:00
impl Value {
pub fn into_config ( self ) -> Result < Config , ShellError > {
2022-01-19 17:42:12 +01:00
let v = self . as_record ( ) ;
2021-11-14 20:25:57 +01:00
let mut config = Config ::default ( ) ;
2022-11-19 18:52:09 +01:00
let mut legacy_options_used = false ;
2022-01-19 17:42:12 +01:00
if let Ok ( v ) = v {
for ( key , value ) in v . 0. iter ( ) . zip ( v . 1 ) {
2022-11-19 18:52:09 +01:00
let key = key . as_str ( ) ;
match key {
// Grouped options
" ls " = > {
if let Ok ( ( cols , inner_vals ) ) = value . as_record ( ) {
for ( key2 , value ) in cols . iter ( ) . zip ( inner_vals ) {
let key2 = key2 . as_str ( ) ;
match key2 {
" use_ls_colors " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . use_ls_colors = b ;
} else {
eprintln! ( " $env.config. {} . {} is not a bool " , key , key2 )
}
}
" clickable_links " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . show_clickable_links_in_ls = b ;
} else {
eprintln! ( " $env.config. {} . {} is not a bool " , key , key2 )
}
}
x = > {
eprintln! (
" $env.config.{}.{} is an unknown config setting " ,
key , x
)
}
}
}
2022-01-19 17:42:12 +01:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a record " , key ) ;
2022-01-19 17:42:12 +01:00
}
}
2022-11-19 18:52:09 +01:00
" cd " = > {
if let Ok ( ( cols , inner_vals ) ) = value . as_record ( ) {
for ( key2 , value ) in cols . iter ( ) . zip ( inner_vals ) {
let key2 = key2 . as_str ( ) ;
match key2 {
" abbreviations " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . cd_with_abbreviations = b ;
} else {
eprintln! ( " $env.config. {} . {} is not a bool " , key , key2 )
}
}
x = > {
eprintln! (
" $env.config.{}.{} is an unknown config setting " ,
key , x
)
}
}
}
} else {
eprintln! ( " $env.config. {} is not a record " , key ) ;
2022-08-22 20:38:51 +02:00
}
}
2022-11-19 18:52:09 +01:00
" rm " = > {
if let Ok ( ( cols , inner_vals ) ) = value . as_record ( ) {
for ( key2 , value ) in cols . iter ( ) . zip ( inner_vals ) {
let key2 = key2 . as_str ( ) ;
match key2 {
" always_trash " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . rm_always_trash = b ;
} else {
eprintln! ( " $env.config. {} . {} is not a bool " , key , key2 )
}
}
x = > {
eprintln! (
" $env.config.{}.{} is an unknown config setting " ,
key , x
)
}
}
}
2022-01-19 17:42:12 +01:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a record " , key ) ;
2022-01-19 17:42:12 +01:00
}
}
2022-11-19 18:52:09 +01:00
" history " = > {
if let Ok ( ( cols , inner_vals ) ) = value . as_record ( ) {
for ( key2 , value ) in cols . iter ( ) . zip ( inner_vals ) {
let key2 = key2 . as_str ( ) ;
match key2 {
" sync_on_enter " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . sync_history_on_enter = b ;
} else {
eprintln! ( " $env.config. {} . {} is not a bool " , key , key2 )
}
}
" max_size " = > {
if let Ok ( i ) = value . as_i64 ( ) {
config . max_history_size = i ;
} else {
eprintln! (
" $env.config.{}.{} is not an integer " ,
key , key2
)
}
}
" file_format " = > {
if let Ok ( v ) = value . as_string ( ) {
let val_str = v . to_lowercase ( ) ;
config . history_file_format = match val_str . as_ref ( ) {
" sqlite " = > HistoryFileFormat ::Sqlite ,
" plaintext " = > HistoryFileFormat ::PlainText ,
_ = > {
eprintln! (
" unrecognized $config.{}.{} '{val_str}'; expected either 'sqlite' or 'plaintext' " ,
key , key2 ,
) ;
HistoryFileFormat ::PlainText
}
} ;
} else {
eprintln! (
" $env.config.{}.{} is not a string " ,
key , key2
)
}
}
x = > {
eprintln! (
" $env.config.{}.{} is an unknown config setting " ,
key , x
)
}
}
}
2022-01-19 17:42:12 +01:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a record " , key )
2022-01-19 17:42:12 +01:00
}
}
2022-11-19 18:52:09 +01:00
" completions " = > {
if let Ok ( ( cols , inner_vals ) ) = value . as_record ( ) {
for ( key2 , value ) in cols . iter ( ) . zip ( inner_vals ) {
let key2 = key2 . as_str ( ) ;
match key2 {
" quick " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . quick_completions = b ;
} else {
eprintln! ( " $env.config. {} . {} is not a bool " , key , key2 )
}
}
" partial " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . partial_completions = b ;
} else {
eprintln! ( " $env.config. {} . {} is not a bool " , key , key2 )
}
}
" algorithm " = > {
if let Ok ( v ) = value . as_string ( ) {
let val_str = v . to_lowercase ( ) ;
config . completion_algorithm = match val_str . as_ref ( ) {
// This should match the MatchAlgorithm enum in completions::completion_options
" prefix " = > val_str ,
" fuzzy " = > val_str ,
_ = > {
eprintln! (
" unrecognized $config.{}.{} '{val_str}'; expected either 'prefix' or 'fuzzy' " ,
key , key2
) ;
String ::from ( " prefix " )
}
} ;
} else {
eprintln! (
" $env.config.{}.{} is not a string " ,
key , key2
)
}
}
" case_sensitive " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . case_sensitive_completions = b ;
} else {
eprintln! ( " $env.config. {} . {} is not a bool " , key , key2 )
}
}
" external " = > {
if let Ok ( ( cols , inner_vals ) ) = value . as_record ( ) {
for ( key3 , value ) in cols . iter ( ) . zip ( inner_vals ) {
let key3 = key3 . as_str ( ) ;
match key3 {
" max_results " = > {
if let Ok ( i ) = value . as_integer ( ) {
config
. max_external_completion_results =
i ;
} else {
eprintln! ( " $env.config. {} . {} . {} is not an integer " , key , key2 , key3 )
}
}
" completer " = > {
if let Ok ( v ) = value . as_block ( ) {
config . external_completer = Some ( v )
} else {
match value {
Value ::Nothing { .. } = > { }
_ = > {
eprintln! ( " $env.config. {} . {} . {} is not a block or null " , key , key2 , key3 )
}
}
}
}
" enable " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . enable_external_completion = b ;
} else {
eprintln! ( " $env.config. {} . {} . {} is not a bool " , key , key2 , key3 )
}
}
x = > {
eprintln! ( " $env.config. {} . {} . {} is an unknown config setting " , key , key2 , x )
}
}
}
} else {
eprintln! (
" $env.config.{}.{} is not a record " ,
key , key2
) ;
}
}
x = > {
eprintln! (
" $env.config.{}.{} is an unknown config setting " ,
key , x
)
}
}
}
} else {
eprintln! ( " $env.config. {} is not a record " , key )
}
}
" table " = > {
if let Ok ( ( cols , inner_vals ) ) = value . as_record ( ) {
for ( key2 , value ) in cols . iter ( ) . zip ( inner_vals ) {
let key2 = key2 . as_str ( ) ;
match key2 {
" mode " = > {
if let Ok ( v ) = value . as_string ( ) {
config . table_mode = v ;
} else {
eprintln! (
" $env.config.{}.{} is not a string " ,
key , key2
)
}
}
" index_mode " = > {
if let Ok ( b ) = value . as_string ( ) {
let val_str = b . to_lowercase ( ) ;
match val_str . as_ref ( ) {
" always " = > config . table_index_mode = TableIndexMode ::Always ,
" never " = > config . table_index_mode = TableIndexMode ::Never ,
" auto " = > config . table_index_mode = TableIndexMode ::Auto ,
_ = > eprintln! (
" unrecognized $env.config.{}.{} '{val_str}'; expected either 'never', 'always' or 'auto' " ,
key , key2
) ,
}
} else {
eprintln! (
" $env.config.{}.{} is not a string " ,
key , key2
)
}
}
" trim " = > {
config . trim_strategy =
try_parse_trim_strategy ( value , & config ) ?
}
x = > {
eprintln! (
" $env.config.{}.{} is an unknown config setting " ,
key , x
)
}
}
}
} else {
eprintln! ( " $env.config. {} is not a record " , key )
}
}
" filesize " = > {
if let Ok ( ( cols , inner_vals ) ) = value . as_record ( ) {
for ( key2 , value ) in cols . iter ( ) . zip ( inner_vals ) {
let key2 = key2 . as_str ( ) ;
match key2 {
" metric " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . filesize_metric = b ;
} else {
eprintln! ( " $env.config. {} . {} is not a bool " , key , key2 )
}
}
" format " = > {
if let Ok ( v ) = value . as_string ( ) {
config . filesize_format = v . to_lowercase ( ) ;
} else {
eprintln! (
" $env.config.{}.{} is not a string " ,
key , key2
)
}
}
x = > {
eprintln! (
" $env.config.{}.{} is an unknown config setting " ,
key , x
)
}
}
}
} else {
eprintln! ( " $env.config. {} is not a record " , key )
}
}
2022-12-02 07:42:18 +01:00
" explore " = > {
if let Ok ( map ) = create_map ( value , & config ) {
config . explore = map ;
} else {
eprintln! ( " $env.config. {} is not a record " , key )
}
}
2022-11-19 18:52:09 +01:00
// Misc. options
2022-01-19 17:42:12 +01:00
" color_config " = > {
if let Ok ( map ) = create_map ( value , & config ) {
config . color_config = map ;
} else {
2022-07-29 22:42:00 +02:00
eprintln! ( " $env.config.color_config is not a record " )
2022-01-19 17:42:12 +01:00
}
}
" use_grid_icons " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . use_grid_icons = b ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a bool " , key )
2022-01-19 17:42:12 +01:00
}
}
" footer_mode " = > {
if let Ok ( b ) = value . as_string ( ) {
let val_str = b . to_lowercase ( ) ;
config . footer_mode = match val_str . as_ref ( ) {
" auto " = > FooterMode ::Auto ,
" never " = > FooterMode ::Never ,
" always " = > FooterMode ::Always ,
_ = > match & val_str . parse ::< u64 > ( ) {
Ok ( number ) = > FooterMode ::RowCount ( * number ) ,
_ = > FooterMode ::Never ,
} ,
} ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a string " , key )
2022-01-19 17:42:12 +01:00
}
2021-12-17 02:04:54 +01:00
}
2022-01-19 17:42:12 +01:00
" float_precision " = > {
if let Ok ( i ) = value . as_integer ( ) {
config . float_precision = i ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not an integer " , key )
2022-01-19 17:42:12 +01:00
}
}
" use_ansi_coloring " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . use_ansi_coloring = b ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a bool " , key )
2022-01-19 17:42:12 +01:00
}
}
2022-11-19 18:52:09 +01:00
" edit_mode " = > {
if let Ok ( v ) = value . as_string ( ) {
config . edit_mode = v . to_lowercase ( ) ;
2022-02-04 16:30:21 +01:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a string " , key )
2022-02-04 16:30:21 +01:00
}
}
2022-11-19 18:52:09 +01:00
" log_level " = > {
if let Ok ( v ) = value . as_string ( ) {
config . log_level = v . to_lowercase ( ) ;
2022-03-03 10:13:44 +01:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a string " , key )
2022-03-03 10:13:44 +01:00
}
}
2022-11-19 18:52:09 +01:00
" menus " = > match create_menus ( value ) {
Ok ( map ) = > config . menus = map ,
Err ( e ) = > {
eprintln! ( " $env.config. {} is not a valid list of menus " , key ) ;
eprintln! ( " {:?} " , e ) ;
}
} ,
" keybindings " = > match create_keybindings ( value ) {
Ok ( keybindings ) = > config . keybindings = keybindings ,
Err ( e ) = > {
eprintln! ( " $env.config. {} is not a valid keybindings list " , key ) ;
eprintln! ( " {:?} " , e ) ;
}
} ,
" hooks " = > match create_hooks ( value ) {
Ok ( hooks ) = > config . hooks = hooks ,
Err ( e ) = > {
eprintln! ( " $env.config. {} is not a valid hooks list " , key ) ;
eprintln! ( " {:?} " , e ) ;
}
} ,
" shell_integration " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . shell_integration = b ;
2022-07-19 19:39:50 +02:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a bool " , key ) ;
2022-07-19 19:39:50 +02:00
}
}
2022-11-19 18:52:09 +01:00
" buffer_editor " = > {
2022-04-24 23:43:18 +02:00
if let Ok ( v ) = value . as_string ( ) {
2022-11-19 18:52:09 +01:00
config . buffer_editor = v . to_lowercase ( ) ;
2022-04-24 23:43:18 +02:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a string " , key ) ;
2022-04-24 23:43:18 +02:00
}
}
2022-11-19 18:52:09 +01:00
" show_banner " = > {
2022-02-09 15:56:27 +01:00
if let Ok ( b ) = value . as_bool ( ) {
2022-11-19 18:52:09 +01:00
config . show_banner = b ;
2022-02-09 15:56:27 +01:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a bool " , key ) ;
2022-02-09 15:56:27 +01:00
}
}
2022-11-19 18:52:09 +01:00
" render_right_prompt_on_last_line " = > {
if let Ok ( b ) = value . as_bool ( ) {
config . render_right_prompt_on_last_line = b ;
2022-01-19 17:42:12 +01:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is not a bool " , key ) ;
2022-01-19 17:42:12 +01:00
}
}
2022-11-19 18:52:09 +01:00
// Legacy config options (deprecated as of 2022-11-02)
" use_ls_colors " = > {
legacy_options_used = true ;
if let Ok ( b ) = value . as_bool ( ) {
config . use_ls_colors = b ;
2022-01-19 17:42:12 +01:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.use_ls_colors is not a bool " )
}
}
" rm_always_trash " = > {
legacy_options_used = true ;
if let Ok ( b ) = value . as_bool ( ) {
config . rm_always_trash = b ;
} else {
eprintln! ( " $env.config.rm_always_trash is not a bool " )
2022-01-19 17:42:12 +01:00
}
}
2022-06-14 22:53:33 +02:00
" history_file_format " = > {
2022-11-19 18:52:09 +01:00
legacy_options_used = true ;
2022-06-14 22:53:33 +02:00
if let Ok ( b ) = value . as_string ( ) {
let val_str = b . to_lowercase ( ) ;
config . history_file_format = match val_str . as_ref ( ) {
" sqlite " = > HistoryFileFormat ::Sqlite ,
" plaintext " = > HistoryFileFormat ::PlainText ,
_ = > {
eprintln! (
2022-11-19 18:52:09 +01:00
" unrecognized $env.config.history_file_format '{val_str}' "
2022-06-14 22:53:33 +02:00
) ;
HistoryFileFormat ::PlainText
}
} ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.history_file_format is not a string " )
2022-01-19 17:42:12 +01:00
}
}
2022-03-31 23:25:48 +02:00
" sync_history_on_enter " = > {
2022-11-19 18:52:09 +01:00
legacy_options_used = true ;
2022-03-31 23:25:48 +02:00
if let Ok ( b ) = value . as_bool ( ) {
config . sync_history_on_enter = b ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.sync_history_on_enter is not a bool " )
2022-03-31 23:25:48 +02:00
}
}
2022-11-19 18:52:09 +01:00
" max_history_size " = > {
legacy_options_used = true ;
if let Ok ( i ) = value . as_i64 ( ) {
config . max_history_size = i ;
2022-01-19 17:42:12 +01:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.max_history_size is not an integer " )
2022-01-19 17:42:12 +01:00
}
}
2022-11-19 18:52:09 +01:00
" quick_completions " = > {
legacy_options_used = true ;
2022-04-24 02:53:12 +02:00
if let Ok ( b ) = value . as_bool ( ) {
2022-11-19 18:52:09 +01:00
config . quick_completions = b ;
2022-04-24 02:53:12 +02:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.quick_completions is not a bool " )
2022-04-24 02:53:12 +02:00
}
}
2022-11-19 18:52:09 +01:00
" partial_completions " = > {
legacy_options_used = true ;
if let Ok ( b ) = value . as_bool ( ) {
config . partial_completions = b ;
2022-04-30 16:40:41 +02:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.partial_completions is not a bool " )
2022-04-30 16:40:41 +02:00
}
}
2022-11-19 18:52:09 +01:00
" max_external_completion_results " = > {
legacy_options_used = true ;
if let Ok ( i ) = value . as_integer ( ) {
config . max_external_completion_results = i ;
2022-04-30 16:07:46 +02:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! (
" $env.config.max_external_completion_results is not an integer "
)
2022-05-06 14:58:32 +02:00
}
}
2022-11-19 18:52:09 +01:00
" completion_algorithm " = > {
legacy_options_used = true ;
if let Ok ( v ) = value . as_string ( ) {
let val_str = v . to_lowercase ( ) ;
config . completion_algorithm = match val_str . as_ref ( ) {
// This should match the MatchAlgorithm enum in completions::completion_options
" prefix " = > val_str ,
" fuzzy " = > val_str ,
_ = > {
eprintln! (
" unrecognized $env.config.completions.algorithm '{val_str}'; expected either 'prefix' or 'fuzzy' "
) ;
val_str
}
} ;
2022-05-06 14:58:32 +02:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.completion_algorithm is not a string " )
2022-05-26 16:22:20 +02:00
}
}
" case_sensitive_completions " = > {
2022-11-19 18:52:09 +01:00
legacy_options_used = true ;
2022-05-26 16:22:20 +02:00
if let Ok ( b ) = value . as_bool ( ) {
config . case_sensitive_completions = b ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.case_sensitive_completions is not a bool " )
2022-04-30 16:07:46 +02:00
}
}
2022-06-14 21:28:11 +02:00
" enable_external_completion " = > {
2022-11-19 18:52:09 +01:00
legacy_options_used = true ;
2022-06-14 21:28:11 +02:00
if let Ok ( b ) = value . as_bool ( ) {
config . enable_external_completion = b ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.enable_external_completion is not a bool " )
2022-06-14 21:28:11 +02:00
}
}
2022-11-19 18:52:09 +01:00
" external_completer " = > {
legacy_options_used = true ;
if let Ok ( v ) = value . as_block ( ) {
config . external_completer = Some ( v )
}
}
" table_mode " = > {
legacy_options_used = true ;
if let Ok ( v ) = value . as_string ( ) {
config . table_mode = v ;
2022-07-29 19:50:12 +02:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.table_mode is not a string " )
2022-07-29 19:50:12 +02:00
}
}
2022-11-20 06:46:13 +01:00
" table_index_mode " = > {
legacy_options_used = true ;
if let Ok ( b ) = value . as_string ( ) {
let val_str = b . to_lowercase ( ) ;
match val_str . as_ref ( ) {
" always " = > config . table_index_mode = TableIndexMode ::Always ,
" never " = > config . table_index_mode = TableIndexMode ::Never ,
" auto " = > config . table_index_mode = TableIndexMode ::Auto ,
_ = > eprintln! (
" unrecognized $env.config.table_index_mode '{val_str}'; expected either 'never', 'always' or 'auto' "
) ,
}
} else {
eprintln! ( " $env.config.table_index_mode is not a string " )
}
}
2022-11-19 18:52:09 +01:00
" table_trim " = > {
legacy_options_used = true ;
config . trim_strategy = try_parse_trim_strategy ( value , & config ) ?
}
2022-08-18 12:45:49 +02:00
" show_clickable_links_in_ls " = > {
2022-11-19 18:52:09 +01:00
legacy_options_used = true ;
2022-08-18 12:45:49 +02:00
if let Ok ( b ) = value . as_bool ( ) {
config . show_clickable_links_in_ls = b ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.show_clickable_links_in_ls is not a bool " )
2022-08-18 12:45:49 +02:00
}
}
2022-11-19 18:52:09 +01:00
" cd_with_abbreviations " = > {
legacy_options_used = true ;
2022-10-23 16:18:26 +02:00
if let Ok ( b ) = value . as_bool ( ) {
2022-11-19 18:52:09 +01:00
config . cd_with_abbreviations = b ;
2022-10-23 16:18:26 +02:00
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.cd_with_abbreviations is not a bool " )
2022-10-23 16:18:26 +02:00
}
}
2022-11-19 18:52:09 +01:00
" filesize_metric " = > {
legacy_options_used = true ;
if let Ok ( b ) = value . as_bool ( ) {
config . filesize_metric = b ;
} else {
eprintln! ( " $env.config.filesize_metric is not a bool " )
}
}
" filesize_format " = > {
legacy_options_used = true ;
if let Ok ( v ) = value . as_string ( ) {
config . filesize_format = v . to_lowercase ( ) ;
} else {
eprintln! ( " $env.config.filesize_format is not a string " )
}
}
// End legacy options
2022-01-19 17:42:12 +01:00
x = > {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config. {} is an unknown config setting " , x )
2022-01-19 17:42:12 +01:00
}
2022-01-15 18:01:44 +01:00
}
2021-11-14 20:25:57 +01:00
}
2022-01-19 17:42:12 +01:00
} else {
2022-07-29 22:42:00 +02:00
eprintln! ( " $env.config is not a record " ) ;
2021-11-14 20:25:57 +01:00
}
2022-11-19 18:52:09 +01:00
if legacy_options_used {
eprintln! (
r #" The format of $env.config has recently changed, and several options have been grouped into sub-records. You may need to update your config.nu file.
Please consult https ://www.nushell.sh/blog/2022-11-29-nushell-0.72.html for details. Support for the old format will be removed in an upcoming Nu release."#
) ;
}
2021-11-14 20:25:57 +01:00
Ok ( config )
}
}
2022-01-15 18:01:44 +01:00
2022-07-12 18:23:50 +02:00
fn try_parse_trim_strategy ( value : & Value , config : & Config ) -> Result < TrimStrategy , ShellError > {
let map = create_map ( value , config ) . map_err ( | e | {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.table.trim is not a record " ) ;
2022-07-12 18:23:50 +02:00
e
} ) ? ;
let mut methodology = match map . get ( " methodology " ) {
Some ( value ) = > match try_parse_trim_methodology ( value ) {
Some ( methodology ) = > methodology ,
None = > return Ok ( TRIM_STRATEGY_DEFAULT ) ,
} ,
None = > {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.table.trim.methodology was not provided " ) ;
2022-07-12 18:23:50 +02:00
return Ok ( TRIM_STRATEGY_DEFAULT ) ;
}
} ;
match & mut methodology {
TrimStrategy ::Wrap { try_to_keep_words } = > {
if let Some ( value ) = map . get ( " wrapping_try_keep_words " ) {
if let Ok ( b ) = value . as_bool ( ) {
* try_to_keep_words = b ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.table.trim.wrapping_try_keep_words is not a bool " ) ;
2022-07-12 18:23:50 +02:00
}
}
}
TrimStrategy ::Truncate { suffix } = > {
if let Some ( value ) = map . get ( " truncating_suffix " ) {
if let Ok ( v ) = value . as_string ( ) {
* suffix = Some ( v ) ;
} else {
2022-11-19 18:52:09 +01:00
eprintln! ( " $env.config.table.trim.truncating_suffix is not a string " )
2022-07-12 18:23:50 +02:00
}
}
}
}
Ok ( methodology )
}
fn try_parse_trim_methodology ( value : & Value ) -> Option < TrimStrategy > {
match value . as_string ( ) {
Ok ( value ) = > match value . to_lowercase ( ) . as_str ( ) {
" wrapping " = > {
return Some ( TrimStrategy ::Wrap {
try_to_keep_words : false ,
} ) ;
}
" truncating " = > return Some ( TrimStrategy ::Truncate { suffix : None } ) ,
2022-11-19 18:52:09 +01:00
_ = > eprintln! ( " unrecognized $config.table.trim.methodology value; expected either 'truncating' or 'wrapping' " ) ,
2022-07-12 18:23:50 +02:00
} ,
2022-11-19 18:52:09 +01:00
Err ( _ ) = > eprintln! ( " $env.config.table.trim.methodology is not a string " ) ,
2022-07-12 18:23:50 +02:00
}
None
}
2022-01-15 18:01:44 +01:00
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 ,
} = > {
2022-01-18 09:48:28 +01:00
let val = color_value_string ( span , inner_cols , inner_vals , config ) ;
hm . insert ( k . to_string ( ) , val ) ;
2022-01-15 18:01:44 +01:00
}
_ = > {
hm . insert ( k . to_string ( ) , v . clone ( ) ) ;
}
}
}
Ok ( hm )
}
2022-01-18 09:48:28 +01:00
2022-04-04 23:36:48 +02:00
pub fn color_value_string (
2022-01-18 09:48:28 +01:00
span : & Span ,
inner_cols : & [ String ] ,
inner_vals : & [ Value ] ,
config : & Config ,
) -> Value {
// 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 val : String = inner_cols
. iter ( )
. zip ( inner_vals )
2022-01-19 14:28:08 +01:00
. map ( | ( x , y ) | format! ( " {} : \" {} \" " , x , y . into_string ( " , " , config ) ) )
2022-01-18 09:48:28 +01:00
. collect ( ) ;
// now insert the braces at the front and the back to fake the json string
Value ::String {
val : format ! ( " {{{}}} " , val ) ,
span : * span ,
}
}
2022-05-08 21:28:39 +02:00
// Parse the hooks to find the blocks to run when the hooks fire
fn create_hooks ( value : & Value ) -> Result < Hooks , ShellError > {
match value {
Value ::Record { cols , vals , span } = > {
let mut hooks = Hooks ::new ( ) ;
for idx in 0 .. cols . len ( ) {
match cols [ idx ] . as_str ( ) {
" pre_prompt " = > hooks . pre_prompt = Some ( vals [ idx ] . clone ( ) ) ,
" pre_execution " = > hooks . pre_execution = Some ( vals [ idx ] . clone ( ) ) ,
2022-05-20 23:49:42 +02:00
" env_change " = > hooks . env_change = Some ( vals [ idx ] . clone ( ) ) ,
2022-11-06 01:46:40 +01:00
" display_output " = > hooks . display_output = Some ( vals [ idx ] . clone ( ) ) ,
2022-05-08 21:28:39 +02:00
x = > {
return Err ( ShellError ::UnsupportedConfigValue (
2022-11-06 01:46:40 +01:00
" 'pre_prompt', 'pre_execution', 'env_change' " . to_string ( ) ,
2022-05-08 21:28:39 +02:00
x . to_string ( ) ,
* span ,
) ) ;
}
}
}
Ok ( hooks )
}
v = > match v . span ( ) {
Ok ( span ) = > Err ( ShellError ::UnsupportedConfigValue (
" record for 'hooks' config " . into ( ) ,
" non-record value " . into ( ) ,
span ,
) ) ,
_ = > Err ( ShellError ::UnsupportedConfigValue (
" record for 'hooks' config " . into ( ) ,
" non-record value " . into ( ) ,
2022-12-03 10:44:12 +01:00
Span ::unknown ( ) ,
2022-05-08 21:28:39 +02:00
) ) ,
} ,
}
}
2022-01-18 09:48:28 +01:00
// Parses the config object to extract the strings that will compose a keybinding for reedline
2022-11-04 21:11:17 +01:00
fn create_keybindings ( value : & Value ) -> Result < Vec < ParsedKeybinding > , ShellError > {
2022-01-18 09:48:28 +01:00
match value {
2022-01-19 14:28:08 +01:00
Value ::Record { cols , vals , span } = > {
// Finding the modifier value in the record
2022-04-04 16:54:48 +02:00
let modifier = extract_value ( " modifier " , cols , vals , span ) ? . clone ( ) ;
let keycode = extract_value ( " keycode " , cols , vals , span ) ? . clone ( ) ;
let mode = extract_value ( " mode " , cols , vals , span ) ? . clone ( ) ;
let event = extract_value ( " event " , cols , vals , span ) ? . clone ( ) ;
2022-01-19 14:28:08 +01:00
let keybinding = ParsedKeybinding {
2022-04-04 16:54:48 +02:00
modifier ,
keycode ,
mode ,
event ,
2022-01-19 14:28:08 +01:00
} ;
2022-01-18 09:48:28 +01:00
2022-04-04 16:54:48 +02:00
// We return a menu to be able to do recursion on the same function
2022-01-18 09:48:28 +01:00
Ok ( vec! [ keybinding ] )
}
Value ::List { vals , .. } = > {
let res = vals
. iter ( )
2022-11-04 21:11:17 +01:00
. map ( create_keybindings )
2022-01-18 09:48:28 +01:00
. collect ::< Result < Vec < Vec < ParsedKeybinding > > , ShellError > > ( ) ;
let res = res ?
. into_iter ( )
. flatten ( )
. collect ::< Vec < ParsedKeybinding > > ( ) ;
Ok ( res )
}
_ = > Ok ( Vec ::new ( ) ) ,
}
}
2022-01-19 14:28:08 +01:00
2022-04-04 16:54:48 +02:00
// Parses the config object to extract the strings that will compose a keybinding for reedline
2022-11-04 21:11:17 +01:00
pub fn create_menus ( value : & Value ) -> Result < Vec < ParsedMenu > , ShellError > {
2022-04-04 16:54:48 +02:00
match value {
Value ::Record { cols , vals , span } = > {
// Finding the modifier value in the record
let name = extract_value ( " name " , cols , vals , span ) ? . clone ( ) ;
let marker = extract_value ( " marker " , cols , vals , span ) ? . clone ( ) ;
let only_buffer_difference =
extract_value ( " only_buffer_difference " , cols , vals , span ) ? . clone ( ) ;
let style = extract_value ( " style " , cols , vals , span ) ? . clone ( ) ;
let menu_type = extract_value ( " type " , cols , vals , span ) ? . clone ( ) ;
// Source is an optional value
let source = match extract_value ( " source " , cols , vals , span ) {
Ok ( source ) = > source . clone ( ) ,
Err ( _ ) = > Value ::Nothing { span : * span } ,
} ;
let menu = ParsedMenu {
name ,
only_buffer_difference ,
marker ,
style ,
menu_type ,
source ,
} ;
Ok ( vec! [ menu ] )
}
Value ::List { vals , .. } = > {
let res = vals
. iter ( )
2022-11-04 21:11:17 +01:00
. map ( create_menus )
2022-04-04 16:54:48 +02:00
. collect ::< Result < Vec < Vec < ParsedMenu > > , ShellError > > ( ) ;
let res = res ? . into_iter ( ) . flatten ( ) . collect ::< Vec < ParsedMenu > > ( ) ;
Ok ( res )
}
_ = > Ok ( Vec ::new ( ) ) ,
}
}
2022-01-19 14:28:08 +01:00
pub fn extract_value < ' record > (
name : & str ,
cols : & ' record [ String ] ,
vals : & ' record [ Value ] ,
span : & Span ,
) -> Result < & ' record Value , ShellError > {
cols . iter ( )
. position ( | col | col . as_str ( ) = = name )
. and_then ( | index | vals . get ( index ) )
. ok_or_else ( | | ShellError ::MissingConfigValue ( name . to_string ( ) , * span ) )
}