update default layout (#523)
* update layouts * add other duration changes * fmt :(
This commit is contained in:
parent
702a644f68
commit
e8c8415278
6 changed files with 143 additions and 157 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -86,7 +86,6 @@ dependencies = [
|
||||||
"directories",
|
"directories",
|
||||||
"eyre",
|
"eyre",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"humantime 2.1.0",
|
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
|
@ -568,7 +567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"humantime 1.3.0",
|
"humantime",
|
||||||
"log",
|
"log",
|
||||||
"regex",
|
"regex",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
|
@ -837,12 +836,6 @@ dependencies = [
|
||||||
"quick-error",
|
"quick-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "humantime"
|
|
||||||
version = "2.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.14.19"
|
version = "0.14.19"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
name = "atuin"
|
name = "atuin"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
authors = ["Ellie Huxtable <ellie@elliehuxtable.com>"]
|
authors = ["Ellie Huxtable <ellie@elliehuxtable.com>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
rust-version = "1.59"
|
rust-version = "1.59"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
description = "atuin - magical shell history"
|
description = "atuin - magical shell history"
|
||||||
|
@ -65,7 +65,6 @@ async-trait = "0.1.49"
|
||||||
chrono-english = "0.1.4"
|
chrono-english = "0.1.4"
|
||||||
cli-table = { version = "0.4", default-features = false }
|
cli-table = { version = "0.4", default-features = false }
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
humantime = "2.1.0"
|
|
||||||
crossbeam-channel = "0.5.1"
|
crossbeam-channel = "0.5.1"
|
||||||
clap = { version = "3.1.18", features = ["derive"] }
|
clap = { version = "3.1.18", features = ["derive"] }
|
||||||
clap_complete = "3.1.4"
|
clap_complete = "3.1.4"
|
||||||
|
|
|
@ -16,6 +16,8 @@ use atuin_client::{
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
use atuin_client::sync;
|
use atuin_client::sync;
|
||||||
|
|
||||||
|
use super::search::format_duration;
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
#[clap(infer_subcommands = true)]
|
#[clap(infer_subcommands = true)]
|
||||||
pub enum Cmd {
|
pub enum Cmd {
|
||||||
|
@ -92,11 +94,7 @@ pub fn print_list(h: &[History], list_mode: ListMode) {
|
||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
pub fn print_human_list(w: &mut StdoutLock, h: &[History]) {
|
pub fn print_human_list(w: &mut StdoutLock, h: &[History]) {
|
||||||
for h in h.iter().rev() {
|
for h in h.iter().rev() {
|
||||||
let duration =
|
let duration = format_duration(Duration::from_nanos(std::cmp::max(h.duration, 0) as u64));
|
||||||
humantime::format_duration(Duration::from_nanos(std::cmp::max(h.duration, 0) as u64))
|
|
||||||
.to_string();
|
|
||||||
let duration: Vec<&str> = duration.split(' ').collect();
|
|
||||||
let duration = duration[0];
|
|
||||||
|
|
||||||
let time = h.timestamp.format("%Y-%m-%d %H:%M:%S");
|
let time = h.timestamp.format("%Y-%m-%d %H:%M:%S");
|
||||||
let cmd = h.command.trim();
|
let cmd = h.command.trim();
|
||||||
|
@ -108,11 +106,7 @@ pub fn print_human_list(w: &mut StdoutLock, h: &[History]) {
|
||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
pub fn print_regular(w: &mut StdoutLock, h: &[History]) {
|
pub fn print_regular(w: &mut StdoutLock, h: &[History]) {
|
||||||
for h in h.iter().rev() {
|
for h in h.iter().rev() {
|
||||||
let duration =
|
let duration = format_duration(Duration::from_nanos(std::cmp::max(h.duration, 0) as u64));
|
||||||
humantime::format_duration(Duration::from_nanos(std::cmp::max(h.duration, 0) as u64))
|
|
||||||
.to_string();
|
|
||||||
let duration: Vec<&str> = duration.split(' ').collect();
|
|
||||||
let duration = duration[0];
|
|
||||||
|
|
||||||
let time = h.timestamp.format("%Y-%m-%d %H:%M:%S");
|
let time = h.timestamp.format("%Y-%m-%d %H:%M:%S");
|
||||||
let cmd = h.command.trim();
|
let cmd = h.command.trim();
|
||||||
|
|
|
@ -9,8 +9,10 @@ use atuin_client::{
|
||||||
use super::history::ListMode;
|
use super::history::ListMode;
|
||||||
|
|
||||||
mod cursor;
|
mod cursor;
|
||||||
|
mod duration;
|
||||||
mod event;
|
mod event;
|
||||||
mod interactive;
|
mod interactive;
|
||||||
|
pub use duration::format_duration;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub struct Cmd {
|
pub struct Cmd {
|
||||||
|
|
50
src/command/client/search/duration.rs
Normal file
50
src/command/client/search/duration.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use std::{ops::ControlFlow, time::Duration};
|
||||||
|
|
||||||
|
#[allow(clippy::module_name_repetitions)]
|
||||||
|
pub fn format_duration(f: Duration) -> String {
|
||||||
|
fn item(name: &str, value: u64) -> ControlFlow<String> {
|
||||||
|
if value > 0 {
|
||||||
|
ControlFlow::Break(format!("{}{}", value, name))
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl taken and modified from
|
||||||
|
// https://github.com/tailhook/humantime/blob/master/src/duration.rs#L295-L331
|
||||||
|
// Copyright (c) 2016 The humantime Developers
|
||||||
|
fn fmt(f: Duration) -> ControlFlow<String, ()> {
|
||||||
|
let secs = f.as_secs();
|
||||||
|
let nanos = f.subsec_nanos();
|
||||||
|
|
||||||
|
let years = secs / 31_557_600; // 365.25d
|
||||||
|
let year_days = secs % 31_557_600;
|
||||||
|
let months = year_days / 2_630_016; // 30.44d
|
||||||
|
let month_days = year_days % 2_630_016;
|
||||||
|
let days = month_days / 86400;
|
||||||
|
let day_secs = month_days % 86400;
|
||||||
|
let hours = day_secs / 3600;
|
||||||
|
let minutes = day_secs % 3600 / 60;
|
||||||
|
let seconds = day_secs % 60;
|
||||||
|
|
||||||
|
let millis = nanos / 1_000_000;
|
||||||
|
|
||||||
|
// a difference from our impl than the original is that
|
||||||
|
// we only care about the most-significant segment of the duration.
|
||||||
|
// If the item call returns `Break`, then the `?` will early-return.
|
||||||
|
// This allows for a very consise impl
|
||||||
|
item("y", years)?;
|
||||||
|
item("mo", months)?;
|
||||||
|
item("d", days)?;
|
||||||
|
item("h", hours)?;
|
||||||
|
item("m", minutes)?;
|
||||||
|
item("s", seconds)?;
|
||||||
|
item("ms", u64::from(millis))?;
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
match fmt(f) {
|
||||||
|
ControlFlow::Break(b) => b,
|
||||||
|
ControlFlow::Continue(()) => String::from("0s"),
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ use tui::{
|
||||||
layout::{Alignment, Constraint, Corner, Direction, Layout},
|
layout::{Alignment, Constraint, Corner, Direction, Layout},
|
||||||
style::{Color, Modifier, Style},
|
style::{Color, Modifier, Style},
|
||||||
text::{Span, Spans, Text},
|
text::{Span, Spans, Text},
|
||||||
widgets::{Block, Borders, List, ListItem, ListState, Paragraph},
|
widgets::{Block, BorderType, Borders, List, ListItem, ListState, Paragraph},
|
||||||
Frame, Terminal,
|
Frame, Terminal,
|
||||||
};
|
};
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
@ -26,6 +26,7 @@ use atuin_client::{
|
||||||
use super::{
|
use super::{
|
||||||
cursor::Cursor,
|
cursor::Cursor,
|
||||||
event::{Event, Events},
|
event::{Event, Events},
|
||||||
|
format_duration,
|
||||||
};
|
};
|
||||||
use crate::VERSION;
|
use crate::VERSION;
|
||||||
|
|
||||||
|
@ -41,17 +42,12 @@ struct State {
|
||||||
context: Context,
|
context: Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
fn duration(h: &History) -> String {
|
||||||
#[allow(clippy::cast_sign_loss)]
|
let duration = Duration::from_nanos(u64::try_from(h.duration).unwrap_or(0));
|
||||||
fn durations(&self) -> Vec<(String, String)> {
|
format_duration(duration)
|
||||||
self.results
|
}
|
||||||
.iter()
|
|
||||||
.map(|h| {
|
|
||||||
let duration =
|
|
||||||
Duration::from_millis(std::cmp::max(h.duration, 0) as u64 / 1_000_000);
|
|
||||||
let duration = humantime::format_duration(duration).to_string();
|
|
||||||
let duration: Vec<&str> = duration.split(' ').collect();
|
|
||||||
|
|
||||||
|
fn ago(h: &History) -> String {
|
||||||
let ago = chrono::Utc::now().sub(h.timestamp);
|
let ago = chrono::Utc::now().sub(h.timestamp);
|
||||||
|
|
||||||
// Account for the chance that h.timestamp is "in the future"
|
// Account for the chance that h.timestamp is "in the future"
|
||||||
|
@ -59,102 +55,49 @@ impl State {
|
||||||
// would fail.
|
// would fail.
|
||||||
// If the timestamp would otherwise be in the future, display
|
// If the timestamp would otherwise be in the future, display
|
||||||
// the time ago as 0.
|
// the time ago as 0.
|
||||||
let ago = humantime::format_duration(
|
let ago = ago.to_std().unwrap_or_default();
|
||||||
ago.to_std().unwrap_or_else(|_| Duration::new(0, 0)),
|
format_duration(ago) + " ago"
|
||||||
)
|
}
|
||||||
.to_string();
|
|
||||||
let ago: Vec<&str> = ago.split(' ').collect();
|
|
||||||
|
|
||||||
(
|
|
||||||
duration[0]
|
|
||||||
.to_string()
|
|
||||||
.replace("days", "d")
|
|
||||||
.replace("day", "d")
|
|
||||||
.replace("weeks", "w")
|
|
||||||
.replace("week", "w")
|
|
||||||
.replace("months", "mo")
|
|
||||||
.replace("month", "mo")
|
|
||||||
.replace("years", "y")
|
|
||||||
.replace("year", "y"),
|
|
||||||
ago[0]
|
|
||||||
.to_string()
|
|
||||||
.replace("days", "d")
|
|
||||||
.replace("day", "d")
|
|
||||||
.replace("weeks", "w")
|
|
||||||
.replace("week", "w")
|
|
||||||
.replace("months", "mo")
|
|
||||||
.replace("month", "mo")
|
|
||||||
.replace("years", "y")
|
|
||||||
.replace("year", "y")
|
|
||||||
+ " ago",
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
impl State {
|
||||||
fn render_results<T: tui::backend::Backend>(
|
fn render_results<T: tui::backend::Backend>(
|
||||||
&mut self,
|
&mut self,
|
||||||
f: &mut tui::Frame<T>,
|
f: &mut tui::Frame<T>,
|
||||||
r: tui::layout::Rect,
|
r: tui::layout::Rect,
|
||||||
b: tui::widgets::Block,
|
b: tui::widgets::Block,
|
||||||
) {
|
) {
|
||||||
let durations = self.durations();
|
let max_length = 12; // '123ms' + '59s ago'
|
||||||
let max_length = durations.iter().fold(0, |largest, i| {
|
|
||||||
std::cmp::max(largest, i.0.len() + i.1.len())
|
|
||||||
});
|
|
||||||
|
|
||||||
let results: Vec<ListItem> = self
|
let results: Vec<ListItem> = self
|
||||||
.results
|
.results
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, m)| {
|
.map(|(i, m)| {
|
||||||
let command = m.command.to_string().replace('\n', " ").replace('\t', " ");
|
// these encode the slices of `" > "`, `" {n} "`, or `" "` in a compact form.
|
||||||
|
// Yes, this is a hack, but it makes me feel happy
|
||||||
|
let slices = " > 1 2 3 4 5 6 7 8 9 ";
|
||||||
|
let index = self.results_state.selected().and_then(|s| i.checked_sub(s));
|
||||||
|
let slice_index = index.unwrap_or(10).min(10) * 2;
|
||||||
|
|
||||||
let mut command = Span::raw(command);
|
let status_colour = if m.success() {
|
||||||
|
|
||||||
let (duration, mut ago) = durations[i].clone();
|
|
||||||
|
|
||||||
while (duration.len() + ago.len()) < max_length {
|
|
||||||
ago = format!(" {}", ago);
|
|
||||||
}
|
|
||||||
|
|
||||||
let selected_index = match self.results_state.selected() {
|
|
||||||
None => Span::raw(" "),
|
|
||||||
Some(selected) => match i.checked_sub(selected) {
|
|
||||||
None => Span::raw(" "),
|
|
||||||
Some(diff) => {
|
|
||||||
if 0 < diff && diff < 10 {
|
|
||||||
Span::raw(format!(" {} ", diff))
|
|
||||||
} else {
|
|
||||||
Span::raw(" ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let duration = Span::styled(
|
|
||||||
duration,
|
|
||||||
Style::default().fg(if m.success() {
|
|
||||||
Color::Green
|
Color::Green
|
||||||
} else {
|
} else {
|
||||||
Color::Red
|
Color::Red
|
||||||
}),
|
};
|
||||||
);
|
let ago = ago(m);
|
||||||
|
let duration = format!("{:width$}", duration(m), width = max_length - ago.len());
|
||||||
|
|
||||||
let ago = Span::styled(ago, Style::default().fg(Color::Blue));
|
let command = m.command.replace(['\n', '\t'], " ");
|
||||||
|
let mut command = Span::raw(command);
|
||||||
if let Some(selected) = self.results_state.selected() {
|
if slice_index == 0 {
|
||||||
if selected == i {
|
command.style = Style::default().fg(Color::Red).add_modifier(Modifier::BOLD);
|
||||||
command.style =
|
|
||||||
Style::default().fg(Color::Red).add_modifier(Modifier::BOLD);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let spans = Spans::from(vec![
|
let spans = Spans::from(vec![
|
||||||
selected_index,
|
Span::raw(&slices[slice_index..slice_index + 3]),
|
||||||
duration,
|
Span::styled(duration, Style::default().fg(status_colour)),
|
||||||
Span::raw(" "),
|
Span::raw(" "),
|
||||||
ago,
|
Span::styled(ago, Style::default().fg(Color::Blue)),
|
||||||
Span::raw(" "),
|
Span::raw(" "),
|
||||||
command,
|
command,
|
||||||
]);
|
]);
|
||||||
|
@ -163,10 +106,7 @@ impl State {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let results = List::new(results)
|
let results = List::new(results).block(b).start_corner(Corner::BottomLeft);
|
||||||
.block(b)
|
|
||||||
.start_corner(Corner::BottomLeft)
|
|
||||||
.highlight_symbol(">> ");
|
|
||||||
|
|
||||||
f.render_stateful_widget(results, r, &mut self.results_state);
|
f.render_stateful_widget(results, r, &mut self.results_state);
|
||||||
}
|
}
|
||||||
|
@ -280,73 +220,78 @@ impl State {
|
||||||
fn draw<T: Backend>(&mut self, f: &mut Frame<'_, T>, history_count: i64) {
|
fn draw<T: Backend>(&mut self, f: &mut Frame<'_, T>, history_count: i64) {
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.margin(1)
|
.margin(0)
|
||||||
.constraints(
|
.constraints([
|
||||||
[
|
Constraint::Length(3),
|
||||||
Constraint::Length(2),
|
|
||||||
Constraint::Min(1),
|
Constraint::Min(1),
|
||||||
Constraint::Length(3),
|
Constraint::Length(3),
|
||||||
]
|
])
|
||||||
.as_ref(),
|
|
||||||
)
|
|
||||||
.split(f.size());
|
.split(f.size());
|
||||||
|
|
||||||
let top_chunks = Layout::default()
|
let top_chunks = Layout::default()
|
||||||
.direction(Direction::Horizontal)
|
.direction(Direction::Horizontal)
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
.constraints([Constraint::Percentage(50); 2])
|
||||||
.split(chunks[0]);
|
.split(chunks[0]);
|
||||||
|
|
||||||
let top_left_chunks = Layout::default()
|
let top_left_chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([Constraint::Length(1), Constraint::Length(1)].as_ref())
|
.constraints([Constraint::Length(1); 3])
|
||||||
.split(top_chunks[0]);
|
.split(top_chunks[0]);
|
||||||
|
|
||||||
let top_right_chunks = Layout::default()
|
let top_right_chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([Constraint::Length(1), Constraint::Length(1)].as_ref())
|
.constraints([Constraint::Length(1); 3])
|
||||||
.split(top_chunks[1]);
|
.split(top_chunks[1]);
|
||||||
|
|
||||||
let title = Paragraph::new(Text::from(Span::styled(
|
let title = Paragraph::new(Text::from(Span::styled(
|
||||||
format!("Atuin v{}", VERSION),
|
format!(" Atuin v{VERSION}"),
|
||||||
Style::default().add_modifier(Modifier::BOLD),
|
Style::default().add_modifier(Modifier::BOLD),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let help = vec![
|
let help = vec![
|
||||||
Span::raw("Press "),
|
Span::raw(" Press "),
|
||||||
Span::styled("Esc", Style::default().add_modifier(Modifier::BOLD)),
|
Span::styled("Esc", Style::default().add_modifier(Modifier::BOLD)),
|
||||||
Span::raw(" to exit."),
|
Span::raw(" to exit."),
|
||||||
];
|
];
|
||||||
|
|
||||||
let help = Text::from(Spans::from(help));
|
let help = Paragraph::new(Text::from(Spans::from(help)));
|
||||||
let help = Paragraph::new(help);
|
|
||||||
|
|
||||||
let input = Paragraph::new(self.input.as_str().to_owned()).block(
|
|
||||||
Block::default()
|
|
||||||
.borders(Borders::ALL)
|
|
||||||
.title(self.filter_mode.as_str()),
|
|
||||||
);
|
|
||||||
|
|
||||||
let stats = Paragraph::new(Text::from(Span::raw(format!(
|
let stats = Paragraph::new(Text::from(Span::raw(format!(
|
||||||
"history count: {}",
|
"history count: {history_count} ",
|
||||||
history_count,
|
))));
|
||||||
))))
|
|
||||||
.alignment(Alignment::Right);
|
|
||||||
|
|
||||||
f.render_widget(title, top_left_chunks[0]);
|
f.render_widget(title, top_left_chunks[1]);
|
||||||
f.render_widget(help, top_left_chunks[1]);
|
f.render_widget(help, top_left_chunks[2]);
|
||||||
f.render_widget(stats, top_right_chunks[0]);
|
f.render_widget(stats.alignment(Alignment::Right), top_right_chunks[1]);
|
||||||
|
|
||||||
self.render_results(
|
self.render_results(
|
||||||
f,
|
f,
|
||||||
chunks[1],
|
chunks[1],
|
||||||
Block::default().borders(Borders::ALL).title("History"),
|
Block::default()
|
||||||
|
.borders(Borders::TOP | Borders::LEFT | Borders::RIGHT)
|
||||||
|
.border_type(BorderType::Rounded), // .title("History"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let input = format!(
|
||||||
|
"[{:^14}] {}",
|
||||||
|
self.filter_mode.as_str(),
|
||||||
|
self.input.as_str(),
|
||||||
|
);
|
||||||
|
let input = Paragraph::new(input).block(
|
||||||
|
Block::default()
|
||||||
|
.borders(Borders::BOTTOM | Borders::LEFT | Borders::RIGHT)
|
||||||
|
.border_type(BorderType::Rounded)
|
||||||
|
.title(format!(
|
||||||
|
"{:─>width$}",
|
||||||
|
"",
|
||||||
|
width = chunks[2].width as usize - 2
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
f.render_widget(input, chunks[2]);
|
f.render_widget(input, chunks[2]);
|
||||||
|
|
||||||
let width = UnicodeWidthStr::width(self.input.substring());
|
let width = UnicodeWidthStr::width(self.input.substring());
|
||||||
f.set_cursor(
|
f.set_cursor(
|
||||||
// Put cursor past the end of the input text
|
// Put cursor past the end of the input text
|
||||||
chunks[2].x + width as u16 + 1,
|
chunks[2].x + width as u16 + 18,
|
||||||
// Move one line down, from the border to the input line
|
// Move one line down, from the border to the input line
|
||||||
chunks[2].y + 1,
|
chunks[2].y + 1,
|
||||||
);
|
);
|
||||||
|
@ -399,22 +344,25 @@ impl State {
|
||||||
.style(Style::default().fg(Color::DarkGray))
|
.style(Style::default().fg(Color::DarkGray))
|
||||||
.alignment(Alignment::Right);
|
.alignment(Alignment::Right);
|
||||||
|
|
||||||
let filter_mode = self.filter_mode.as_str();
|
|
||||||
let input = Paragraph::new(format!("{}] {}", filter_mode, self.input.as_str()))
|
|
||||||
.block(Block::default());
|
|
||||||
|
|
||||||
f.render_widget(title, header_chunks[0]);
|
f.render_widget(title, header_chunks[0]);
|
||||||
f.render_widget(help, header_chunks[1]);
|
f.render_widget(help, header_chunks[1]);
|
||||||
f.render_widget(stats, header_chunks[2]);
|
f.render_widget(stats, header_chunks[2]);
|
||||||
|
|
||||||
self.render_results(f, chunks[1], Block::default());
|
self.render_results(f, chunks[1], Block::default());
|
||||||
|
|
||||||
|
let input = format!(
|
||||||
|
"[{:^14}] {}",
|
||||||
|
self.filter_mode.as_str(),
|
||||||
|
self.input.as_str(),
|
||||||
|
);
|
||||||
|
let input = Paragraph::new(input).block(Block::default());
|
||||||
f.render_widget(input, chunks[2]);
|
f.render_widget(input, chunks[2]);
|
||||||
|
|
||||||
let extra_width = UnicodeWidthStr::width(self.input.substring()) + filter_mode.len();
|
let extra_width = UnicodeWidthStr::width(self.input.substring());
|
||||||
|
|
||||||
f.set_cursor(
|
f.set_cursor(
|
||||||
// Put cursor past the end of the input text
|
// Put cursor past the end of the input text
|
||||||
chunks[2].x + extra_width as u16 + 2,
|
chunks[2].x + extra_width as u16 + 17,
|
||||||
// Move one line down, from the border to the input line
|
// Move one line down, from the border to the input line
|
||||||
chunks[2].y + 1,
|
chunks[2].y + 1,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue