mirror of
https://github.com/nushell/nushell.git
synced 2024-12-23 23:49:44 +01: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;
|
||||
}
|
||||
|
||||
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<String, Value>) {
|
||||
|
||||
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<String, Value>) {
|
||||
.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);
|
||||
|
||||
|
@ -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()));
|
||||
|
||||
|
@ -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 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};
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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<Page>,
|
||||
view: Option<Page>,
|
||||
commands: CommandRegistry,
|
||||
) -> Result<Option<Value>> {
|
||||
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<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(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
pager: &mut Pager,
|
||||
view: &mut Option<Page>,
|
||||
view_stack: &mut Vec<Page>,
|
||||
view_stack: &mut ViewStack,
|
||||
commands: &CommandRegistry,
|
||||
args: String,
|
||||
) -> std::result::Result<bool, String> {
|
||||
) -> result::Result<CmdResult, String> {
|
||||
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 {
|
||||
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<Page>,
|
||||
view_stack: &mut Vec<Page>,
|
||||
view_stack: &mut ViewStack,
|
||||
command: Command,
|
||||
args: &str,
|
||||
) -> std::result::Result<bool, String> {
|
||||
) -> Result<CmdResult> {
|
||||
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<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) {
|
||||
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<String, Value>, 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<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 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<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 {
|
||||
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 {
|
||||
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,
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user