what the hell
This commit is contained in:
commit
b34f32310c
5 files changed
+1380
No files matched your search
@@ -0,0 +1 @@
|
||||
/target
|
||||
Generated
+1058
File diff suppressed because it is too large.
Load diff
+11
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "lda-thp"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
publish = ["gitea"]
|
||||
|
||||
[dependencies]
|
||||
color-eyre = "0.6.5"
|
||||
crossterm = "0.29.0"
|
||||
ratatui = { version = "0.29.0", features = ["all-widgets", "macros"] }
|
||||
ratatui-explorer = "0.2.1"
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
use crossterm::event::{self, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent};
|
||||
use ratatui::crossterm;
|
||||
use ratatui::crossterm::event::Event;
|
||||
use ratatui::widgets::Clear;
|
||||
use ratatui::{
|
||||
Frame, Terminal,
|
||||
layout::{Constraint, Layout, Spacing},
|
||||
prelude::Backend,
|
||||
style::{Style, Stylize},
|
||||
text::{Line, Span, Text},
|
||||
widgets::{Block, BorderType, Padding, Paragraph},
|
||||
};
|
||||
use ratatui_explorer::{FileExplorer, Input};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
fs::{File, read_to_string},
|
||||
io::{self, Read},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
pub struct DocCache {
|
||||
doc: PathBuf,
|
||||
cache: String,
|
||||
offset: (u16, u16),
|
||||
}
|
||||
impl Debug for DocCache {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("DocCache")
|
||||
.field("doc", &self.doc)
|
||||
.field("cache", &format!("{:.20}", &self.cache))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
enum AppState {
|
||||
#[default]
|
||||
Main,
|
||||
Quit,
|
||||
DocSwitcher,
|
||||
FileError, // file open error. file read error. whatever error.
|
||||
}
|
||||
/// model
|
||||
#[derive(Debug, Default)]
|
||||
pub struct App<'a> {
|
||||
doc: Option<DocCache>,
|
||||
state: AppState,
|
||||
explorer: Option<&'a mut FileExplorer>,
|
||||
}
|
||||
|
||||
impl<'a> App<'a> {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
pub fn with_doc(self, doc: impl Into<PathBuf>) -> io::Result<Self> {
|
||||
let doc = Some(DocCache::new(doc)?);
|
||||
Ok(Self { doc, ..self })
|
||||
}
|
||||
pub fn with_explorer(self, explorer: &'a mut FileExplorer) -> Self {
|
||||
explorer.set_theme(
|
||||
explorer
|
||||
.theme()
|
||||
.clone()
|
||||
.with_title_bottom(|_| Line::from("press enter to select ig idk")),
|
||||
);
|
||||
Self {
|
||||
explorer: Some(explorer),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
||||
enum Message {
|
||||
#[default]
|
||||
Main,
|
||||
Quit,
|
||||
ReloadDoc,
|
||||
OpenDocSwitcher,
|
||||
CloseDocSwitcher,
|
||||
}
|
||||
impl App<'_> {
|
||||
pub fn run<B: Backend>(&mut self, term: &mut Terminal<B>) -> io::Result<()> {
|
||||
while self.state != AppState::Quit {
|
||||
term.draw(|frame| self.view(frame))?;
|
||||
let mut event = self.event()?;
|
||||
while let Some(ev) = event {
|
||||
event = self.update(ev);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn view(&self, frame: &mut Frame) {
|
||||
let [header, main] = Layout::vertical([Constraint::Length(3), Constraint::Min(2)])
|
||||
.split(frame.area())[..]
|
||||
.try_into()
|
||||
.expect("Layout::split / Rc problem");
|
||||
let header_box = Block::bordered()
|
||||
.border_type(BorderType::Rounded)
|
||||
.padding(Padding::horizontal(1));
|
||||
let [lda, space] = Layout::horizontal([Constraint::Length(3), Constraint::Min(0)])
|
||||
.spacing(Spacing::Space(1))
|
||||
.split(header_box.inner(header))[..]
|
||||
.try_into()
|
||||
.expect("Layout::split / Rc problem");
|
||||
|
||||
let lda_text =
|
||||
Span::from("lda").style(Style::new().fg(ratatui::style::Color::Indexed(202)));
|
||||
frame.render_widget(lda_text, lda);
|
||||
let content_block = Block::bordered().title(Line::from(" file content ").left_aligned());
|
||||
|
||||
let mut file_name = Text::default().blue().centered();
|
||||
let content;
|
||||
//wtf
|
||||
if let Some(doc) = &self.doc {
|
||||
file_name.push_span(doc.doc.display().to_string());
|
||||
content = Paragraph::new(doc.cache.as_str())
|
||||
.scroll(doc.offset)
|
||||
.block(content_block);
|
||||
} else {
|
||||
file_name.push_span("no file");
|
||||
content = Paragraph::new("no idea").block(content_block)
|
||||
}
|
||||
frame.render_widget(file_name, space);
|
||||
frame.render_widget(header_box, header);
|
||||
frame.render_widget(content, main);
|
||||
|
||||
let bij = Layout::horizontal([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Max(120),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.split(frame.area())[1];
|
||||
let real = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Max(30),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.split(bij)[1];
|
||||
|
||||
if self.state == AppState::DocSwitcher {
|
||||
frame.render_widget(Clear, real);
|
||||
let Some(ref exp) = self.explorer else {
|
||||
let widget = Paragraph::new("you dont have shit on buh what fuck")
|
||||
.block(Block::bordered().title("shit cuh"));
|
||||
frame.render_widget(widget, real);
|
||||
return;
|
||||
};
|
||||
frame.render_widget_ref(exp.widget(), real);
|
||||
}
|
||||
if self.state == AppState::FileError {
|
||||
frame.render_widget(Clear, real);
|
||||
frame.render_widget(
|
||||
Paragraph::new("file error bihfhahf (if you select with the thing how could it be file error i wonder")
|
||||
.centered()
|
||||
.block(Block::bordered().padding(Padding::proportional(5))),
|
||||
real,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message) -> Option<Message> {
|
||||
match message {
|
||||
Message::Main => {
|
||||
// tf do here
|
||||
// good. reset
|
||||
self.state = AppState::Main;
|
||||
return None;
|
||||
}
|
||||
Message::Quit => {
|
||||
self.state = AppState::Quit;
|
||||
}
|
||||
Message::ReloadDoc => {
|
||||
let Some(doc) = &mut self.doc else {
|
||||
return Some(Message::Main);
|
||||
};
|
||||
match doc.reload_doc() {
|
||||
Ok(_) => return Some(Message::Main),
|
||||
Err(_e) => self.state = AppState::FileError,
|
||||
};
|
||||
}
|
||||
Message::OpenDocSwitcher => self.state = AppState::DocSwitcher,
|
||||
Message::CloseDocSwitcher => {
|
||||
let Some(ref mut expl) = self.explorer else {
|
||||
// no way bro doesnt have this and then close doc
|
||||
unreachable!()
|
||||
};
|
||||
if let Some(file_name) = {
|
||||
let maybe = expl.current();
|
||||
(maybe.is_file()).then(|| maybe.path())
|
||||
} {
|
||||
if let Some(ref mut doc) = self.doc {
|
||||
// get cur file if
|
||||
{
|
||||
if file_name != &doc.doc {
|
||||
doc.doc.clear();
|
||||
doc.doc.push(file_name);
|
||||
return Some(Message::ReloadDoc); // ohoho i can do this
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match DocCache::new(file_name.clone()) {
|
||||
Ok(f) => {
|
||||
self.doc = Some(f);
|
||||
return Some(Message::Main);
|
||||
}
|
||||
Err(_e) => self.state = AppState::FileError,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
fn event(&mut self) -> io::Result<Option<Message>> {
|
||||
let ev = ratatui::crossterm::event::read()?;
|
||||
if self.state == AppState::DocSwitcher {
|
||||
if let Some(ref mut exp) = self.explorer {
|
||||
if matches!(
|
||||
ev,
|
||||
Event::Key(
|
||||
KeyEvent {
|
||||
code,..
|
||||
}
|
||||
) if code == KeyCode::Char('q') || code == KeyCode::Esc
|
||||
) {
|
||||
return Ok(Some(Message::Main));
|
||||
}
|
||||
|
||||
if matches!(
|
||||
ev,
|
||||
event::Event::Key(KeyEvent {
|
||||
code: KeyCode::Enter,
|
||||
..
|
||||
})
|
||||
) && exp.current().is_file()
|
||||
{
|
||||
return Ok(Some(Message::CloseDocSwitcher));
|
||||
};
|
||||
|
||||
exp.handle(Input::from(&ev))?;
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
match ev {
|
||||
event::Event::Key(KeyEvent {
|
||||
code,
|
||||
modifiers,
|
||||
kind,
|
||||
state: _,
|
||||
}) => {
|
||||
if kind == KeyEventKind::Release {
|
||||
return Ok(None);
|
||||
}
|
||||
if code == KeyCode::Char('q') || code == KeyCode::Esc {
|
||||
return Ok(Some(Message::Quit));
|
||||
} else if code == KeyCode::Char('r') && modifiers.contains(KeyModifiers::CONTROL) {
|
||||
return Ok(Some(Message::ReloadDoc));
|
||||
} else if code == KeyCode::Enter {
|
||||
return Ok(Some(Message::OpenDocSwitcher));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
event::Event::Mouse(MouseEvent {
|
||||
kind: _,
|
||||
column: _,
|
||||
row: _,
|
||||
modifiers: _,
|
||||
}) => Ok(None),
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DocCache {
|
||||
pub fn new(doc: impl Into<PathBuf>) -> io::Result<Self> {
|
||||
let doc = doc.into();
|
||||
let cache = read_to_string(&doc)?;
|
||||
Ok(Self {
|
||||
doc,
|
||||
cache,
|
||||
offset: (0, 0),
|
||||
})
|
||||
}
|
||||
fn reload_doc(&mut self) -> io::Result<()> {
|
||||
self.cache.clear();
|
||||
File::open(&self.doc)?.read_to_string(&mut self.cache)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
//! im going to fucking ELM
|
||||
//! ima view event update
|
||||
|
||||
use ratatui_explorer::FileExplorer;
|
||||
|
||||
|
||||
mod app;
|
||||
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
let mut r = ratatui::init();
|
||||
let mut exp = FileExplorer::new()?;
|
||||
app::App::new()
|
||||
.with_doc("src/main.rs")?
|
||||
.with_explorer(&mut exp)
|
||||
.run(&mut r)?;
|
||||
ratatui::restore();
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user