elm nightmare
This commit is contained in:
1 parent
b34f32310c
commit
c165b3fa94
3 files changed
+337
-127
No files matched your search
+304
-127
@@ -1,6 +1,6 @@
|
|||||||
|
use crossterm::event::Event;
|
||||||
use crossterm::event::{self, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent};
|
use crossterm::event::{self, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent};
|
||||||
use ratatui::crossterm;
|
use ratatui::text::{ToLine, ToSpan};
|
||||||
use ratatui::crossterm::event::Event;
|
|
||||||
use ratatui::widgets::Clear;
|
use ratatui::widgets::Clear;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
Frame, Terminal,
|
Frame, Terminal,
|
||||||
@@ -11,24 +11,36 @@ use ratatui::{
|
|||||||
widgets::{Block, BorderType, Padding, Paragraph},
|
widgets::{Block, BorderType, Padding, Paragraph},
|
||||||
};
|
};
|
||||||
use ratatui_explorer::{FileExplorer, Input};
|
use ratatui_explorer::{FileExplorer, Input};
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
use std::path::Path;
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
fs::{File, read_to_string},
|
fs::File,
|
||||||
io::{self, Read},
|
io::{self},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct DocCache {
|
pub struct DocCache {
|
||||||
doc: PathBuf,
|
content: String,
|
||||||
cache: String,
|
|
||||||
offset: (u16, u16),
|
offset: (u16, u16),
|
||||||
|
length_hint: u16,
|
||||||
}
|
}
|
||||||
impl Debug for DocCache {
|
pub struct Doc {
|
||||||
|
doc: PathBuf,
|
||||||
|
cache: Option<DocCache>,
|
||||||
|
}
|
||||||
|
impl Debug for Doc {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("DocCache")
|
let mut c = f.debug_struct("DocCache");
|
||||||
.field("doc", &self.doc)
|
c.field("doc", &self.doc);
|
||||||
.field("cache", &format!("{:.20}", &self.cache))
|
|
||||||
.finish()
|
if let Some(ref con) = self.cache {
|
||||||
|
c.field("cache", &format!("Some({:.20})", &con.content));
|
||||||
|
} else {
|
||||||
|
c.field("cache", &"None");
|
||||||
|
}
|
||||||
|
|
||||||
|
c.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
@@ -38,11 +50,12 @@ enum AppState {
|
|||||||
Quit,
|
Quit,
|
||||||
DocSwitcher,
|
DocSwitcher,
|
||||||
FileError, // file open error. file read error. whatever error.
|
FileError, // file open error. file read error. whatever error.
|
||||||
|
// up, right.
|
||||||
}
|
}
|
||||||
/// model
|
/// model
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct App<'a> {
|
pub struct App<'a> {
|
||||||
doc: Option<DocCache>,
|
doc: Option<Doc>,
|
||||||
state: AppState,
|
state: AppState,
|
||||||
explorer: Option<&'a mut FileExplorer>,
|
explorer: Option<&'a mut FileExplorer>,
|
||||||
}
|
}
|
||||||
@@ -51,16 +64,29 @@ impl<'a> App<'a> {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
pub fn with_doc(self, doc: impl Into<PathBuf>) -> io::Result<Self> {
|
pub fn with_doc(self, doc: impl AsRef<Path>) -> io::Result<Self> {
|
||||||
let doc = Some(DocCache::new(doc)?);
|
let mut doc = Doc::new(doc);
|
||||||
Ok(Self { doc, ..self })
|
doc.reload_doc()?;
|
||||||
|
Ok(Self {
|
||||||
|
doc: Some(doc),
|
||||||
|
..self
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn with_explorer(self, explorer: &'a mut FileExplorer) -> Self {
|
pub fn with_explorer(self, explorer: &'a mut FileExplorer) -> Self {
|
||||||
explorer.set_theme(
|
explorer.set_theme(
|
||||||
explorer
|
explorer
|
||||||
.theme()
|
.theme()
|
||||||
.clone()
|
.clone()
|
||||||
.with_title_bottom(|_| Line::from("press enter to select ig idk")),
|
.with_title_bottom(|_| Line::from("press Space to select ig idk"))
|
||||||
|
.with_title_top(|exp| {
|
||||||
|
let thing = exp.cwd().display().to_string();
|
||||||
|
Line::from_iter([
|
||||||
|
"cur dir: <".to_span().yellow(),
|
||||||
|
Span::from(thing).cyan(), // fuck is your probklem borrow checker
|
||||||
|
">".to_span().yellow(),
|
||||||
|
])
|
||||||
|
.centered()
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
Self {
|
Self {
|
||||||
explorer: Some(explorer),
|
explorer: Some(explorer),
|
||||||
@@ -76,7 +102,10 @@ enum Message {
|
|||||||
Quit,
|
Quit,
|
||||||
ReloadDoc,
|
ReloadDoc,
|
||||||
OpenDocSwitcher,
|
OpenDocSwitcher,
|
||||||
CloseDocSwitcher,
|
DocSwitcherAction(Input),
|
||||||
|
/// close doc switcher because there is a new file coming
|
||||||
|
NewDoc,
|
||||||
|
TextScroll(Option<bool>, Option<bool>),
|
||||||
}
|
}
|
||||||
impl App<'_> {
|
impl App<'_> {
|
||||||
pub fn run<B: Backend>(&mut self, term: &mut Terminal<B>) -> io::Result<()> {
|
pub fn run<B: Backend>(&mut self, term: &mut Terminal<B>) -> io::Result<()> {
|
||||||
@@ -90,8 +119,14 @@ impl App<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn view(&self, frame: &mut Frame) {
|
fn view(&self, frame: &mut Frame) {
|
||||||
let [header, main] = Layout::vertical([Constraint::Length(3), Constraint::Min(2)])
|
frame.render_widget(Clear, frame.area()); // tf this about
|
||||||
.split(frame.area())[..]
|
|
||||||
|
let [header, main, foot] = Layout::vertical([
|
||||||
|
Constraint::Length(3),
|
||||||
|
Constraint::Min(2),
|
||||||
|
Constraint::Length(1),
|
||||||
|
])
|
||||||
|
.split(frame.area())[..]
|
||||||
.try_into()
|
.try_into()
|
||||||
.expect("Layout::split / Rc problem");
|
.expect("Layout::split / Rc problem");
|
||||||
let header_box = Block::bordered()
|
let header_box = Block::bordered()
|
||||||
@@ -113,48 +148,67 @@ impl App<'_> {
|
|||||||
//wtf
|
//wtf
|
||||||
if let Some(doc) = &self.doc {
|
if let Some(doc) = &self.doc {
|
||||||
file_name.push_span(doc.doc.display().to_string());
|
file_name.push_span(doc.doc.display().to_string());
|
||||||
content = Paragraph::new(doc.cache.as_str())
|
if let Some(cache) = &doc.cache {
|
||||||
.scroll(doc.offset)
|
let text = Text::from(cache.content.as_str());
|
||||||
.block(content_block);
|
content = Paragraph::new(text).scroll(cache.offset);
|
||||||
|
} else {
|
||||||
|
content = Paragraph::new("errored buhhhhhh".to_line().centered())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
file_name.push_span("no file");
|
file_name.push_span("no file");
|
||||||
content = Paragraph::new("no idea").block(content_block)
|
content = Paragraph::new("no idea")
|
||||||
}
|
}
|
||||||
frame.render_widget(file_name, space);
|
let content = content.block(content_block);
|
||||||
frame.render_widget(header_box, header);
|
frame.render_widget(header_box, header);
|
||||||
frame.render_widget(content, main);
|
frame.render_widget(content, main);
|
||||||
|
frame.render_widget(
|
||||||
|
Line::from_iter([
|
||||||
|
Span::from("enter to choose file, "),
|
||||||
|
Span::from("esc or q to quit"),
|
||||||
|
]),
|
||||||
|
foot,
|
||||||
|
);
|
||||||
|
{
|
||||||
|
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];
|
||||||
|
|
||||||
let bij = Layout::horizontal([
|
if self.state == AppState::DocSwitcher {
|
||||||
Constraint::Fill(1),
|
frame.render_widget(file_name, space);
|
||||||
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);
|
||||||
frame.render_widget(Clear, real);
|
let Some(ref exp) = self.explorer else {
|
||||||
let Some(ref exp) = self.explorer else {
|
let widget = Paragraph::new("you dont have shit on buh what fuck")
|
||||||
let widget = Paragraph::new("you dont have shit on buh what fuck")
|
.block(Block::bordered().title("shit cuh"));
|
||||||
.block(Block::bordered().title("shit cuh"));
|
frame.render_widget(widget, real);
|
||||||
frame.render_widget(widget, real);
|
return;
|
||||||
return;
|
};
|
||||||
};
|
frame.render_widget_ref(exp.widget(), real);
|
||||||
frame.render_widget_ref(exp.widget(), real);
|
} else if self.state == AppState::FileError {
|
||||||
}
|
file_name.push_span(" (file errored)".red());
|
||||||
if self.state == AppState::FileError {
|
frame.render_widget(file_name, space);
|
||||||
frame.render_widget(Clear, real);
|
|
||||||
frame.render_widget(
|
frame.render_widget(Clear, real);
|
||||||
Paragraph::new("file error bihfhahf (if you select with the thing how could it be file error i wonder")
|
frame.render_widget(
|
||||||
|
Paragraph::new(
|
||||||
|
"file error bihfhahf (100% read error cant view esc choose another one",
|
||||||
|
)
|
||||||
.centered()
|
.centered()
|
||||||
.block(Block::bordered().padding(Padding::proportional(5))),
|
.block(Block::bordered().padding(Padding::proportional(5))),
|
||||||
real,
|
real,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
frame.render_widget(file_name, space);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,113 +233,236 @@ impl App<'_> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
Message::OpenDocSwitcher => self.state = AppState::DocSwitcher,
|
Message::OpenDocSwitcher => self.state = AppState::DocSwitcher,
|
||||||
Message::CloseDocSwitcher => {
|
Message::NewDoc => {
|
||||||
let Some(ref mut expl) = self.explorer else {
|
let Some(ref mut expl) = self.explorer else {
|
||||||
// no way bro doesnt have this and then close doc
|
// no way bro doesnt have this and then close doc
|
||||||
unreachable!()
|
unreachable!("wym new doc without an explorer")
|
||||||
};
|
};
|
||||||
if let Some(file_name) = {
|
if let Some(file_name) = {
|
||||||
let maybe = expl.current();
|
let maybe = expl.current();
|
||||||
(maybe.is_file()).then(|| maybe.path())
|
(maybe.is_file()).then(|| maybe.path())
|
||||||
} {
|
} {
|
||||||
if let Some(ref mut doc) = self.doc {
|
if self
|
||||||
// get cur file if
|
.doc
|
||||||
{
|
.as_ref()
|
||||||
if file_name != &doc.doc {
|
.filter(|doc| file_name == &doc.doc)
|
||||||
doc.doc.clear();
|
.is_none()
|
||||||
doc.doc.push(file_name);
|
{
|
||||||
return Some(Message::ReloadDoc); // ohoho i can do this
|
self.doc = Some(Doc::new(file_name));
|
||||||
|
return Some(Message::ReloadDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(Message::Main);
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::DocSwitcherAction(action) => {
|
||||||
|
let Some(ref mut exp) = self.explorer else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
if action == Input::Right {
|
||||||
|
if exp.current().is_file() {
|
||||||
|
return Some(Message::NewDoc);
|
||||||
|
} else if exp.current().file_type().is_some_and(|c| c.is_symlink()) {
|
||||||
|
match exp.current().path().read_link() {
|
||||||
|
Ok(path) => exp.set_cwd(path).expect("i swear path is real"),
|
||||||
|
Err(_not_real) => {
|
||||||
|
// is shortcut != is symlink
|
||||||
|
self.state = AppState::FileError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
match DocCache::new(file_name.clone()) {
|
|
||||||
Ok(f) => {
|
|
||||||
self.doc = Some(f);
|
|
||||||
return Some(Message::Main);
|
|
||||||
}
|
|
||||||
Err(_e) => self.state = AppState::FileError,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(_e) = exp.handle(action) {
|
||||||
|
// reading dir Fucked Up
|
||||||
|
self.state = AppState::FileError;
|
||||||
|
return None;
|
||||||
|
}; // noooo
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::TextScroll(up, right) => {
|
||||||
|
if let Some(ref mut doc) = self.doc {
|
||||||
|
if let Some(up) = up {
|
||||||
|
let bij = if up { -1 } else { 1 }; // fuck is this about
|
||||||
|
if let Some(ref mut cache) = doc.cache {
|
||||||
|
cache.offset.0 = cache.offset.0.saturating_add_signed(bij);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(right) = right {
|
||||||
|
let bij = if right { 1 } else { -1 };
|
||||||
|
if let Some(ref mut cache) = doc.cache {
|
||||||
|
cache.offset.1 = cache.offset.1.saturating_add_signed(bij);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(&mut self) -> io::Result<Option<Message>> {
|
fn event(&mut self) -> io::Result<Option<Message>> {
|
||||||
let ev = ratatui::crossterm::event::read()?;
|
|
||||||
if self.state == AppState::DocSwitcher {
|
if self.state == AppState::DocSwitcher {
|
||||||
if let Some(ref mut exp) = self.explorer {
|
use ratatui::crossterm::event; // 10/10 workaround
|
||||||
|
let ev = event::read()?;
|
||||||
|
{
|
||||||
if matches!(
|
if matches!(
|
||||||
ev,
|
ev,
|
||||||
Event::Key(
|
event::Event::Key(event::KeyEvent {
|
||||||
KeyEvent {
|
code: _c @ (event::KeyCode::Char('q') | event::KeyCode::Esc),
|
||||||
code,..
|
kind: _k @ (event::KeyEventKind::Press | event::KeyEventKind::Repeat),
|
||||||
}
|
..
|
||||||
) if code == KeyCode::Char('q') || code == KeyCode::Esc
|
})
|
||||||
) {
|
) {
|
||||||
return Ok(Some(Message::Main));
|
return Ok(Some(Message::Main));
|
||||||
}
|
}
|
||||||
|
let cip = Input::from(&ev);
|
||||||
|
Ok(Some(Message::DocSwitcherAction(cip)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let ev = crossterm::event::read()?;
|
||||||
|
match self.state {
|
||||||
|
AppState::DocSwitcher => unreachable!("jus handled that above"),
|
||||||
|
AppState::FileError => {
|
||||||
|
if matches!(
|
||||||
|
ev,
|
||||||
|
Event::Key(
|
||||||
|
KeyEvent {
|
||||||
|
code,..
|
||||||
|
}
|
||||||
|
) if code == KeyCode::Char('q') || code == KeyCode::Esc
|
||||||
|
) {
|
||||||
|
return Ok(Some(Message::OpenDocSwitcher));
|
||||||
|
}
|
||||||
|
|
||||||
if matches!(
|
Ok(None)
|
||||||
ev,
|
}
|
||||||
|
_ => match ev {
|
||||||
event::Event::Key(KeyEvent {
|
event::Event::Key(KeyEvent {
|
||||||
code: KeyCode::Enter,
|
code,
|
||||||
..
|
modifiers,
|
||||||
})
|
kind,
|
||||||
) && exp.current().is_file()
|
state: _,
|
||||||
{
|
}) => {
|
||||||
return Ok(Some(Message::CloseDocSwitcher));
|
if kind == KeyEventKind::Release {
|
||||||
};
|
return Ok(None);
|
||||||
|
}
|
||||||
exp.handle(Input::from(&ev))?;
|
if code == KeyCode::Char('q') || code == KeyCode::Esc {
|
||||||
return Ok(None);
|
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));
|
||||||
|
}
|
||||||
|
// no what is this code block
|
||||||
|
if self.doc.is_some() {
|
||||||
|
let updown = tri_state(
|
||||||
|
code.is_up() || code.is_char('k'),
|
||||||
|
code.is_down() || code.is_char('j'),
|
||||||
|
);
|
||||||
|
let leftright = tri_state(
|
||||||
|
code.is_right() || code.is_char('l'),
|
||||||
|
code.is_left() || code.is_char('h'),
|
||||||
|
);
|
||||||
|
return Ok(Some(Message::TextScroll(updown, leftright)));
|
||||||
|
};
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
event::Event::Mouse(MouseEvent {
|
||||||
|
kind,
|
||||||
|
column: _,
|
||||||
|
row: _,
|
||||||
|
modifiers,
|
||||||
|
}) => {
|
||||||
|
if self.doc.is_some() {
|
||||||
|
eprintln!("{modifiers}");
|
||||||
|
let updown = tri_state(
|
||||||
|
kind.is_scroll_up() && !modifiers.contains(KeyModifiers::SHIFT),
|
||||||
|
kind.is_scroll_down() && !modifiers.contains(KeyModifiers::SHIFT),
|
||||||
|
);
|
||||||
|
let leftright = tri_state(
|
||||||
|
kind.is_scroll_right()
|
||||||
|
|| (kind.is_scroll_down()
|
||||||
|
&& modifiers.contains(KeyModifiers::SHIFT)),
|
||||||
|
kind.is_scroll_left()
|
||||||
|
|| (kind.is_scroll_up()
|
||||||
|
&& modifiers.contains(KeyModifiers::SHIFT)),
|
||||||
|
);
|
||||||
|
return Ok(Some(Message::TextScroll(updown, leftright)));
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
_ => 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 {
|
impl Doc {
|
||||||
pub fn new(doc: impl Into<PathBuf>) -> io::Result<Self> {
|
pub fn new(doc: impl AsRef<Path>) -> Self {
|
||||||
let doc = doc.into();
|
let doc = doc.as_ref().to_path_buf();
|
||||||
let cache = read_to_string(&doc)?;
|
let cache = None;
|
||||||
Ok(Self {
|
// let length_hint = cache.lines().map(|_|1).sum();
|
||||||
doc,
|
Self { doc, cache }
|
||||||
cache,
|
|
||||||
offset: (0, 0),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
fn reload_doc(&mut self) -> io::Result<()> {
|
fn reload_doc(&mut self) -> io::Result<()> {
|
||||||
self.cache.clear();
|
if let Some(ref mut c) = self.cache {
|
||||||
File::open(&self.doc)?.read_to_string(&mut self.cache)?;
|
c.reload_doc(&self.doc).inspect_err(|_| {
|
||||||
|
self.cache = None;
|
||||||
|
})?;
|
||||||
|
} else {
|
||||||
|
// init the thing
|
||||||
|
self.cache = Some(DocCache::new(&self.doc)?);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl DocCache {
|
||||||
|
pub fn new(doc: impl AsRef<Path>) -> io::Result<Self> {
|
||||||
|
read_lines(&doc).map(|(l, content)| Self {
|
||||||
|
content,
|
||||||
|
offset: (0, 0),
|
||||||
|
length_hint: l as _,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn reload_doc(&mut self, doc: impl AsRef<Path>) -> io::Result<()> {
|
||||||
|
let a = read_lines(doc)?; // bail as early as possible
|
||||||
|
self.content.clear();
|
||||||
|
let lh;
|
||||||
|
(lh, self.content) = a;
|
||||||
|
self.length_hint = lh as _;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns some true if real, some false if fake, none if neither,
|
||||||
|
/// idk what happens if both
|
||||||
|
fn tri_state(real: bool, fake: bool) -> Option<bool> {
|
||||||
|
if real {
|
||||||
|
Some(true)
|
||||||
|
} else if fake {
|
||||||
|
Some(false)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this works for now
|
||||||
|
fn read_lines(doc: impl AsRef<Path>) -> io::Result<(usize, String)> {
|
||||||
|
let file = File::open(doc)?;
|
||||||
|
let lenf = file.metadata()?.len() as _;
|
||||||
|
let mut strg = String::with_capacity(lenf);
|
||||||
|
let mut fuek = BufReader::with_capacity(lenf, file);
|
||||||
|
let mut c = 0;
|
||||||
|
loop {
|
||||||
|
let r = fuek.read_line(&mut strg)?;
|
||||||
|
if r > 0 {
|
||||||
|
c += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((c, strg))
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
macro_rules! expr {
|
||||||
|
($($does:tt)*) => {
|
||||||
|
{$($does)*}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! defer_lda {
|
||||||
|
{$($does:tt)*} => {
|
||||||
|
let _realrealrealrealrealrealrealrealrealreal = $crate::defer::Defer(Some(|| expr!{$($does)*}));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub struct Defer<F: FnOnce ()>(pub Option<F>);
|
||||||
|
|
||||||
|
impl<F: FnOnce()> Drop for Defer<F> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.0.take().unwrap()();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let mut string = String::new();
|
||||||
|
{
|
||||||
|
defer_lda!{
|
||||||
|
string.push_str(" world"); // borrow checked
|
||||||
|
}
|
||||||
|
string.push_str("hello"); // why coudnt it just move the code to the end szjefhgsakjfghaskg``
|
||||||
|
}
|
||||||
|
assert_eq!(string, "hello world")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ use ratatui_explorer::FileExplorer;
|
|||||||
|
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
|
// mod defer;
|
||||||
|
|
||||||
fn main() -> color_eyre::Result<()> {
|
fn main() -> color_eyre::Result<()> {
|
||||||
color_eyre::install()?;
|
color_eyre::install()?;
|
||||||
|
|||||||
Reference in new issue
Block a user