summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJiayi Zhao <jeff.no.zhao@gmail.com>2020-02-17 21:37:44 -0500
committerJiayi Zhao <jeff.no.zhao@gmail.com>2020-02-17 21:37:44 -0500
commitaa9b25ab36d6da75d4163f13de7cad5f5ed2ce69 (patch)
tree8c798b86e1ddcc7425d2b89fd417b5267cabf91d /src
parente7bcdd1fc7685e1f132adc267e56cdae2925d632 (diff)
rework menu widget
- menu loop is now contained in widget rather than in run.rs - add tui_footer for showing file info - move TuiDirListDetailed into its own file - add format util file for formatting file info - add support for showing file size, symlink paths and modified times
Diffstat (limited to 'src')
-rw-r--r--src/run.rs37
-rw-r--r--src/ui/mod.rs14
-rw-r--r--src/ui/tui_backend.rs26
-rw-r--r--src/ui/widgets/mod.rs10
-rw-r--r--src/ui/widgets/tui_dirlist.rs136
-rw-r--r--src/ui/widgets/tui_dirlist_detailed.rs117
-rw-r--r--src/ui/widgets/tui_footer.rs61
-rw-r--r--src/ui/widgets/tui_menu.rs162
-rw-r--r--src/util/format.rs33
-rw-r--r--src/util/menu.rs75
-rw-r--r--src/util/mod.rs2
11 files changed, 433 insertions, 240 deletions
diff --git a/src/run.rs b/src/run.rs
index 7b53040..f09dcbe 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -8,7 +8,7 @@ use crate::context::JoshutoContext;
use crate::tab::JoshutoTab;
use crate::ui;
use crate::util::event::{Event, Events};
-use crate::util::menu::OptionMenu;
+use crate::ui::widgets::TuiCommandMenu;
pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) {
let mut backend: ui::TuiBackend = ui::TuiBackend::new().unwrap();
@@ -83,40 +83,13 @@ pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) {
}
}
Some(CommandKeybind::CompositeKeybind(m)) => {
- let mut cmd = None;
let mut map: &JoshutoCommandMapping = &m;
- loop {
- let event2 = {
- let mut menu = OptionMenu::new(&mut backend, &context.events);
+ let cmd = {
+ let mut menu = TuiCommandMenu::new();
+ menu.get_input(&mut backend, &context, map)
+ };
- // TODO: format keys better, rather than debug
- let mut display_vec: Vec<String> = map
- .iter()
- .map(|(k, v)| format!(" {:?}\t{}", k, v))
- .collect();
- display_vec.sort();
- let display_str: Vec<&str> =
- display_vec.iter().map(|v| v.as_str()).collect();
- let result = menu.get_option(&display_str);
- result
- };
-
- match event2 {
- None => break,
- Some(key) => match key {
- Key::Char(_) => match map.get(&key) {
- Some(CommandKeybind::CompositeKeybind(m)) => map = &m,
- Some(CommandKeybind::SimpleKeybind(s)) => {
- cmd = Some(s.as_ref());
- break;
- }
- None => break,
- },
- _ => {}
- },
- }
- }
if let Some(command) = cmd {
if let Err(e) = command.execute(&mut context, &mut backend) {
eprintln!("{}", e.cause());
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
index 74f080d..844a70c 100644
--- a/src/ui/mod.rs
+++ b/src/ui/mod.rs
@@ -1,4 +1,18 @@
+use tui::layout::Constraint;
+
mod tui_backend;
pub mod widgets;
pub use tui_backend::*;
+
+pub const DEFAULT_LAYOUT: [tui::layout::Constraint; 3] = [
+ Constraint::Ratio(1, 8),
+ Constraint::Ratio(3, 8),
+ Constraint::Ratio(4, 8),
+];
+
+pub const NO_PREVIEW_LAYOUT: [tui::layout::Constraint; 3] = [
+ Constraint::Ratio(1, 8),
+ Constraint::Ratio(7, 8),
+ Constraint::Ratio(0, 8),
+];
diff --git a/src/ui/tui_backend.rs b/src/ui/tui_backend.rs
index 583f501..4c64497 100644
--- a/src/ui/tui_backend.rs
+++ b/src/ui/tui_backend.rs
@@ -8,13 +8,15 @@ use tui::layout::{Constraint, Direction, Layout, Rect};
use tui::widgets::Widget;
use unicode_width::UnicodeWidthStr;
-use super::widgets::{TuiDirList, TuiDirListDetailed, TuiTopBar};
+use super::widgets::{TuiDirList, TuiDirListDetailed, TuiFooter, TuiTopBar};
use crate::context::JoshutoContext;
pub struct TuiBackend {
pub terminal: tui::Terminal<TermionBackend<AlternateScreen<RawTerminal<std::io::Stdout>>>>,
}
+use super::{DEFAULT_LAYOUT, NO_PREVIEW_LAYOUT};
+
impl TuiBackend {
pub fn new() -> std::io::Result<Self> {
let stdout = std::io::stdout().into_raw_mode()?;
@@ -53,16 +55,8 @@ impl TuiBackend {
}
let constraints = match child_list {
- Some(_) => [
- Constraint::Ratio(1, 6),
- Constraint::Ratio(2, 6),
- Constraint::Ratio(3, 6),
- ],
- None => [
- Constraint::Ratio(1, 6),
- Constraint::Ratio(5, 6),
- Constraint::Ratio(0, 6),
- ],
+ Some(_) => DEFAULT_LAYOUT,
+ None => NO_PREVIEW_LAYOUT,
};
let layout_rect = Layout::default()
.direction(Direction::Horizontal)
@@ -76,6 +70,16 @@ impl TuiBackend {
if let Some(curr_list) = curr_list.as_ref() {
TuiDirListDetailed::new(&curr_list).render(&mut frame, layout_rect[1]);
+ if let Some(entry) = curr_list.get_curr_ref() {
+ let top_rect = Rect {
+ x: 0,
+ y: f_size.height - 1,
+ width: f_size.width,
+ height: 1,
+ };
+ TuiFooter::new(entry)
+ .render(&mut frame, top_rect);
+ }
};
if let Some(curr_list) = child_list.as_ref() {
diff --git a/src/ui/widgets/mod.rs b/src/ui/widgets/mod.rs
index e619450..d80d4ca 100644
--- a/src/ui/widgets/mod.rs
+++ b/src/ui/widgets/mod.rs
@@ -1,5 +1,11 @@
-pub mod tui_topbar;
pub mod tui_dirlist;
+pub mod tui_dirlist_detailed;
+pub mod tui_footer;
+pub mod tui_menu;
+pub mod tui_topbar;
-pub use self::tui_dirlist::{TuiDirList, TuiDirListDetailed};
+pub use self::tui_dirlist::TuiDirList;
+pub use self::tui_dirlist_detailed::TuiDirListDetailed;
+pub use self::tui_footer::TuiFooter;
+pub use self::tui_menu::TuiCommandMenu;
pub use self::tui_topbar::TuiTopBar;
diff --git a/src/ui/widgets/tui_dirlist.rs b/src/ui/widgets/tui_dirlist.rs
index 73425c4..77684c7 100644
--- a/src/ui/widgets/tui_dirlist.rs
+++ b/src/ui/widgets/tui_dirlist.rs
@@ -6,6 +6,7 @@ use unicode_width::UnicodeWidthStr;
use unicode_width::UnicodeWidthChar;
use crate::fs::JoshutoDirList;
+use crate::util::format;
pub struct TuiDirList<'a> {
dirlist: &'a JoshutoDirList,
@@ -56,123 +57,42 @@ impl<'a> Widget for TuiDirList<'a> {
.take(area.height as usize)
{
let name = entry.file_name();
- let mut style = entry.get_style();
-
- if i == screen_index {
- style = style.modifier(Modifier::REVERSED);
- }
let name_width = name.width();
- if name_width < area_width {
- buf.set_stringn(x, y + i as u16,
- name,
- area_width, style);
- } else {
- match name.rfind('.') {
- None => {
- buf.set_stringn(x, y + i as u16,
- name,
- area_width, style);
- }
- Some(p_ind) => {
- let ext_width = name[p_ind..].width();
- let file_name_width = area_width - ext_width - 1;
-
- buf.set_stringn(x, y + i as u16,
- &name[..p_ind],
- file_name_width, style);
- buf.set_string(x + file_name_width as u16, y + i as u16,
- "…", style);
- buf.set_string(x + file_name_width as u16 + 1, y + i as u16,
- &name[p_ind..], style);
- }
- }
- }
- }
- }
-}
-
-const FILE_SIZE_WIDTH: usize = 8;
-
-pub struct TuiDirListDetailed<'a> {
- dirlist: &'a JoshutoDirList,
-}
-
-impl<'a> TuiDirListDetailed<'a> {
- pub fn new(dirlist: &'a JoshutoDirList) -> Self {
- Self { dirlist }
- }
-}
-
-impl<'a> Widget for TuiDirListDetailed<'a> {
- fn draw(&mut self, area: Rect, buf: &mut Buffer) {
- if area.width < 1 || area.height < 1 {
- return;
- }
-
- if area.width < 4 {
- return;
- }
-
- let x = area.left();
- let y = area.top();
-
- let dir_len = self.dirlist.contents.len();
- if dir_len == 0 {
- let style = Style::default()
- .bg(Color::Red)
- .fg(Color::White);
- buf.set_stringn(x, y, "empty", area.width as usize, style);
- return;
- }
-
- let curr_index = self.dirlist.index.unwrap();
- let skip_dist = curr_index / area.height as usize * area.height as usize;
- let screen_index = if skip_dist > 0 {
- curr_index % skip_dist
- } else {
- curr_index
- };
-
- let area_width = area.width as usize;
- for (i, entry) in self
- .dirlist
- .contents
- .iter()
- .skip(skip_dist)
- .enumerate()
- .take(area.height as usize)
- {
- let name = entry.file_name();
let mut style = entry.get_style();
-
if i == screen_index {
style = style.modifier(Modifier::REVERSED);
}
- let file_type = entry.metadata.file_type;
- let name_width = name.width();
+ let file_type = entry.metadata.file_type;
if file_type.is_dir() {
- buf.set_stringn(x, y + i as u16,
- name,
- area_width, style);
+ if name_width <= area_width {
+ buf.set_stringn(x, y + i as u16,
+ name,
+ area_width, style);
+ } else {
+ buf.set_stringn(x, y + i as u16,
+ name,
+ area_width - 1, style);
+ buf.set_string(x + area_width as u16 - 1, y + i as u16,
+ "…", style);
+ }
continue;
}
-
- if name_width < area_width - FILE_SIZE_WIDTH {
+ if name_width < area_width {
buf.set_stringn(x, y + i as u16,
name,
- area_width - FILE_SIZE_WIDTH, style);
+ area_width, style);
} else {
match name.rfind('.') {
None => {
buf.set_stringn(x, y + i as u16,
name,
- area_width - FILE_SIZE_WIDTH, style);
+ area_width, style);
}
Some(p_ind) => {
let ext_width = name[p_ind..].width();
- let file_name_width = area_width - FILE_SIZE_WIDTH - ext_width - 1;
+ let file_name_width = area_width - ext_width - 1;
buf.set_stringn(x, y + i as u16,
&name[..p_ind],
@@ -184,28 +104,6 @@ impl<'a> Widget for TuiDirListDetailed<'a> {
}
}
}
- let file_size_string = file_size_to_string(entry.metadata.len as f64);
- buf.set_string(x + (area_width - FILE_SIZE_WIDTH) as u16, y + i as u16,
- file_size_string, style);
}
}
}
-
-fn file_size_to_string(mut file_size: f64) -> String {
- const FILE_UNITS: [&str; 6] = ["B", "K", "M", "G", "T", "E"];
- const CONV_RATE: f64 = 1024.0;
-
- let mut index = 0;
- while file_size > CONV_RATE {
- file_size /= CONV_RATE;
- index += 1;
- }
-
- if file_size >= 100.0 {
- format!("{:>4.0} {}", file_size, FILE_UNITS[index])
- } else if file_size >= 10.0 {
- format!("{:>4.1} {}", file_size, FILE_UNITS[index])
- } else {
- format!("{:>4.2} {}", file_size, FILE_UNITS[index])
- }
-}
diff --git a/src/ui/widgets/tui_dirlist_detailed.rs b/src/ui/widgets/tui_dirlist_detailed.rs
new file mode 100644
index 0000000..2e01a26
--- /dev/null
+++ b/src/ui/widgets/tui_dirlist_detailed.rs
@@ -0,0 +1,117 @@
+use tui::buffer::Buffer;
+use tui::layout::Rect;
+use tui::style::{Color, Modifier, Style};
+use tui::widgets::Widget;
+use unicode_width::UnicodeWidthStr;
+use unicode_width::UnicodeWidthChar;
+
+use crate::fs::JoshutoDirList;
+use crate::util::format;
+
+const FILE_SIZE_WIDTH: usize = 8;
+
+pub struct TuiDirListDetailed<'a> {
+ dirlist: &'a JoshutoDirList,
+}
+
+impl<'a> TuiDirListDetailed<'a> {
+ pub fn new(dirlist: &'a JoshutoDirList) -> Self {
+ Self { dirlist }
+ }
+}
+
+impl<'a> Widget for TuiDirListDetailed<'a> {
+ fn draw(&mut self, area: Rect, buf: &mut Buffer) {
+ if area.width < 1 || area.height < 1 {
+ return;
+ }
+
+ if area.width < 4 {
+ return;
+ }
+
+ let x = area.left();
+ let y = area.top();
+
+ let dir_len = self.dirlist.contents.len();
+ if dir_len == 0 {
+ let style = Style::default()
+ .bg(Color::Red)
+ .fg(Color::White);
+ buf.set_stringn(x, y, "empty", area.width as usize, style);
+ return;
+ }
+
+ let curr_index = self.dirlist.index.unwrap();
+ let skip_dist = curr_index / area.height as usize * area.height as usize;
+
+ let screen_index = if skip_dist > 0 {
+ curr_index % skip_dist
+ } else {
+ curr_index
+ };
+
+ let area_width = area.width as usize;
+ for (i, entry) in self
+ .dirlist
+ .contents
+ .iter()
+ .skip(skip_dist)
+ .enumerate()
+ .take(area.height as usize)
+ {
+ let name = entry.file_name();
+ let name_width = name.width();
+
+ let mut style = entry.get_style();
+ if i == screen_index {
+ style = style.modifier(Modifier::REVERSED);
+ }
+
+ let file_type = entry.metadata.file_type;
+ if file_type.is_dir() {
+ if name_width <= area_width {
+ buf.set_stringn(x, y + i as u16,
+ name,
+ area_width, style);
+ } else {
+ buf.set_stringn(x, y + i as u16,
+ name,
+ area_width - 1, style);
+ buf.set_string(x + area_width as u16 - 1, y + i as u16,
+ "…", style);
+ }
+ continue;
+ }
+
+ if name_width < area_width - FILE_SIZE_WIDTH {
+ buf.set_stringn(x, y + i as u16,
+ name,
+ area_width - FILE_SIZE_WIDTH, style);
+ } else {
+ match name.rfind('.') {
+ None => {
+ buf.set_stringn(x, y + i as u16,
+ name,
+ area_width - FILE_SIZE_WIDTH, style);
+ }
+ Some(p_ind) => {
+ let ext_width = name[p_ind..].width();
+ let file_name_width = area_width - FILE_SIZE_WIDTH - ext_width - 2;
+
+ buf.set_stringn(x, y + i as u16,
+ &name[..p_ind],
+ file_name_width, style);
+ buf.set_string(x + file_name_width as u16, y + i as u16,
+ "…", style);
+ buf.set_string(x + file_name_width as u16 + 1, y + i as u16,
+ &name[p_ind..], style);
+ }
+ }
+ }
+ let file_size_string = format::file_size_to_string(entry.metadata.len as f64);
+ buf.set_string(x + (area_width - FILE_SIZE_WIDTH) as u16, y + i as u16,
+ file_size_string, style);
+ }
+ }
+}
diff --git a/src/ui/widgets/tui_footer.rs b/src/ui/widgets/tui_footer.rs
new file mode 100644
index 0000000..ac34b98
--- /dev/null
+++ b/src/ui/widgets/tui_footer.rs
@@ -0,0 +1,61 @@
+use std::fs;
+use std::path::Path;
+
+use tui::buffer::Buffer;
+use tui::layout::Rect;
+use tui::style::{Color, Modifier, Style};
+use tui::widgets::{Paragraph, Text, Widget};
+
+use crate::fs::JoshutoDirEntry;
+use crate::util::format;
+
+use crate::{HOSTNAME, USERNAME};
+
+pub struct TuiFooter<'a> {
+ entry: &'a JoshutoDirEntry,
+}
+
+impl<'a> TuiFooter<'a> {
+ pub fn new(entry: &'a JoshutoDirEntry) -> Self {
+ Self { entry }
+ }
+}
+
+impl<'a> Widget for TuiFooter<'a> {
+ fn draw(&mut self, area: Rect, buf: &mut Buffer) {
+ use std::os::unix::fs::PermissionsExt;
+
+ let mode = self.entry.metadata.permissions.mode();
+ let mode = format::mode_to_string(mode);
+
+ let mode_style = Style::default()
+ .fg(Color::Cyan);
+
+ let mtime = self.entry.metadata.modified;
+ let mtime = format::mtime_to_string(mtime);
+
+ let size = self.entry.metadata.len;
+ let size = format::file_size_to_string(size as f64);
+
+ let mut text = vec![
+ Text::styled(mode, mode_style),
+ Text::raw(" "),
+ Text::raw(mtime),
+ Text::raw(" "),
+ Text::raw(size),
+ ];
+
+ if self.entry.metadata.file_type.is_symlink() {
+ if let Ok(path) = fs::read_link(self.entry.file_path()) {
+ text.push(Text::styled(" -> ", mode_style));
+ if let Some(s) = path.to_str() {
+ text.push(Text::styled(s.to_string(), mode_style));
+ }
+ }
+ }
+
+ Paragraph::new(text.iter())
+ .wrap(true)
+ .draw(area, buf);
+ }
+}
diff --git a/src/ui/widgets/tui_menu.rs b/src/ui/widgets/tui_menu.rs
new file mode 100644
index 0000000..64100f4
--- /dev/null
+++ b/src/ui/widgets/tui_menu.rs
@@ -0,0 +1,162 @@
+use std::io::{self, Write};
+use std::iter::Iterator;
+
+use tui::buffer::Buffer;
+use termion::clear;
+use termion::cursor::Goto;
+use termion::event::Key;
+use termion::raw::IntoRawMode;
+use termion::screen::AlternateScreen;
+use tui::backend::TermionBackend;
+use tui::layout::{Constraint, Direction, Layout, Rect};
+use tui::style::{Color, Style};
+use tui::widgets::{Block, Borders, List, Paragraph, Text, Widget};
+use tui::Terminal;
+use unicode_width::UnicodeWidthStr;
+
+use crate::commands::{CommandKeybind, CursorMoveUp, JoshutoCommand, JoshutoRunnable};
+use crate::config::JoshutoCommandMapping;
+use crate::context::JoshutoContext;
+use crate::ui::TuiBackend;
+use crate::util::event::{Event, Events};
+use super::{TuiDirList, TuiDirListDetailed, TuiTopBar};
+
+use crate::{HOSTNAME, USERNAME};
+use super::super::{DEFAULT_LAYOUT, NO_PREVIEW_LAYOUT};
+
+const BORDER_HEIGHT: usize = 1;
+const BOTTOM_MARGIN: usize = 1;
+
+pub struct TuiCommandMenu;
+
+impl TuiCommandMenu {
+ pub fn new() -> Self {
+ Self {}
+ }
+
+ pub fn get_input<'a>(&mut self, backend: &mut TuiBackend,
+ context: &JoshutoContext, m: &'a JoshutoCommandMapping) ->
+ Option<&'a Box<JoshutoCommand>> {
+ let mut map: &JoshutoCommandMapping = &m;
+ let events = &context.events;
+
+ let curr_tab = context.curr_tab_ref();
+
+ let curr_list = curr_tab.curr_list_ref();
+ let parent_list = curr_tab.parent_list_ref();
+ let child_list = curr_tab.child_list_ref();
+
+ loop {
+ backend.terminal.draw(|mut frame| {
+ let f_size = frame.size();
+
+ {
+ let top_rect = Rect {
+ x: 0,
+ y: 0,
+ width: f_size.width,
+ height: 1,
+ };
+
+ TuiTopBar::new(curr_tab.curr_path.as_path())
+ .render(&mut frame, top_rect);
+ }
+
+ let constraints = match child_list {
+ Some(_) => DEFAULT_LAYOUT,
+ None => NO_PREVIEW_LAYOUT,
+ };
+ let layout_rect = Layout::default()
+ .direction(Direction::Horizontal)
+ .margin(1)
+ .constraints(constraints.as_ref())
+ .split(f_size);
+
+ if let Some(curr_list) = parent_list.as_ref() {
+ TuiDirList::new(&curr_list).render(&mut frame, layout_rect[0]);
+ };
+
+ if let Some(curr_list) = curr_list.as_ref() {
+ TuiDirListDetailed::new(&curr_list).render(&mut frame, layout_rect[1]);
+ };
+
+ if let Some(curr_list) = child_list.as_ref() {
+ TuiDirList::new(&curr_list).render(&mut frame, layout_rect[2]);
+ };
+
+ {
+ // draw menu
+ let mut display_vec: Vec<String> = map
+ .iter()
+ .map(|(k, v)| {
+ format!(" {:?} {}", k, v)
+ })
+ .collect();
+ display_vec.sort();
+ let display_str: Vec<&str> =
+ display_vec.iter().map(|v| v.as_str()).collect();
+
+ let display_str_len = display_str.len();
+
+ let y = if (f_size.height as usize) < display_str_len + BORDER_HEIGHT + BOTTOM_MARGIN {
+ 0
+ } else {
+ f_size.height - (BORDER_HEIGHT + BOTTOM_MARGIN) as u16
+ - display_str_len as u16
+ };
+
+ let menu_rect = Rect {
+ x: 0,
+ y: y,
+ width: f_size.width,
+ height: (display_str_len + BORDER_HEIGHT) as u16,
+ };
+
+ TuiMenu::new(&display_str).render(&mut frame, menu_rect);
+ }
+ });
+ if let Ok(event) = events.next() {
+ match event {
+ Event::Input(Key::Esc) => {
+ return None;
+ }
+ Event::Input(key) => {
+ match map.get(&key) {
+ Some(CommandKeybind::SimpleKeybind(s)) => {
+ return Some(s);
+ }
+ Some(CommandKeybind::CompositeKeybind(m)) => {
+ map = m;
+ }
+ None => return None,
+ }
+ }
+ _ => {},
+ }
+ }
+ }
+
+ }
+}
+
+pub struct TuiMenu<'a> {
+ options: &'a Vec<&'a str>,
+}
+
+impl<'a> TuiMenu<'a> {
+ pub fn new(options: &'a Vec<&str>) -> Self {
+ Self { options }
+ }
+}
+
+impl<'a> Widget for TuiMenu<'a> {
+ fn draw(&mut self, area: Rect, buf: &mut Buffer) {
+ let text_iter = self.options.iter().map(|s| Text::raw(*s));
+ let block = Block::default()
+ .borders(Borders::TOP);
+
+ List::new(text_iter)
+ .block(block)
+ .draw(area, buf);
+ }
+}
diff --git a/src/util/format.rs b/src/util/format.rs
new file mode 100644
index 0000000..144aaaf
--- /dev/null
+++ b/src/util/format.rs
@@ -0,0 +1,33 @@
+use std::time;
+
+use crate::unix;
+
+pub fn file_size_to_string(mut file_size: f64) -> String {
+ const FILE_UNITS: [&str; 6] = ["B", "K", "M", "G", "T", "E"];
+ const CONV_RATE: f64 = 1024.0;
+
+ let mut index = 0;
+ while file_size > CONV_RATE {
+ file_size /= CONV_RATE;
+ index += 1;
+ }
+
+ if file_size >= 100.0 {
+ format!("{:>4.0} {}", file_size, FILE_UNITS[index])
+ } else if file_size >= 10.0 {
+ format!("{:>4.1} {}", file_size, FILE_UNITS[index])
+ } else {
+ format!("{:>4.2} {}", file_size, FILE_UNITS[index])
+ }
+}
+
+pub fn mode_to_string(mode: u32) -> String {
+ unix::stringify_mode(mode)
+}
+
+pub fn mtime_to_string(mtime: time::SystemTime) -> String {
+ const MTIME_FORMATTING: &str = "%Y-%m-%d %H:%M";
+
+ let datetime: chrono::DateTime<chrono::offset::Utc> = mtime.into();
+ datetime.format(MTIME_FORMATTING).to_string()
+}
diff --git a/src/util/menu.rs b/src/util/menu.rs
deleted file mode 100644
index d60c9a1..0000000
--- a/src/util/menu.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use std::io::{self, Write};
-use std::iter::Iterator;
-
-use termion::clear;
-use termion::cursor::Goto;
-use termion::event::Key;
-use termion::raw::IntoRawMode;
-use termion::screen::AlternateScreen;
-use tui::backend::TermionBackend;
-use tui::layout::{Constraint, Direction, Layout, Rect};
-use tui::style::{Color, Style};
-use tui::widgets::{Block, Borders, List, Paragraph, Text, Widget};
-use tui::Terminal;
-use unicode_width::UnicodeWidthStr;
-
-use crate::context::JoshutoContext;
-use crate::ui::TuiBackend;
-use crate::util::event::{Event, Events};
-
-pub struct OptionMenu<'a> {
- backend: &'a mut TuiBackend,
- events: &'a Events,
-}
-
-impl<'a> OptionMenu<'a> {
- pub fn new(backend: &'a mut TuiBackend, events: &'a Events) -> Self {
- Self { backend, events }
- }
-
- pub fn render(&mut self, context: &JoshutoContext) {
-
- }
-
- pub fn get_option(&mut self, options: &[&str]) -> Option<Key> {
- let events = self.events;
-
- // initially, clear the line for textfield and move the cursor there as well
- let f_size = {
- let frame = self.backend.terminal.get_frame();
- frame.size()
- };
- let txt_y = if f_size.height < options.len() as u16 {
- 0
- } else {
- f_size.height - options.len() as u16
- };
-
- let termion_terminal = self.backend.terminal.backend_mut();
-
- write!(termion_terminal, "{}", Goto(1, txt_y));
- for (i, option) in options.iter().enumerate() {
- write!(
- termion_terminal,
- "{}{}{}",
- option,
- Goto(1, txt_y + i as u16),
- clear::AfterCursor
- );
- }
- io::stdout().flush().ok();
-
- loop {
- let event = events.next();
- if let Ok(event) = event {
- match event {
- Event::Input(input) => match input {
- Key::Esc => return None,
- key => return Some(key),
- },
- _ => {}
- }
- }
- }
- }
-}
diff --git a/src/util/mod.rs b/src/util/mod.rs
index 34b8eb4..9519706 100644
--- a/src/util/mod.rs
+++ b/src/util/mod.rs
@@ -1,5 +1,5 @@
pub mod event;
+pub mod format;
pub mod key_mapping;
pub mod load_child;
-pub mod menu;
pub mod textfield;