mirror of
https://github.com/nushell/nushell.git
synced 2025-04-09 21:28:55 +02:00
nu-explore: Refactorings (#10247)
1. Added mode to the status bar right most corner 2. Added a command name with a status when run ref #8582 cc: @fdncred
This commit is contained in:
parent
7486850357
commit
99caad7d60
@ -182,6 +182,10 @@ fn style_from_config(config: &HashMap<String, Value>) -> StyleConfig {
|
|||||||
style.status_info = *s;
|
style.status_info = *s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(s) = colors.get("success") {
|
||||||
|
style.status_success = *s;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(s) = colors.get("warn") {
|
if let Some(s) = colors.get("warn") {
|
||||||
style.status_warn = *s;
|
style.status_warn = *s;
|
||||||
}
|
}
|
||||||
@ -208,6 +212,8 @@ fn prepare_default_config(config: &mut HashMap<String, Value>) {
|
|||||||
|
|
||||||
const STATUS_INFO: Style = color(None, None);
|
const STATUS_INFO: Style = color(None, None);
|
||||||
|
|
||||||
|
const STATUS_SUCCESS: Style = color(Some(Color::Black), Some(Color::Green));
|
||||||
|
|
||||||
const STATUS_WARN: Style = color(None, None);
|
const STATUS_WARN: Style = color(None, None);
|
||||||
|
|
||||||
const TABLE_SPLIT_LINE: Style = color(Some(Color::Rgb(64, 64, 64)), None);
|
const TABLE_SPLIT_LINE: Style = color(Some(Color::Rgb(64, 64, 64)), None);
|
||||||
@ -245,6 +251,7 @@ fn prepare_default_config(config: &mut HashMap<String, Value>) {
|
|||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
insert_style(&mut hm, "info", STATUS_INFO);
|
insert_style(&mut hm, "info", STATUS_INFO);
|
||||||
|
insert_style(&mut hm, "success", STATUS_SUCCESS);
|
||||||
insert_style(&mut hm, "warn", STATUS_WARN);
|
insert_style(&mut hm, "warn", STATUS_WARN);
|
||||||
insert_style(&mut hm, "error", STATUS_ERROR);
|
insert_style(&mut hm, "error", STATUS_ERROR);
|
||||||
|
|
||||||
|
@ -134,6 +134,7 @@ fn create_config_command(commands: &[Command]) -> ConfigCmd {
|
|||||||
let mut config = ConfigCmd::from_commands(commands.to_vec());
|
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 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 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 error color", "status.error", default_color_list()));
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ pub type CtrlC = Option<Arc<AtomicBool>>;
|
|||||||
|
|
||||||
pub use command::{is_ignored_command, run_command_with_value, run_nu_command};
|
pub use command::{is_ignored_command, run_command_with_value, run_nu_command};
|
||||||
pub use lscolor::{create_lscolors, lscolorize};
|
pub use lscolor::{create_lscolors, lscolorize};
|
||||||
pub use string::truncate_str;
|
pub use string::{string_width, truncate_str};
|
||||||
pub use table::try_build_table;
|
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, nu_str};
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use nu_table::{string_truncate, string_width};
|
use nu_table::string_truncate;
|
||||||
|
|
||||||
|
pub use nu_table::string_width;
|
||||||
|
|
||||||
pub fn truncate_str(text: &mut String, width: usize) {
|
pub fn truncate_str(text: &mut String, width: usize) {
|
||||||
if width == 0 {
|
if width == 0 {
|
||||||
|
@ -6,6 +6,7 @@ mod status_bar;
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::min,
|
cmp::min,
|
||||||
io::{self, Result, Stdout},
|
io::{self, Result, Stdout},
|
||||||
|
result,
|
||||||
sync::atomic::Ordering,
|
sync::atomic::Ordering,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,6 +81,7 @@ struct CommandBuf {
|
|||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct StyleConfig {
|
pub struct StyleConfig {
|
||||||
pub status_info: NuStyle,
|
pub status_info: NuStyle,
|
||||||
|
pub status_success: NuStyle,
|
||||||
pub status_warn: NuStyle,
|
pub status_warn: NuStyle,
|
||||||
pub status_error: NuStyle,
|
pub status_error: NuStyle,
|
||||||
pub status_bar_background: NuStyle,
|
pub status_bar_background: NuStyle,
|
||||||
@ -125,6 +127,7 @@ impl<'a> Pager<'a> {
|
|||||||
}
|
}
|
||||||
["highlight"] => value_as_style(&mut self.config.style.highlight, &value),
|
["highlight"] => value_as_style(&mut self.config.style.highlight, &value),
|
||||||
["status", "info"] => value_as_style(&mut self.config.style.status_info, &value),
|
["status", "info"] => value_as_style(&mut self.config.style.status_info, &value),
|
||||||
|
["status", "success"] => value_as_style(&mut self.config.style.status_success, &value),
|
||||||
["status", "warn"] => value_as_style(&mut self.config.style.status_warn, &value),
|
["status", "warn"] => value_as_style(&mut self.config.style.status_warn, &value),
|
||||||
["status", "error"] => value_as_style(&mut self.config.style.status_error, &value),
|
["status", "error"] => value_as_style(&mut self.config.style.status_error, &value),
|
||||||
path => set_config(&mut self.config.config, path, value),
|
path => set_config(&mut self.config.config, path, value),
|
||||||
@ -245,13 +248,12 @@ fn render_ui(
|
|||||||
ctrlc: CtrlC,
|
ctrlc: CtrlC,
|
||||||
pager: &mut Pager<'_>,
|
pager: &mut Pager<'_>,
|
||||||
info: &mut ViewInfo,
|
info: &mut ViewInfo,
|
||||||
mut view: Option<Page>,
|
view: Option<Page>,
|
||||||
commands: CommandRegistry,
|
commands: CommandRegistry,
|
||||||
) -> Result<Option<Value>> {
|
) -> Result<Option<Value>> {
|
||||||
let events = UIEvents::new();
|
let events = UIEvents::new();
|
||||||
let mut view_stack = Vec::new();
|
let mut view_stack = ViewStack::new(view, Vec::new());
|
||||||
|
|
||||||
// let mut command_view = None;
|
|
||||||
loop {
|
loop {
|
||||||
// handle CTRLC event
|
// handle CTRLC event
|
||||||
if let Some(ctrlc) = ctrlc.clone() {
|
if let Some(ctrlc) = ctrlc.clone() {
|
||||||
@ -264,39 +266,11 @@ fn render_ui(
|
|||||||
{
|
{
|
||||||
let info = info.clone();
|
let info = info.clone();
|
||||||
term.draw(|f| {
|
term.draw(|f| {
|
||||||
let area = f.size();
|
draw_frame(f, &mut view_stack.view, pager, &mut layout, info);
|
||||||
let available_area =
|
|
||||||
Rect::new(area.x, area.y, area.width, area.height.saturating_sub(2));
|
|
||||||
|
|
||||||
if let Some(page) = &mut view {
|
|
||||||
let cfg = ViewConfig::new(
|
|
||||||
pager.config.nu_config,
|
|
||||||
pager.config.style_computer,
|
|
||||||
&pager.config.config,
|
|
||||||
pager.config.lscolors,
|
|
||||||
);
|
|
||||||
|
|
||||||
page.view.draw(f, available_area, cfg, &mut layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(report) = info.status {
|
|
||||||
let last_2nd_line = area.bottom().saturating_sub(2);
|
|
||||||
let area = Rect::new(area.left(), last_2nd_line, area.width, 1);
|
|
||||||
render_status_bar(f, area, report, &pager.config.style);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let last_line = area.bottom().saturating_sub(1);
|
|
||||||
let area = Rect::new(area.left(), last_line, area.width, 1);
|
|
||||||
render_cmd_bar(f, area, pager, info.report, &pager.config.style);
|
|
||||||
}
|
|
||||||
|
|
||||||
highlight_search_results(f, pager, &layout, pager.config.style.highlight);
|
|
||||||
set_cursor_cmd_bar(f, area, pager);
|
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = handle_events(
|
let transition = handle_events(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
&events,
|
&events,
|
||||||
@ -304,42 +278,36 @@ fn render_ui(
|
|||||||
info,
|
info,
|
||||||
&mut pager.search_buf,
|
&mut pager.search_buf,
|
||||||
&mut pager.cmd_buf,
|
&mut pager.cmd_buf,
|
||||||
view.as_mut().map(|p| &mut p.view),
|
view_stack.view.as_mut().map(|p| &mut p.view),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(status) = status {
|
if let Some(transition) = transition {
|
||||||
match status {
|
let (exit, cmd_name) = react_to_event_result(
|
||||||
Transition::Exit => {
|
transition,
|
||||||
break Ok(try_to_peek_value(pager, view.as_mut().map(|p| &mut p.view)));
|
engine_state,
|
||||||
}
|
&commands,
|
||||||
Transition::Ok => {
|
pager,
|
||||||
if view_stack.is_empty() && pager.config.exit_esc {
|
&mut view_stack,
|
||||||
break Ok(try_to_peek_value(pager, view.as_mut().map(|p| &mut p.view)));
|
stack,
|
||||||
}
|
info,
|
||||||
|
);
|
||||||
|
|
||||||
// try to pop the view stack
|
if let Some(value) = exit {
|
||||||
if let Some(v) = view_stack.pop() {
|
break Ok(value);
|
||||||
view = Some(v);
|
}
|
||||||
}
|
|
||||||
}
|
if !cmd_name.is_empty() {
|
||||||
Transition::Cmd(command) => {
|
if let Some(r) = info.report.as_mut() {
|
||||||
let out = pager_run_command(
|
r.message = cmd_name;
|
||||||
engine_state,
|
r.level = Severity::Success;
|
||||||
stack,
|
} else {
|
||||||
pager,
|
info.report = Some(Report::success(cmd_name));
|
||||||
&mut view,
|
|
||||||
&mut view_stack,
|
|
||||||
&commands,
|
|
||||||
command,
|
|
||||||
);
|
|
||||||
match out {
|
|
||||||
Ok(false) => {}
|
|
||||||
Ok(true) => {
|
|
||||||
break Ok(try_to_peek_value(pager, view.as_mut().map(|p| &mut p.view)))
|
|
||||||
}
|
|
||||||
Err(err) => info.report = Some(Report::error(err)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let info = info.clone();
|
||||||
|
term.draw(|f| {
|
||||||
|
draw_info(f, pager, info);
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,50 +316,144 @@ fn render_ui(
|
|||||||
pager.cmd_buf.run_cmd = false;
|
pager.cmd_buf.run_cmd = false;
|
||||||
pager.cmd_buf.buf_cmd2 = String::new();
|
pager.cmd_buf.buf_cmd2 = String::new();
|
||||||
|
|
||||||
let out = pager_run_command(
|
let out =
|
||||||
engine_state,
|
pager_run_command(engine_state, stack, pager, &mut view_stack, &commands, args);
|
||||||
stack,
|
|
||||||
pager,
|
|
||||||
&mut view,
|
|
||||||
&mut view_stack,
|
|
||||||
&commands,
|
|
||||||
args,
|
|
||||||
);
|
|
||||||
match out {
|
match out {
|
||||||
Ok(false) => {}
|
Ok(result) => {
|
||||||
Ok(true) => break Ok(try_to_peek_value(pager, view.as_mut().map(|p| &mut p.view))),
|
if result.exit {
|
||||||
|
break Ok(peak_value_from_view(&mut view_stack.view, pager));
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.view_change && !result.cmd_name.is_empty() {
|
||||||
|
if let Some(r) = info.report.as_mut() {
|
||||||
|
r.message = result.cmd_name;
|
||||||
|
r.level = Severity::Success;
|
||||||
|
} else {
|
||||||
|
info.report = Some(Report::success(result.cmd_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
let info = info.clone();
|
||||||
|
term.draw(|f| {
|
||||||
|
draw_info(f, pager, info);
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(err) => info.report = Some(Report::error(err)),
|
Err(err) => info.report = Some(Report::error(err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
fn react_to_event_result(
|
||||||
|
status: Transition,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
commands: &CommandRegistry,
|
||||||
|
pager: &mut Pager<'_>,
|
||||||
|
view_stack: &mut ViewStack,
|
||||||
|
stack: &mut Stack,
|
||||||
|
info: &mut ViewInfo,
|
||||||
|
) -> (Option<Option<Value>>, String) {
|
||||||
|
match status {
|
||||||
|
Transition::Exit => (
|
||||||
|
Some(peak_value_from_view(&mut view_stack.view, pager)),
|
||||||
|
String::default(),
|
||||||
|
),
|
||||||
|
Transition::Ok => {
|
||||||
|
let exit = view_stack.stack.is_empty() && pager.config.exit_esc;
|
||||||
|
if exit {
|
||||||
|
return (
|
||||||
|
Some(peak_value_from_view(&mut view_stack.view, pager)),
|
||||||
|
String::default(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to pop the view stack
|
||||||
|
if let Some(v) = view_stack.stack.pop() {
|
||||||
|
view_stack.view = Some(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
(None, String::default())
|
||||||
|
}
|
||||||
|
Transition::Cmd(cmd) => {
|
||||||
|
let out = pager_run_command(engine_state, stack, pager, view_stack, commands, cmd);
|
||||||
|
match out {
|
||||||
|
Ok(result) if result.exit => (
|
||||||
|
Some(peak_value_from_view(&mut view_stack.view, pager)),
|
||||||
|
String::default(),
|
||||||
|
),
|
||||||
|
Ok(result) => (None, result.cmd_name),
|
||||||
|
Err(err) => {
|
||||||
|
info.report = Some(Report::error(err));
|
||||||
|
(None, String::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peak_value_from_view(view: &mut Option<Page>, pager: &mut Pager<'_>) -> Option<Value> {
|
||||||
|
let view = view.as_mut().map(|p| &mut p.view);
|
||||||
|
try_to_peek_value(pager, view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_frame(
|
||||||
|
f: &mut Frame,
|
||||||
|
view: &mut Option<Page>,
|
||||||
|
pager: &mut Pager<'_>,
|
||||||
|
layout: &mut Layout,
|
||||||
|
info: ViewInfo,
|
||||||
|
) {
|
||||||
|
let area = f.size();
|
||||||
|
let available_area = Rect::new(area.x, area.y, area.width, area.height.saturating_sub(2));
|
||||||
|
|
||||||
|
if let Some(page) = view {
|
||||||
|
let cfg = create_view_config(pager);
|
||||||
|
page.view.draw(f, available_area, cfg, layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_info(f, pager, info);
|
||||||
|
|
||||||
|
highlight_search_results(f, pager, layout, pager.config.style.highlight);
|
||||||
|
set_cursor_cmd_bar(f, area, pager);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_info(f: &mut Frame, pager: &mut Pager<'_>, info: ViewInfo) {
|
||||||
|
let area = f.size();
|
||||||
|
|
||||||
|
if let Some(report) = info.status {
|
||||||
|
let last_2nd_line = area.bottom().saturating_sub(2);
|
||||||
|
let area = Rect::new(area.left(), last_2nd_line, area.width, 1);
|
||||||
|
render_status_bar(f, area, report, &pager.config.style);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let last_line = area.bottom().saturating_sub(1);
|
||||||
|
let area = Rect::new(area.left(), last_line, area.width, 1);
|
||||||
|
render_cmd_bar(f, area, pager, info.report, &pager.config.style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_view_config<'a>(pager: &'a Pager<'_>) -> ViewConfig<'a> {
|
||||||
|
let cfg = &pager.config;
|
||||||
|
ViewConfig::new(cfg.nu_config, cfg.style_computer, &cfg.config, cfg.lscolors)
|
||||||
|
}
|
||||||
|
|
||||||
fn pager_run_command(
|
fn pager_run_command(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
pager: &mut Pager,
|
pager: &mut Pager,
|
||||||
view: &mut Option<Page>,
|
view_stack: &mut ViewStack,
|
||||||
view_stack: &mut Vec<Page>,
|
|
||||||
commands: &CommandRegistry,
|
commands: &CommandRegistry,
|
||||||
args: String,
|
args: String,
|
||||||
) -> std::result::Result<bool, String> {
|
) -> result::Result<CmdResult, String> {
|
||||||
let command = commands.find(&args);
|
let command = commands.find(&args);
|
||||||
handle_command(engine_state, stack, pager, view, view_stack, command, &args)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_command(
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
pager: &mut Pager,
|
|
||||||
view: &mut Option<Page>,
|
|
||||||
view_stack: &mut Vec<Page>,
|
|
||||||
command: Option<Result<Command>>,
|
|
||||||
args: &str,
|
|
||||||
) -> std::result::Result<bool, String> {
|
|
||||||
match command {
|
match command {
|
||||||
Some(Ok(command)) => {
|
Some(Ok(command)) => {
|
||||||
run_command(engine_state, stack, pager, view, view_stack, command, args)
|
let result = run_command(engine_state, stack, pager, view_stack, command);
|
||||||
|
match result {
|
||||||
|
Ok(value) => Ok(value),
|
||||||
|
Err(err) => Err(format!("Error: command {args:?} failed: {err}")),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(Err(err)) => Err(format!(
|
Some(Err(err)) => Err(format!(
|
||||||
"Error: command {args:?} was not provided with correct arguments: {err}"
|
"Error: command {args:?} was not provided with correct arguments: {err}"
|
||||||
@ -404,80 +466,62 @@ fn run_command(
|
|||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
pager: &mut Pager,
|
pager: &mut Pager,
|
||||||
view: &mut Option<Page>,
|
view_stack: &mut ViewStack,
|
||||||
view_stack: &mut Vec<Page>,
|
|
||||||
command: Command,
|
command: Command,
|
||||||
args: &str,
|
) -> Result<CmdResult> {
|
||||||
) -> std::result::Result<bool, String> {
|
|
||||||
match command {
|
match command {
|
||||||
Command::Reactive(mut command) => {
|
Command::Reactive(mut command) => {
|
||||||
// what we do we just replace the view.
|
// what we do we just replace the view.
|
||||||
let value = view.as_mut().and_then(|p| p.view.exit());
|
let value = view_stack.view.as_mut().and_then(|p| p.view.exit());
|
||||||
let result = command.react(engine_state, stack, pager, value);
|
let transition = command.react(engine_state, stack, pager, value)?;
|
||||||
match result {
|
match transition {
|
||||||
Ok(transition) => match transition {
|
Transition::Ok => {
|
||||||
Transition::Ok => {
|
// so we basically allow a change of a config inside a command,
|
||||||
// so we basically allow a change of a config inside a command,
|
// and cause of this we wanna update all of our views.
|
||||||
// and cause of this we wanna update all of our views.
|
//
|
||||||
//
|
// THOUGH: MOST LIKELY IT WON'T BE CHANGED AND WE DO A WASTE.......
|
||||||
// THOUGH: MOST LIKELY IT WON'T BE CHANGED AND WE DO A WASTE.......
|
|
||||||
|
|
||||||
{
|
update_view_stack_setup(view_stack, &pager.config);
|
||||||
if let Some(page) = view.as_mut() {
|
|
||||||
page.view.setup(ViewConfig::new(
|
|
||||||
pager.config.nu_config,
|
|
||||||
pager.config.style_computer,
|
|
||||||
&pager.config.config,
|
|
||||||
pager.config.lscolors,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
for page in view_stack {
|
Ok(CmdResult::new(false, false, String::new()))
|
||||||
page.view.setup(ViewConfig::new(
|
}
|
||||||
pager.config.nu_config,
|
Transition::Exit => Ok(CmdResult::new(true, false, String::new())),
|
||||||
pager.config.style_computer,
|
Transition::Cmd { .. } => todo!("not used so far"),
|
||||||
&pager.config.config,
|
|
||||||
pager.config.lscolors,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
Transition::Exit => Ok(true),
|
|
||||||
Transition::Cmd { .. } => todo!("not used so far"),
|
|
||||||
},
|
|
||||||
Err(err) => Err(format!("Error: command {args:?} failed: {err}")),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::View { mut cmd, is_light } => {
|
Command::View { mut cmd, is_light } => {
|
||||||
// what we do we just replace the view.
|
// what we do we just replace the view.
|
||||||
let value = view.as_mut().and_then(|p| p.view.exit());
|
let value = view_stack.view.as_mut().and_then(|p| p.view.exit());
|
||||||
let result = cmd.spawn(engine_state, stack, value);
|
let mut new_view = cmd.spawn(engine_state, stack, value)?;
|
||||||
match result {
|
if let Some(view) = view_stack.view.take() {
|
||||||
Ok(mut new_view) => {
|
if !view.is_light {
|
||||||
if let Some(view) = view.take() {
|
view_stack.stack.push(view);
|
||||||
if !view.is_light {
|
|
||||||
view_stack.push(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new_view.setup(ViewConfig::new(
|
|
||||||
pager.config.nu_config,
|
|
||||||
pager.config.style_computer,
|
|
||||||
&pager.config.config,
|
|
||||||
pager.config.lscolors,
|
|
||||||
));
|
|
||||||
|
|
||||||
*view = Some(Page::raw(new_view, is_light));
|
|
||||||
Ok(false)
|
|
||||||
}
|
}
|
||||||
Err(err) => Err(format!("Error: command {args:?} failed: {err}")),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_view_setup(&mut new_view, &pager.config);
|
||||||
|
view_stack.view = Some(Page::raw(new_view, is_light));
|
||||||
|
|
||||||
|
Ok(CmdResult::new(false, true, cmd.name().to_owned()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_view_stack_setup(view_stack: &mut ViewStack, cfg: &PagerConfig<'_>) {
|
||||||
|
if let Some(page) = view_stack.view.as_mut() {
|
||||||
|
update_view_setup(&mut page.view, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
for page in &mut view_stack.stack {
|
||||||
|
update_view_setup(&mut page.view, cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_view_setup(view: &mut Box<dyn View>, cfg: &PagerConfig<'_>) {
|
||||||
|
let cfg = ViewConfig::new(cfg.nu_config, cfg.style_computer, &cfg.config, cfg.lscolors);
|
||||||
|
view.setup(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
fn set_cursor_cmd_bar(f: &mut Frame, area: Rect, pager: &Pager) {
|
fn set_cursor_cmd_bar(f: &mut Frame, area: Rect, pager: &Pager) {
|
||||||
if pager.cmd_buf.is_cmd_input {
|
if pager.cmd_buf.is_cmd_input {
|
||||||
// todo: deal with a situation where we exceed the bar width
|
// todo: deal with a situation where we exceed the bar width
|
||||||
@ -509,15 +553,25 @@ where
|
|||||||
|
|
||||||
fn render_status_bar(f: &mut Frame, area: Rect, report: Report, theme: &StyleConfig) {
|
fn render_status_bar(f: &mut Frame, area: Rect, report: Report, theme: &StyleConfig) {
|
||||||
let msg_style = report_msg_style(&report, theme, theme.status_bar_text);
|
let msg_style = report_msg_style(&report, theme, theme.status_bar_text);
|
||||||
let mut status_bar = StatusBar::new(report.message, report.context, report.context2);
|
let mut status_bar = create_status_bar(report);
|
||||||
status_bar.set_background_style(theme.status_bar_background);
|
status_bar.set_background_style(theme.status_bar_background);
|
||||||
status_bar.set_message_style(msg_style);
|
status_bar.set_message_style(msg_style);
|
||||||
status_bar.set_ctx_style(theme.status_bar_text);
|
status_bar.set_ctx1_style(theme.status_bar_text);
|
||||||
status_bar.set_ctx2_style(theme.status_bar_text);
|
status_bar.set_ctx2_style(theme.status_bar_text);
|
||||||
|
status_bar.set_ctx3_style(theme.status_bar_text);
|
||||||
|
|
||||||
f.render_widget(status_bar, area);
|
f.render_widget(status_bar, area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_status_bar(report: Report) -> StatusBar {
|
||||||
|
StatusBar::new(
|
||||||
|
report.message,
|
||||||
|
report.context1,
|
||||||
|
report.context2,
|
||||||
|
report.context3,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn report_msg_style(report: &Report, theme: &StyleConfig, style: NuStyle) -> NuStyle {
|
fn report_msg_style(report: &Report, theme: &StyleConfig, style: NuStyle) -> NuStyle {
|
||||||
if matches!(report.level, Severity::Info) {
|
if matches!(report.level, Severity::Info) {
|
||||||
style
|
style
|
||||||
@ -537,7 +591,7 @@ fn render_cmd_bar(
|
|||||||
let style = report_msg_style(&report, theme, theme.cmd_bar_text);
|
let style = report_msg_style(&report, theme, theme.cmd_bar_text);
|
||||||
let bar = CommandBar::new(
|
let bar = CommandBar::new(
|
||||||
&report.message,
|
&report.message,
|
||||||
&report.context,
|
&report.context1,
|
||||||
style,
|
style,
|
||||||
theme.cmd_bar_background,
|
theme.cmd_bar_background,
|
||||||
);
|
);
|
||||||
@ -1041,6 +1095,7 @@ fn set_config(hm: &mut HashMap<String, Value>, path: &[&str], value: Value) -> b
|
|||||||
fn report_level_style(level: Severity, theme: &StyleConfig) -> NuStyle {
|
fn report_level_style(level: Severity, theme: &StyleConfig) -> NuStyle {
|
||||||
match level {
|
match level {
|
||||||
Severity::Info => theme.status_info,
|
Severity::Info => theme.status_info,
|
||||||
|
Severity::Success => theme.status_success,
|
||||||
Severity::Warn => theme.status_warn,
|
Severity::Warn => theme.status_warn,
|
||||||
Severity::Err => theme.status_error,
|
Severity::Err => theme.status_error,
|
||||||
}
|
}
|
||||||
@ -1082,3 +1137,30 @@ impl Page {
|
|||||||
Self::raw(Box::new(view), is_light)
|
Self::raw(Box::new(view), is_light)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ViewStack {
|
||||||
|
view: Option<Page>,
|
||||||
|
stack: Vec<Page>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewStack {
|
||||||
|
fn new(view: Option<Page>, stack: Vec<Page>) -> Self {
|
||||||
|
Self { view, stack }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CmdResult {
|
||||||
|
exit: bool,
|
||||||
|
view_change: bool,
|
||||||
|
cmd_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmdResult {
|
||||||
|
fn new(exit: bool, view_change: bool, cmd_name: String) -> Self {
|
||||||
|
Self {
|
||||||
|
exit,
|
||||||
|
view_change,
|
||||||
|
cmd_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,43 +2,61 @@
|
|||||||
pub struct Report {
|
pub struct Report {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub level: Severity,
|
pub level: Severity,
|
||||||
pub context: String,
|
pub context1: String,
|
||||||
pub context2: String,
|
pub context2: String,
|
||||||
|
pub context3: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Report {
|
impl Report {
|
||||||
pub fn new(message: String, level: Severity, context: String, context2: String) -> Self {
|
pub fn new(message: String, level: Severity, ctx1: String, ctx2: String, ctx3: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
message,
|
message,
|
||||||
level,
|
level,
|
||||||
context,
|
context1: ctx1,
|
||||||
context2,
|
context2: ctx2,
|
||||||
|
context3: ctx3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message(message: impl Into<String>, level: Severity) -> Self {
|
pub fn message(message: impl Into<String>, level: Severity) -> Self {
|
||||||
Self::new(message.into(), level, String::new(), String::new())
|
Self::new(
|
||||||
|
message.into(),
|
||||||
|
level,
|
||||||
|
String::new(),
|
||||||
|
String::new(),
|
||||||
|
String::new(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn info(message: impl Into<String>) -> Self {
|
pub fn info(message: impl Into<String>) -> Self {
|
||||||
Self::new(message.into(), Severity::Info, String::new(), String::new())
|
Self::message(message.into(), Severity::Info)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn success(message: impl Into<String>) -> Self {
|
||||||
|
Self::message(message.into(), Severity::Success)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(message: impl Into<String>) -> Self {
|
pub fn error(message: impl Into<String>) -> Self {
|
||||||
Self::new(message.into(), Severity::Err, String::new(), String::new())
|
Self::message(message.into(), Severity::Err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Report {
|
impl Default for Report {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(String::new(), Severity::Info, String::new(), String::new())
|
Self::new(
|
||||||
|
String::new(),
|
||||||
|
Severity::Info,
|
||||||
|
String::new(),
|
||||||
|
String::new(),
|
||||||
|
String::new(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Severity {
|
pub enum Severity {
|
||||||
Info,
|
Info,
|
||||||
#[allow(dead_code)]
|
Success,
|
||||||
Warn,
|
Warn,
|
||||||
Err,
|
Err,
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use ratatui::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
nu_common::NuStyle,
|
nu_common::{string_width, NuStyle},
|
||||||
views::util::{nu_style_to_tui, set_span},
|
views::util::{nu_style_to_tui, set_span},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -14,15 +14,17 @@ pub struct StatusBar {
|
|||||||
text: (String, Style),
|
text: (String, Style),
|
||||||
ctx1: (String, Style),
|
ctx1: (String, Style),
|
||||||
ctx2: (String, Style),
|
ctx2: (String, Style),
|
||||||
|
ctx3: (String, Style),
|
||||||
back_s: Style,
|
back_s: Style,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatusBar {
|
impl StatusBar {
|
||||||
pub fn new(text: String, ctx: String, ctx2: String) -> Self {
|
pub fn new(text: String, ctx1: String, ctx2: String, ctx3: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
text: (text, Style::default()),
|
text: (text, Style::default()),
|
||||||
ctx1: (ctx, Style::default()),
|
ctx1: (ctx1, Style::default()),
|
||||||
ctx2: (ctx2, Style::default()),
|
ctx2: (ctx2, Style::default()),
|
||||||
|
ctx3: (ctx3, Style::default()),
|
||||||
back_s: Style::default(),
|
back_s: Style::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,7 +33,7 @@ impl StatusBar {
|
|||||||
self.text.1 = nu_style_to_tui(style).add_modifier(Modifier::BOLD);
|
self.text.1 = nu_style_to_tui(style).add_modifier(Modifier::BOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_ctx_style(&mut self, style: NuStyle) {
|
pub fn set_ctx1_style(&mut self, style: NuStyle) {
|
||||||
self.ctx1.1 = nu_style_to_tui(style).add_modifier(Modifier::BOLD);
|
self.ctx1.1 = nu_style_to_tui(style).add_modifier(Modifier::BOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +41,10 @@ impl StatusBar {
|
|||||||
self.ctx2.1 = nu_style_to_tui(style).add_modifier(Modifier::BOLD);
|
self.ctx2.1 = nu_style_to_tui(style).add_modifier(Modifier::BOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_ctx3_style(&mut self, style: NuStyle) {
|
||||||
|
self.ctx3.1 = nu_style_to_tui(style).add_modifier(Modifier::BOLD);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_background_style(&mut self, style: NuStyle) {
|
pub fn set_background_style(&mut self, style: NuStyle) {
|
||||||
self.back_s = nu_style_to_tui(style);
|
self.back_s = nu_style_to_tui(style);
|
||||||
}
|
}
|
||||||
@ -46,8 +52,9 @@ impl StatusBar {
|
|||||||
|
|
||||||
impl Widget for StatusBar {
|
impl Widget for StatusBar {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
const MAX_CONTEXT_WIDTH: u16 = 12;
|
const MAX_CTX1_WIDTH: u16 = 12;
|
||||||
const MAX_CONTEXT2_WIDTH: u16 = 12;
|
const MAX_CTX2_WIDTH: u16 = 12;
|
||||||
|
const MAX_CTX3_WIDTH: u16 = 12;
|
||||||
|
|
||||||
// colorize the line
|
// colorize the line
|
||||||
let block = Block::default().style(self.back_s);
|
let block = Block::default().style(self.back_s);
|
||||||
@ -55,26 +62,70 @@ impl Widget for StatusBar {
|
|||||||
|
|
||||||
let mut used_width = 0;
|
let mut used_width = 0;
|
||||||
|
|
||||||
let (text, style) = &self.ctx1;
|
let (text, style) = self.ctx1;
|
||||||
if !text.is_empty() && area.width > MAX_CONTEXT_WIDTH {
|
let text_width = (string_width(&text) as u16).min(MAX_CTX1_WIDTH);
|
||||||
let x = area.right().saturating_sub(MAX_CONTEXT_WIDTH);
|
used_width +=
|
||||||
set_span(buf, (x, area.y), text, *style, MAX_CONTEXT_WIDTH);
|
try_render_text_from_right_most(area, buf, &text, style, used_width, text_width);
|
||||||
|
|
||||||
used_width += MAX_CONTEXT_WIDTH;
|
let (text, style) = self.ctx2;
|
||||||
}
|
used_width +=
|
||||||
|
try_render_text_from_right_most(area, buf, &text, style, used_width, MAX_CTX2_WIDTH);
|
||||||
|
|
||||||
let (text, style) = &self.ctx2;
|
let (text, style) = self.ctx3;
|
||||||
if !text.is_empty() && area.width > MAX_CONTEXT2_WIDTH + used_width {
|
used_width +=
|
||||||
let x = area.right().saturating_sub(MAX_CONTEXT2_WIDTH + used_width);
|
try_render_text_from_right_most(area, buf, &text, style, used_width, MAX_CTX3_WIDTH);
|
||||||
set_span(buf, (x, area.y), text, *style, MAX_CONTEXT2_WIDTH);
|
|
||||||
|
|
||||||
used_width += MAX_CONTEXT2_WIDTH;
|
let (text, style) = self.text;
|
||||||
}
|
try_render_text_from_left(area, buf, &text, style, used_width);
|
||||||
|
|
||||||
let (text, style) = &self.text;
|
|
||||||
if !text.is_empty() && area.width > used_width {
|
|
||||||
let rest_width = area.width - used_width;
|
|
||||||
set_span(buf, (area.x, area.y), text, *style, rest_width);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_render_text_from_right_most(
|
||||||
|
area: Rect,
|
||||||
|
buf: &mut Buffer,
|
||||||
|
text: &str,
|
||||||
|
style: Style,
|
||||||
|
used_width: u16,
|
||||||
|
span_width: u16,
|
||||||
|
) -> u16 {
|
||||||
|
let dis = span_width + used_width;
|
||||||
|
try_render_text_from_right(area, buf, text, style, dis, used_width, span_width)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_render_text_from_right(
|
||||||
|
area: Rect,
|
||||||
|
buf: &mut Buffer,
|
||||||
|
text: &str,
|
||||||
|
style: Style,
|
||||||
|
distance_from_right: u16,
|
||||||
|
used_width: u16,
|
||||||
|
span_width: u16,
|
||||||
|
) -> u16 {
|
||||||
|
let has_space = !text.is_empty() && area.width > used_width;
|
||||||
|
if !has_space {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = area.right().saturating_sub(distance_from_right);
|
||||||
|
set_span(buf, (x, area.y), text, style, span_width);
|
||||||
|
|
||||||
|
span_width
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_render_text_from_left(
|
||||||
|
area: Rect,
|
||||||
|
buf: &mut Buffer,
|
||||||
|
text: &str,
|
||||||
|
style: Style,
|
||||||
|
used_width: u16,
|
||||||
|
) -> u16 {
|
||||||
|
let has_space = !text.is_empty() && area.width > used_width;
|
||||||
|
if !has_space {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rest_width = area.width - used_width;
|
||||||
|
set_span(buf, (area.x, area.y), text, style, rest_width);
|
||||||
|
|
||||||
|
rest_width
|
||||||
|
}
|
||||||
|
@ -246,13 +246,13 @@ impl<'a> RecordView<'a> {
|
|||||||
let covered_percent = report_row_position(layer.cursor);
|
let covered_percent = report_row_position(layer.cursor);
|
||||||
let cursor = report_cursor_position(self.mode, layer.cursor);
|
let cursor = report_cursor_position(self.mode, layer.cursor);
|
||||||
let message = layer.name.clone().unwrap_or_default();
|
let message = layer.name.clone().unwrap_or_default();
|
||||||
|
// note: maybe came up with a better short names? E/V/N?
|
||||||
|
let mode = match self.mode {
|
||||||
|
UIMode::Cursor => String::from("EDIT"),
|
||||||
|
UIMode::View => String::from("VIEW"),
|
||||||
|
};
|
||||||
|
|
||||||
Report {
|
Report::new(message, Severity::Info, mode, cursor, covered_percent)
|
||||||
message,
|
|
||||||
context: covered_percent,
|
|
||||||
context2: cursor,
|
|
||||||
level: Severity::Info,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user