yippie
This commit is contained in:
parent
636c02ce59
commit
c0c62ee964
2 changed files with 333 additions and 47 deletions
|
|
@ -1,61 +1,277 @@
|
||||||
use std::{env, fs, path};
|
use std::{
|
||||||
|
env::{self},
|
||||||
use crossterm::event::{self, Event, KeyCode};
|
fs, io,
|
||||||
use ratatui::{
|
path::PathBuf,
|
||||||
style::{Color, Style, Stylize},
|
|
||||||
widgets::{Block, Borders, List, ListState, Padding},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn list_dir(path: &str) -> Vec<String> {
|
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
||||||
let paths = fs::read_dir(path).unwrap();
|
use ratatui::{
|
||||||
let mut array_of_dirs: Vec<String> = Vec::new();
|
DefaultTerminal, Frame,
|
||||||
|
buffer::Buffer,
|
||||||
|
layout::{Constraint, Direction, Layout, Rect},
|
||||||
|
style::{Color, Stylize},
|
||||||
|
widgets::{Block, Borders, List, ListState, Padding, StatefulWidget},
|
||||||
|
};
|
||||||
|
|
||||||
for path in paths {
|
type E = std::io::Error;
|
||||||
array_of_dirs.push(path.unwrap().path().display().to_string());
|
|
||||||
|
struct App<'a> {
|
||||||
|
window: Window<'a>,
|
||||||
|
preview: Preview<'a>,
|
||||||
|
exit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
array_of_dirs
|
impl App<'_> {
|
||||||
|
fn run(&mut self, terminal: &mut DefaultTerminal) -> io::Result<()> {
|
||||||
|
while !self.exit {
|
||||||
|
terminal.draw(|frame| self.draw(frame))?;
|
||||||
|
self.handle_events()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_list<'a>(ls_result: Vec<String>) -> List<'a> {
|
fn draw(&mut self, frame: &mut Frame) {
|
||||||
|
let main_area = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints(vec![Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||||
|
.split(frame.area());
|
||||||
|
self.window.render(main_area[0], frame.buffer_mut());
|
||||||
|
self.preview.render(main_area[1], frame.buffer_mut());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_events(&mut self) -> io::Result<()> {
|
||||||
|
match event::read()? {
|
||||||
|
Event::Key(key_event) if key_event.kind == KeyEventKind::Press => {
|
||||||
|
self.handle_key_events(key_event)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_key_events(&mut self, key_event: KeyEvent) {
|
||||||
|
match key_event.code {
|
||||||
|
KeyCode::Char('q') | KeyCode::Esc => self.exit(),
|
||||||
|
KeyCode::Down => {
|
||||||
|
self.window.state.select_next();
|
||||||
|
self.preview.the_final_stretch();
|
||||||
|
}
|
||||||
|
KeyCode::Up => {
|
||||||
|
self.window.state.select_previous();
|
||||||
|
self.preview.the_final_stretch();
|
||||||
|
}
|
||||||
|
KeyCode::Left => {
|
||||||
|
if &self.window.absolute_path != "/" {
|
||||||
|
self.preview.absolute_path = self.window.absolute_path.clone();
|
||||||
|
}
|
||||||
|
self.window.absolute_path.pop();
|
||||||
|
self.window.update();
|
||||||
|
self.preview.state = self.window.state;
|
||||||
|
self.preview.muhehe();
|
||||||
|
}
|
||||||
|
KeyCode::Right => {
|
||||||
|
if let Some(val) = self.window.state.selected() {
|
||||||
|
let current_dir = self
|
||||||
|
.window
|
||||||
|
.prepare_updated_list()
|
||||||
|
.expect("You should always be in a valid directory");
|
||||||
|
|
||||||
|
self.window.absolute_path.push(current_dir[val].clone());
|
||||||
|
let output = self.window.update();
|
||||||
|
if !output {
|
||||||
|
self.window.absolute_path.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit(&mut self) {
|
||||||
|
self.exit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Window<'a> {
|
||||||
|
widget: WindowWidget<'a>,
|
||||||
|
absolute_path: PathBuf,
|
||||||
|
state: ListState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Window<'_> {
|
||||||
|
fn new(absolute_path: PathBuf) -> Result<Self, E> {
|
||||||
|
Ok(Window {
|
||||||
|
widget: WindowWidget::new(Self::prepare_list(&absolute_path)?),
|
||||||
|
absolute_path,
|
||||||
|
state: ListState::default().with_selected(Some(0)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, area: Rect, buf: &mut Buffer) {
|
||||||
|
self.widget.render(area, buf, &mut self.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_list(absolute_path: &PathBuf) -> Result<Vec<String>, E> {
|
||||||
|
let entries = fs::read_dir(absolute_path)?;
|
||||||
|
let mut prepared_list = Vec::<String>::new();
|
||||||
|
|
||||||
|
for item in entries {
|
||||||
|
match item {
|
||||||
|
Ok(entry) => {
|
||||||
|
let path_string = entry.path().display().to_string();
|
||||||
|
prepared_list.push(path_string);
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(prepared_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_updated_list(&self) -> Result<Vec<String>, E> {
|
||||||
|
Self::prepare_list(&self.absolute_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self) -> bool {
|
||||||
|
let values = self.prepare_updated_list();
|
||||||
|
|
||||||
|
if let Ok(val) = values {
|
||||||
|
self.widget.update(val);
|
||||||
|
self.state.select_first();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WindowWidget<'a> {
|
||||||
|
list: List<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowWidget<'_> {
|
||||||
|
fn update(&mut self, prepared_list: Vec<String>) {
|
||||||
let block = Block::new()
|
let block = Block::new()
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.padding(Padding::symmetric(1, 1))
|
.padding(Padding::symmetric(1, 1))
|
||||||
.fg(Color::Blue);
|
.fg(Color::Blue);
|
||||||
|
|
||||||
List::new(ls_result)
|
self.list = List::new(prepared_list)
|
||||||
.block(block)
|
.block(block)
|
||||||
.highlight_style(Style::new().reversed())
|
.highlight_style(Color::Cyan);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_events(state: ListState) {
|
fn new(prepared_list: Vec<String>) -> Self {
|
||||||
match event::read().expect("failed to read event") {
|
let mut window_widget = WindowWidget {
|
||||||
Event::Key(key_event) => match key_event.code {
|
list: List::new(Vec::<String>::new()),
|
||||||
KeyCode::Esc => {
|
};
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyCode::Down => {
|
window_widget.update(prepared_list);
|
||||||
state.select_next();
|
window_widget
|
||||||
}
|
|
||||||
|
|
||||||
KeyCode::Up => {
|
|
||||||
state.select_previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyCode::Left => (),
|
|
||||||
|
|
||||||
KeyCode::Right => (),
|
|
||||||
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
impl StatefulWidget for &mut WindowWidget<'_> {
|
||||||
let mut path = env::current_dir().unwrap();
|
type State = ListState;
|
||||||
|
|
||||||
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut ListState) {
|
||||||
|
StatefulWidget::render(&self.list, area, buf, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Preview<'a> {
|
||||||
|
widget: PreviewWidget<'a>,
|
||||||
|
absolute_path: PathBuf,
|
||||||
|
state: ListState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Preview<'_> {
|
||||||
|
fn the_final_stretch(&mut self) {
|
||||||
|
self.absolute_path.push(
|
||||||
|
Self::prepare_list(&self.absolute_path).unwrap()[self.state.selected().unwrap()]
|
||||||
|
.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.widget
|
||||||
|
.update(Self::prepare_list(&self.absolute_path).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn muhehe(&mut self) {
|
||||||
|
self.widget
|
||||||
|
.update(Self::prepare_list(&self.absolute_path).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_list(absolute_path: &PathBuf) -> Result<Vec<String>, E> {
|
||||||
|
let entries = fs::read_dir(absolute_path)?;
|
||||||
|
let mut prepared_list = Vec::<String>::new();
|
||||||
|
|
||||||
|
for item in entries {
|
||||||
|
match item {
|
||||||
|
Ok(entry) => {
|
||||||
|
let path_string = entry.path().display().to_string();
|
||||||
|
prepared_list.push(path_string);
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(prepared_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, area: Rect, buf: &mut Buffer) {
|
||||||
|
self.widget.render(area, buf, &mut ListState::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PreviewWidget<'a> {
|
||||||
|
list: List<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PreviewWidget<'_> {
|
||||||
|
fn update(&mut self, prepared_list: Vec<String>) {
|
||||||
|
let block = Block::new()
|
||||||
|
.borders(Borders::ALL)
|
||||||
|
.padding(Padding::symmetric(1, 1))
|
||||||
|
.fg(Color::Blue);
|
||||||
|
|
||||||
|
self.list = List::new(prepared_list)
|
||||||
|
.block(block)
|
||||||
|
.highlight_style(Color::Cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(prepared_list: Vec<String>) -> Self {
|
||||||
|
let mut preview_widget = PreviewWidget {
|
||||||
|
list: List::new(Vec::<String>::new()),
|
||||||
|
};
|
||||||
|
|
||||||
|
preview_widget.update(prepared_list);
|
||||||
|
preview_widget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StatefulWidget for &mut PreviewWidget<'_> {
|
||||||
|
type State = ListState;
|
||||||
|
|
||||||
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut ListState) {
|
||||||
|
StatefulWidget::render(&self.list, area, buf, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
let mut terminal = ratatui::init();
|
let mut terminal = ratatui::init();
|
||||||
let mut state = ListState::default();
|
let dir = Window::new(env::current_dir()?)?;
|
||||||
|
let view = env::current_dir()?;
|
||||||
|
let app_result = App {
|
||||||
|
window: dir,
|
||||||
|
preview: Preview {
|
||||||
|
widget: PreviewWidget::new(Preview::prepare_list(&view).unwrap()),
|
||||||
|
absolute_path: view,
|
||||||
|
state: ListState::default(),
|
||||||
|
},
|
||||||
|
exit: false,
|
||||||
|
}
|
||||||
|
.run(&mut terminal);
|
||||||
|
ratatui::restore();
|
||||||
|
app_result
|
||||||
}
|
}
|
||||||
|
|
|
||||||
78
src/main.rs
78
src/main.rs
|
|
@ -4,7 +4,7 @@ use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
DefaultTerminal, Frame,
|
DefaultTerminal, Frame,
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
layout::Rect,
|
layout::{Constraint, Direction, Layout, Rect},
|
||||||
style::{Color, Stylize},
|
style::{Color, Stylize},
|
||||||
widgets::{Block, Borders, List, ListState, Padding, StatefulWidget},
|
widgets::{Block, Borders, List, ListState, Padding, StatefulWidget},
|
||||||
};
|
};
|
||||||
|
|
@ -13,6 +13,7 @@ type E = std::io::Error;
|
||||||
|
|
||||||
struct App<'a> {
|
struct App<'a> {
|
||||||
window: Window<'a>,
|
window: Window<'a>,
|
||||||
|
preview: Preview<'a>,
|
||||||
exit: bool,
|
exit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,7 +27,12 @@ impl App<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self, frame: &mut Frame) {
|
fn draw(&mut self, frame: &mut Frame) {
|
||||||
self.window.render(frame.area(), frame.buffer_mut());
|
let main_area = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints(vec![Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||||
|
.split(frame.area());
|
||||||
|
self.window.render(main_area[0], frame.buffer_mut());
|
||||||
|
self.preview.render(main_area[1], frame.buffer_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_events(&mut self) -> io::Result<()> {
|
fn handle_events(&mut self) -> io::Result<()> {
|
||||||
|
|
@ -43,11 +49,18 @@ impl App<'_> {
|
||||||
fn handle_key_events(&mut self, key_event: KeyEvent) {
|
fn handle_key_events(&mut self, key_event: KeyEvent) {
|
||||||
match key_event.code {
|
match key_event.code {
|
||||||
KeyCode::Char('q') | KeyCode::Esc => self.exit(),
|
KeyCode::Char('q') | KeyCode::Esc => self.exit(),
|
||||||
KeyCode::Down => self.window.state.select_next(),
|
KeyCode::Down => {
|
||||||
KeyCode::Up => self.window.state.select_previous(),
|
self.window.state.select_next();
|
||||||
|
self.preview.see(&self.window);
|
||||||
|
}
|
||||||
|
KeyCode::Up => {
|
||||||
|
self.window.state.select_previous();
|
||||||
|
self.preview.see(&self.window);
|
||||||
|
}
|
||||||
KeyCode::Left => {
|
KeyCode::Left => {
|
||||||
self.window.absolute_path.pop();
|
self.window.absolute_path.pop();
|
||||||
self.window.update();
|
self.window.update();
|
||||||
|
self.preview.see(&self.window);
|
||||||
}
|
}
|
||||||
KeyCode::Right => {
|
KeyCode::Right => {
|
||||||
if let Some(val) = self.window.state.selected() {
|
if let Some(val) = self.window.state.selected() {
|
||||||
|
|
@ -61,6 +74,7 @@ impl App<'_> {
|
||||||
if !output {
|
if !output {
|
||||||
self.window.absolute_path.pop();
|
self.window.absolute_path.pop();
|
||||||
}
|
}
|
||||||
|
self.preview.see(&self.window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -159,11 +173,67 @@ impl StatefulWidget for &mut WindowWidget<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Preview<'a> {
|
||||||
|
widget: PreviewWidget<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Preview<'_> {
|
||||||
|
fn render(&mut self, area: Rect, buf: &mut Buffer) {
|
||||||
|
self.widget.render(area, buf, &mut ListState::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn see(&mut self, window: &Window) {
|
||||||
|
let a = Window::prepare_list(&window.absolute_path).unwrap();
|
||||||
|
|
||||||
|
self.widget.update(
|
||||||
|
Window::prepare_list(&PathBuf::from(a[window.state.selected().unwrap()].clone()))
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PreviewWidget<'a> {
|
||||||
|
list: List<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PreviewWidget<'_> {
|
||||||
|
fn update(&mut self, prepared_list: Vec<String>) {
|
||||||
|
let block = Block::new()
|
||||||
|
.borders(Borders::ALL)
|
||||||
|
.padding(Padding::symmetric(1, 1))
|
||||||
|
.fg(Color::Blue);
|
||||||
|
|
||||||
|
self.list = List::new(prepared_list)
|
||||||
|
.block(block)
|
||||||
|
.highlight_style(Color::Cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(prepared_list: Vec<String>) -> Self {
|
||||||
|
let mut preview_widget = PreviewWidget {
|
||||||
|
list: List::new(Vec::<String>::new()),
|
||||||
|
};
|
||||||
|
|
||||||
|
preview_widget.update(prepared_list);
|
||||||
|
preview_widget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StatefulWidget for &mut PreviewWidget<'_> {
|
||||||
|
type State = ListState;
|
||||||
|
|
||||||
|
fn render(self, area: Rect, buf: &mut Buffer, state: &mut ListState) {
|
||||||
|
StatefulWidget::render(&self.list, area, buf, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
fn main() -> io::Result<()> {
|
||||||
let mut terminal = ratatui::init();
|
let mut terminal = ratatui::init();
|
||||||
let dir = Window::new(env::current_dir()?)?;
|
let dir = Window::new(env::current_dir()?)?;
|
||||||
let app_result = App {
|
let app_result = App {
|
||||||
window: dir,
|
window: dir,
|
||||||
|
preview: Preview {
|
||||||
|
widget: PreviewWidget::new(Window::prepare_list(&env::current_dir().unwrap()).unwrap()),
|
||||||
|
},
|
||||||
exit: false,
|
exit: false,
|
||||||
}
|
}
|
||||||
.run(&mut terminal);
|
.run(&mut terminal);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue