From 99caad7d60b359d64973e19a5a66ce79670158d3 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Wed, 6 Sep 2023 18:24:24 +0000 Subject: [PATCH] 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 --- crates/nu-explore/src/explore.rs | 7 + crates/nu-explore/src/lib.rs | 1 + crates/nu-explore/src/nu_common/mod.rs | 2 +- crates/nu-explore/src/nu_common/string.rs | 4 +- crates/nu-explore/src/pager/mod.rs | 390 +++++++++++++--------- crates/nu-explore/src/pager/report.rs | 36 +- crates/nu-explore/src/pager/status_bar.rs | 99 ++++-- crates/nu-explore/src/views/record/mod.rs | 12 +- 8 files changed, 356 insertions(+), 195 deletions(-) diff --git a/crates/nu-explore/src/explore.rs b/crates/nu-explore/src/explore.rs index e385bfb583..fb4d8cf814 100644 --- a/crates/nu-explore/src/explore.rs +++ b/crates/nu-explore/src/explore.rs @@ -182,6 +182,10 @@ fn style_from_config(config: &HashMap) -> StyleConfig { style.status_info = *s; } + if let Some(s) = colors.get("success") { + style.status_success = *s; + } + if let Some(s) = colors.get("warn") { style.status_warn = *s; } @@ -208,6 +212,8 @@ fn prepare_default_config(config: &mut HashMap) { 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 TABLE_SPLIT_LINE: Style = color(Some(Color::Rgb(64, 64, 64)), None); @@ -245,6 +251,7 @@ fn prepare_default_config(config: &mut HashMap) { .unwrap_or_default(); 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, "error", STATUS_ERROR); diff --git a/crates/nu-explore/src/lib.rs b/crates/nu-explore/src/lib.rs index 9ef32746da..38983e99e0 100644 --- a/crates/nu-explore/src/lib.rs +++ b/crates/nu-explore/src/lib.rs @@ -134,6 +134,7 @@ fn create_config_command(commands: &[Command]) -> ConfigCmd { 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())); diff --git a/crates/nu-explore/src/nu_common/mod.rs b/crates/nu-explore/src/nu_common/mod.rs index 337e767f6b..fbf47c2fc6 100644 --- a/crates/nu-explore/src/nu_common/mod.rs +++ b/crates/nu-explore/src/nu_common/mod.rs @@ -17,7 +17,7 @@ pub type CtrlC = Option>; pub use command::{is_ignored_command, run_command_with_value, run_nu_command}; 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 value::{collect_input, collect_pipeline, create_map, map_into_value, nu_str}; diff --git a/crates/nu-explore/src/nu_common/string.rs b/crates/nu-explore/src/nu_common/string.rs index e28fdd0f6d..ee4fda8319 100644 --- a/crates/nu-explore/src/nu_common/string.rs +++ b/crates/nu-explore/src/nu_common/string.rs @@ -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) { if width == 0 { diff --git a/crates/nu-explore/src/pager/mod.rs b/crates/nu-explore/src/pager/mod.rs index e71e8ca5db..8b1f47b02d 100644 --- a/crates/nu-explore/src/pager/mod.rs +++ b/crates/nu-explore/src/pager/mod.rs @@ -6,6 +6,7 @@ mod status_bar; use std::{ cmp::min, io::{self, Result, Stdout}, + result, sync::atomic::Ordering, }; @@ -80,6 +81,7 @@ struct CommandBuf { #[derive(Debug, Default, Clone)] pub struct StyleConfig { pub status_info: NuStyle, + pub status_success: NuStyle, pub status_warn: NuStyle, pub status_error: NuStyle, pub status_bar_background: NuStyle, @@ -125,6 +127,7 @@ impl<'a> Pager<'a> { } ["highlight"] => value_as_style(&mut self.config.style.highlight, &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", "error"] => value_as_style(&mut self.config.style.status_error, &value), path => set_config(&mut self.config.config, path, value), @@ -245,13 +248,12 @@ fn render_ui( ctrlc: CtrlC, pager: &mut Pager<'_>, info: &mut ViewInfo, - mut view: Option, + view: Option, commands: CommandRegistry, ) -> Result> { 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 { // handle CTRLC event if let Some(ctrlc) = ctrlc.clone() { @@ -264,39 +266,11 @@ fn render_ui( { let info = info.clone(); term.draw(|f| { - let area = f.size(); - 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); + draw_frame(f, &mut view_stack.view, pager, &mut layout, info); })?; } - let status = handle_events( + let transition = handle_events( engine_state, stack, &events, @@ -304,42 +278,36 @@ fn render_ui( info, &mut pager.search_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 { - match status { - Transition::Exit => { - break Ok(try_to_peek_value(pager, view.as_mut().map(|p| &mut p.view))); - } - Transition::Ok => { - if view_stack.is_empty() && pager.config.exit_esc { - break Ok(try_to_peek_value(pager, view.as_mut().map(|p| &mut p.view))); - } + if let Some(transition) = transition { + let (exit, cmd_name) = react_to_event_result( + transition, + engine_state, + &commands, + pager, + &mut view_stack, + stack, + info, + ); - // try to pop the view stack - if let Some(v) = view_stack.pop() { - view = Some(v); - } - } - Transition::Cmd(command) => { - let out = pager_run_command( - engine_state, - stack, - pager, - &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)), - } + if let Some(value) = exit { + break Ok(value); + } + + if !cmd_name.is_empty() { + if let Some(r) = info.report.as_mut() { + r.message = cmd_name; + r.level = Severity::Success; + } else { + info.report = Some(Report::success(cmd_name)); } + + 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.buf_cmd2 = String::new(); - let out = pager_run_command( - engine_state, - stack, - pager, - &mut view, - &mut view_stack, - &commands, - args, - ); + let out = + pager_run_command(engine_state, stack, pager, &mut view_stack, &commands, args); match out { - Ok(false) => {} - Ok(true) => break Ok(try_to_peek_value(pager, view.as_mut().map(|p| &mut p.view))), + Ok(result) => { + 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)), } } } } -#[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>, 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, pager: &mut Pager<'_>) -> Option { + 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, + 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( engine_state: &EngineState, stack: &mut Stack, pager: &mut Pager, - view: &mut Option, - view_stack: &mut Vec, + view_stack: &mut ViewStack, commands: &CommandRegistry, args: String, -) -> std::result::Result { +) -> result::Result { 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, - view_stack: &mut Vec, - command: Option>, - args: &str, -) -> std::result::Result { match 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!( "Error: command {args:?} was not provided with correct arguments: {err}" @@ -404,80 +466,62 @@ fn run_command( engine_state: &EngineState, stack: &mut Stack, pager: &mut Pager, - view: &mut Option, - view_stack: &mut Vec, + view_stack: &mut ViewStack, command: Command, - args: &str, -) -> std::result::Result { +) -> Result { match command { Command::Reactive(mut command) => { // what we do we just replace the view. - let value = view.as_mut().and_then(|p| p.view.exit()); - let result = command.react(engine_state, stack, pager, value); - match result { - Ok(transition) => match transition { - Transition::Ok => { - // so we basically allow a change of a config inside a command, - // and cause of this we wanna update all of our views. - // - // THOUGH: MOST LIKELY IT WON'T BE CHANGED AND WE DO A WASTE....... + let value = view_stack.view.as_mut().and_then(|p| p.view.exit()); + let transition = command.react(engine_state, stack, pager, value)?; + match transition { + Transition::Ok => { + // so we basically allow a change of a config inside a command, + // and cause of this we wanna update all of our views. + // + // THOUGH: MOST LIKELY IT WON'T BE CHANGED AND WE DO A WASTE....... - { - 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, - )); - } + update_view_stack_setup(view_stack, &pager.config); - for page in view_stack { - page.view.setup(ViewConfig::new( - pager.config.nu_config, - pager.config.style_computer, - &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}")), + Ok(CmdResult::new(false, false, String::new())) + } + Transition::Exit => Ok(CmdResult::new(true, false, String::new())), + Transition::Cmd { .. } => todo!("not used so far"), } } Command::View { mut cmd, is_light } => { // what we do we just replace the view. - let value = view.as_mut().and_then(|p| p.view.exit()); - let result = cmd.spawn(engine_state, stack, value); - match result { - Ok(mut new_view) => { - if let Some(view) = view.take() { - 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) + let value = view_stack.view.as_mut().and_then(|p| p.view.exit()); + let mut new_view = cmd.spawn(engine_state, stack, value)?; + if let Some(view) = view_stack.view.take() { + if !view.is_light { + view_stack.stack.push(view); } - 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, 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) { if pager.cmd_buf.is_cmd_input { // 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) { 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_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_ctx3_style(theme.status_bar_text); 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 { if matches!(report.level, Severity::Info) { style @@ -537,7 +591,7 @@ fn render_cmd_bar( let style = report_msg_style(&report, theme, theme.cmd_bar_text); let bar = CommandBar::new( &report.message, - &report.context, + &report.context1, style, theme.cmd_bar_background, ); @@ -1041,6 +1095,7 @@ fn set_config(hm: &mut HashMap, path: &[&str], value: Value) -> b fn report_level_style(level: Severity, theme: &StyleConfig) -> NuStyle { match level { Severity::Info => theme.status_info, + Severity::Success => theme.status_success, Severity::Warn => theme.status_warn, Severity::Err => theme.status_error, } @@ -1082,3 +1137,30 @@ impl Page { Self::raw(Box::new(view), is_light) } } + +struct ViewStack { + view: Option, + stack: Vec, +} + +impl ViewStack { + fn new(view: Option, stack: Vec) -> 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, + } + } +} diff --git a/crates/nu-explore/src/pager/report.rs b/crates/nu-explore/src/pager/report.rs index 69934c552c..e2fc180c2a 100644 --- a/crates/nu-explore/src/pager/report.rs +++ b/crates/nu-explore/src/pager/report.rs @@ -2,43 +2,61 @@ pub struct Report { pub message: String, pub level: Severity, - pub context: String, + pub context1: String, pub context2: String, + pub context3: String, } 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 { message, level, - context, - context2, + context1: ctx1, + context2: ctx2, + context3: ctx3, } } pub fn message(message: impl Into, 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) -> Self { - Self::new(message.into(), Severity::Info, String::new(), String::new()) + Self::message(message.into(), Severity::Info) + } + + pub fn success(message: impl Into) -> Self { + Self::message(message.into(), Severity::Success) } pub fn error(message: impl Into) -> Self { - Self::new(message.into(), Severity::Err, String::new(), String::new()) + Self::message(message.into(), Severity::Err) } } impl Default for Report { 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)] pub enum Severity { Info, - #[allow(dead_code)] + Success, Warn, Err, } diff --git a/crates/nu-explore/src/pager/status_bar.rs b/crates/nu-explore/src/pager/status_bar.rs index 32c5dc4b0f..949fdfe517 100644 --- a/crates/nu-explore/src/pager/status_bar.rs +++ b/crates/nu-explore/src/pager/status_bar.rs @@ -6,7 +6,7 @@ use ratatui::{ }; use crate::{ - nu_common::NuStyle, + nu_common::{string_width, NuStyle}, views::util::{nu_style_to_tui, set_span}, }; @@ -14,15 +14,17 @@ pub struct StatusBar { text: (String, Style), ctx1: (String, Style), ctx2: (String, Style), + ctx3: (String, Style), back_s: Style, } 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 { text: (text, Style::default()), - ctx1: (ctx, Style::default()), + ctx1: (ctx1, Style::default()), ctx2: (ctx2, Style::default()), + ctx3: (ctx3, Style::default()), back_s: Style::default(), } } @@ -31,7 +33,7 @@ impl StatusBar { 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); } @@ -39,6 +41,10 @@ impl StatusBar { 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) { self.back_s = nu_style_to_tui(style); } @@ -46,8 +52,9 @@ impl StatusBar { impl Widget for StatusBar { fn render(self, area: Rect, buf: &mut Buffer) { - const MAX_CONTEXT_WIDTH: u16 = 12; - const MAX_CONTEXT2_WIDTH: u16 = 12; + const MAX_CTX1_WIDTH: u16 = 12; + const MAX_CTX2_WIDTH: u16 = 12; + const MAX_CTX3_WIDTH: u16 = 12; // colorize the line let block = Block::default().style(self.back_s); @@ -55,26 +62,70 @@ impl Widget for StatusBar { let mut used_width = 0; - let (text, style) = &self.ctx1; - if !text.is_empty() && area.width > MAX_CONTEXT_WIDTH { - let x = area.right().saturating_sub(MAX_CONTEXT_WIDTH); - set_span(buf, (x, area.y), text, *style, MAX_CONTEXT_WIDTH); + let (text, style) = self.ctx1; + let text_width = (string_width(&text) as u16).min(MAX_CTX1_WIDTH); + used_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; - if !text.is_empty() && area.width > MAX_CONTEXT2_WIDTH + used_width { - let x = area.right().saturating_sub(MAX_CONTEXT2_WIDTH + used_width); - set_span(buf, (x, area.y), text, *style, MAX_CONTEXT2_WIDTH); + let (text, style) = self.ctx3; + used_width += + try_render_text_from_right_most(area, buf, &text, style, used_width, MAX_CTX3_WIDTH); - used_width += MAX_CONTEXT2_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); - } + let (text, style) = self.text; + try_render_text_from_left(area, buf, &text, style, used_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 +} diff --git a/crates/nu-explore/src/views/record/mod.rs b/crates/nu-explore/src/views/record/mod.rs index b7c92eb29a..80c125d785 100644 --- a/crates/nu-explore/src/views/record/mod.rs +++ b/crates/nu-explore/src/views/record/mod.rs @@ -246,13 +246,13 @@ impl<'a> RecordView<'a> { let covered_percent = report_row_position(layer.cursor); let cursor = report_cursor_position(self.mode, layer.cursor); 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 { - message, - context: covered_percent, - context2: cursor, - level: Severity::Info, - } + Report::new(message, Severity::Info, mode, cursor, covered_percent) } }