5 warnings
This commit is contained in:
1 parent
c165b3fa94
commit
a4cafc0ef9
2 files changed
+238
-100
No files matched your search
+237
-99
@@ -1,29 +1,31 @@
|
|||||||
use crossterm::event::Event;
|
use crossterm::event::{
|
||||||
use crossterm::event::{self, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent};
|
self, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent, MouseEventKind,
|
||||||
use ratatui::text::{ToLine, ToSpan};
|
};
|
||||||
use ratatui::widgets::Clear;
|
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
Frame, Terminal,
|
Frame, Terminal,
|
||||||
layout::{Constraint, Layout, Spacing},
|
layout::{Constraint, Layout, Position, Rect, Size, Spacing},
|
||||||
prelude::Backend,
|
prelude::Backend,
|
||||||
style::{Style, Stylize},
|
style::{Style, Stylize},
|
||||||
text::{Line, Span, Text},
|
text::{Line, Span, Text, ToLine, ToSpan},
|
||||||
widgets::{Block, BorderType, Padding, Paragraph},
|
widgets::{Block, BorderType, Clear, Padding, Paragraph, Wrap},
|
||||||
};
|
};
|
||||||
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,
|
fs::File,
|
||||||
io::{self},
|
io::{self, BufRead, BufReader},
|
||||||
path::PathBuf,
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct DocCache {
|
pub struct DocCache {
|
||||||
content: String,
|
content: String,
|
||||||
|
/// height - width. up down first, left right second.
|
||||||
offset: (u16, u16),
|
offset: (u16, u16),
|
||||||
length_hint: u16,
|
/// same format as offset
|
||||||
|
screen: Rect,
|
||||||
|
/// is also lines - max len, which means height width.
|
||||||
|
length_hint: (u16, u16),
|
||||||
}
|
}
|
||||||
pub struct Doc {
|
pub struct Doc {
|
||||||
doc: PathBuf,
|
doc: PathBuf,
|
||||||
@@ -95,6 +97,23 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
enum TextScroll {
|
||||||
|
UpOne,
|
||||||
|
DownOne,
|
||||||
|
UpHalf,
|
||||||
|
DownHalf,
|
||||||
|
UpFull,
|
||||||
|
DownFull,
|
||||||
|
Up(u16),
|
||||||
|
Down(u16),
|
||||||
|
// not when i Wrap.
|
||||||
|
Left(u16),
|
||||||
|
Right(u16),
|
||||||
|
LeftOne,
|
||||||
|
RightOne,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
#[default]
|
#[default]
|
||||||
@@ -105,7 +124,7 @@ enum Message {
|
|||||||
DocSwitcherAction(Input),
|
DocSwitcherAction(Input),
|
||||||
/// close doc switcher because there is a new file coming
|
/// close doc switcher because there is a new file coming
|
||||||
NewDoc,
|
NewDoc,
|
||||||
TextScroll(Option<bool>, Option<bool>),
|
TextScroll(TextScroll),
|
||||||
}
|
}
|
||||||
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<()> {
|
||||||
@@ -118,7 +137,7 @@ impl App<'_> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn view(&self, frame: &mut Frame) {
|
fn view(&mut self, frame: &mut Frame) {
|
||||||
frame.render_widget(Clear, frame.area()); // tf this about
|
frame.render_widget(Clear, frame.area()); // tf this about
|
||||||
|
|
||||||
let [header, main, foot] = Layout::vertical([
|
let [header, main, foot] = Layout::vertical([
|
||||||
@@ -142,6 +161,14 @@ impl App<'_> {
|
|||||||
Span::from("lda").style(Style::new().fg(ratatui::style::Color::Indexed(202)));
|
Span::from("lda").style(Style::new().fg(ratatui::style::Color::Indexed(202)));
|
||||||
frame.render_widget(lda_text, lda);
|
frame.render_widget(lda_text, lda);
|
||||||
let content_block = Block::bordered().title(Line::from(" file content ").left_aligned());
|
let content_block = Block::bordered().title(Line::from(" file content ").left_aligned());
|
||||||
|
// NOOOO this is only reason self is mut
|
||||||
|
if let Some(Doc {
|
||||||
|
cache: Some(DocCache { ref mut screen, .. }),
|
||||||
|
..
|
||||||
|
}) = self.doc
|
||||||
|
{
|
||||||
|
*screen = content_block.inner(main);
|
||||||
|
}
|
||||||
|
|
||||||
let mut file_name = Text::default().blue().centered();
|
let mut file_name = Text::default().blue().centered();
|
||||||
let content;
|
let content;
|
||||||
@@ -150,7 +177,9 @@ impl App<'_> {
|
|||||||
file_name.push_span(doc.doc.display().to_string());
|
file_name.push_span(doc.doc.display().to_string());
|
||||||
if let Some(cache) = &doc.cache {
|
if let Some(cache) = &doc.cache {
|
||||||
let text = Text::from(cache.content.as_str());
|
let text = Text::from(cache.content.as_str());
|
||||||
content = Paragraph::new(text).scroll(cache.offset);
|
content = Paragraph::new(text)
|
||||||
|
.wrap(Wrap { trim: false })
|
||||||
|
.scroll(cache.offset); // pronblem
|
||||||
} else {
|
} else {
|
||||||
content = Paragraph::new("errored buhhhhhh".to_line().centered())
|
content = Paragraph::new("errored buhhhhhh".to_line().centered())
|
||||||
}
|
}
|
||||||
@@ -162,10 +191,14 @@ impl App<'_> {
|
|||||||
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(
|
frame.render_widget(
|
||||||
Line::from_iter([
|
{
|
||||||
Span::from("enter to choose file, "),
|
let mut line = Line::default();
|
||||||
Span::from("esc or q to quit"),
|
if self.explorer.is_some() {
|
||||||
]),
|
line.push_span(Span::from("enter to choose file, "));
|
||||||
|
};
|
||||||
|
line.push_span(Span::from("esc or q to quit"));
|
||||||
|
line
|
||||||
|
},
|
||||||
foot,
|
foot,
|
||||||
);
|
);
|
||||||
{
|
{
|
||||||
@@ -232,7 +265,11 @@ impl App<'_> {
|
|||||||
Err(_e) => self.state = AppState::FileError,
|
Err(_e) => self.state = AppState::FileError,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Message::OpenDocSwitcher => self.state = AppState::DocSwitcher,
|
Message::OpenDocSwitcher => {
|
||||||
|
if self.explorer.is_some() {
|
||||||
|
self.state = AppState::DocSwitcher
|
||||||
|
};
|
||||||
|
}
|
||||||
Message::NewDoc => {
|
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
|
||||||
@@ -250,6 +287,9 @@ impl App<'_> {
|
|||||||
{
|
{
|
||||||
self.doc = Some(Doc::new(file_name));
|
self.doc = Some(Doc::new(file_name));
|
||||||
return Some(Message::ReloadDoc);
|
return Some(Message::ReloadDoc);
|
||||||
|
} else if let Some(Doc { cache: None, .. }) = self.doc {
|
||||||
|
self.state = AppState::FileError;
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Some(Message::Main);
|
return Some(Message::Main);
|
||||||
@@ -280,20 +320,21 @@ impl App<'_> {
|
|||||||
}; // noooo
|
}; // noooo
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::TextScroll(up, right) => {
|
Message::TextScroll(thing) => {
|
||||||
if let Some(ref mut doc) = self.doc {
|
if let Some(Doc {
|
||||||
if let Some(up) = up {
|
cache: Some(ref mut cache),
|
||||||
let bij = if up { -1 } else { 1 }; // fuck is this about
|
..
|
||||||
if let Some(ref mut cache) = doc.cache {
|
}) = self.doc
|
||||||
cache.offset.0 = cache.offset.0.saturating_add_signed(bij);
|
&& !matches!(
|
||||||
}
|
// disabled here
|
||||||
};
|
thing,
|
||||||
if let Some(right) = right {
|
TextScroll::Left(_)
|
||||||
let bij = if right { 1 } else { -1 };
|
| TextScroll::Right(_)
|
||||||
if let Some(ref mut cache) = doc.cache {
|
| TextScroll::LeftOne
|
||||||
cache.offset.1 = cache.offset.1.saturating_add_signed(bij);
|
| TextScroll::RightOne
|
||||||
}
|
)
|
||||||
};
|
{
|
||||||
|
cache.update_scroll(thing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -336,65 +377,112 @@ impl App<'_> {
|
|||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
_ => match ev {
|
_ => {
|
||||||
event::Event::Key(KeyEvent {
|
macro_rules! osScroll {
|
||||||
code,
|
($this:expr) => {
|
||||||
modifiers,
|
Ok(Some(Message::TextScroll($this)))
|
||||||
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));
|
|
||||||
}
|
|
||||||
// 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 {
|
match ev {
|
||||||
kind,
|
event::Event::Key(KeyEvent {
|
||||||
column: _,
|
code,
|
||||||
row: _,
|
modifiers,
|
||||||
modifiers,
|
kind,
|
||||||
}) => {
|
state: _,
|
||||||
if self.doc.is_some() {
|
}) => {
|
||||||
eprintln!("{modifiers}");
|
if kind == KeyEventKind::Release {
|
||||||
let updown = tri_state(
|
return Ok(None);
|
||||||
kind.is_scroll_up() && !modifiers.contains(KeyModifiers::SHIFT),
|
}
|
||||||
kind.is_scroll_down() && !modifiers.contains(KeyModifiers::SHIFT),
|
|
||||||
);
|
if code == KeyCode::Char('q') || code == KeyCode::Esc {
|
||||||
let leftright = tri_state(
|
return Ok(Some(Message::Quit));
|
||||||
kind.is_scroll_right()
|
} else if code == KeyCode::Char('r')
|
||||||
|| (kind.is_scroll_down()
|
&& modifiers.contains(KeyModifiers::CONTROL)
|
||||||
&& modifiers.contains(KeyModifiers::SHIFT)),
|
{
|
||||||
kind.is_scroll_left()
|
return Ok(Some(Message::ReloadDoc));
|
||||||
|| (kind.is_scroll_up()
|
} else if code == KeyCode::Enter {
|
||||||
&& modifiers.contains(KeyModifiers::SHIFT)),
|
return Ok(Some(Message::OpenDocSwitcher));
|
||||||
);
|
}
|
||||||
return Ok(Some(Message::TextScroll(updown, leftright)));
|
// no what is this code block
|
||||||
|
if self.doc.is_some() {
|
||||||
|
match code {
|
||||||
|
KeyCode::Up | KeyCode::Char('k') => {
|
||||||
|
return osScroll!(TextScroll::UpOne);
|
||||||
|
}
|
||||||
|
KeyCode::Down | KeyCode::Char('j') => {
|
||||||
|
return osScroll!(TextScroll::DownOne);
|
||||||
|
}
|
||||||
|
KeyCode::Right | KeyCode::Char('l') => {
|
||||||
|
return osScroll!(TextScroll::RightOne);
|
||||||
|
}
|
||||||
|
KeyCode::Left | KeyCode::Char('h') => {
|
||||||
|
return osScroll!(TextScroll::LeftOne);
|
||||||
|
}
|
||||||
|
KeyCode::Char('u') => return osScroll!(TextScroll::UpHalf),
|
||||||
|
KeyCode::Char('d') => return osScroll!(TextScroll::DownHalf),
|
||||||
|
KeyCode::Char('f') => return osScroll!(TextScroll::UpFull),
|
||||||
|
KeyCode::Char('b') => return osScroll!(TextScroll::DownFull),
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
Ok(None)
|
Event::Mouse(MouseEvent {
|
||||||
|
kind,
|
||||||
|
column,
|
||||||
|
row,
|
||||||
|
modifiers,
|
||||||
|
}) => {
|
||||||
|
if let Some(Doc {
|
||||||
|
cache: Some(DocCache { screen, .. }),
|
||||||
|
..
|
||||||
|
}) = self.doc
|
||||||
|
&& screen.contains(Position::new(column, row))
|
||||||
|
{
|
||||||
|
match kind {
|
||||||
|
MouseEventKind::ScrollDown
|
||||||
|
if !modifiers.contains(KeyModifiers::SHIFT) =>
|
||||||
|
{
|
||||||
|
return osScroll!(TextScroll::Down(
|
||||||
|
TextScroll::SCROLL_STEPS
|
||||||
|
));
|
||||||
|
}
|
||||||
|
MouseEventKind::ScrollUp
|
||||||
|
if !modifiers.contains(KeyModifiers::SHIFT) =>
|
||||||
|
{
|
||||||
|
return osScroll!(TextScroll::Up(TextScroll::SCROLL_STEPS));
|
||||||
|
}
|
||||||
|
MouseEventKind::ScrollLeft => {
|
||||||
|
return osScroll!(TextScroll::Left(
|
||||||
|
TextScroll::SCROLL_STEPS
|
||||||
|
));
|
||||||
|
}
|
||||||
|
MouseEventKind::ScrollUp
|
||||||
|
if modifiers.contains(KeyModifiers::SHIFT) =>
|
||||||
|
{
|
||||||
|
return osScroll!(TextScroll::Left(
|
||||||
|
TextScroll::SCROLL_STEPS
|
||||||
|
));
|
||||||
|
}
|
||||||
|
MouseEventKind::ScrollRight => {
|
||||||
|
return osScroll!(TextScroll::Right(
|
||||||
|
TextScroll::SCROLL_STEPS
|
||||||
|
));
|
||||||
|
}
|
||||||
|
MouseEventKind::ScrollDown
|
||||||
|
if modifiers.contains(KeyModifiers::SHIFT) => {}
|
||||||
|
_ => {
|
||||||
|
return osScroll!(TextScroll::Right(
|
||||||
|
TextScroll::SCROLL_STEPS
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
}
|
}
|
||||||
_ => Ok(None),
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,25 +509,67 @@ impl Doc {
|
|||||||
}
|
}
|
||||||
impl DocCache {
|
impl DocCache {
|
||||||
pub fn new(doc: impl AsRef<Path>) -> io::Result<Self> {
|
pub fn new(doc: impl AsRef<Path>) -> io::Result<Self> {
|
||||||
read_lines(&doc).map(|(l, content)| Self {
|
read_lines(&doc).map(|((l, m), content)| Self {
|
||||||
content,
|
content,
|
||||||
offset: (0, 0),
|
offset: (0, 0),
|
||||||
length_hint: l as _,
|
length_hint: (l as _, m as _),
|
||||||
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn reload_doc(&mut self, doc: impl AsRef<Path>) -> io::Result<()> {
|
pub fn reload_doc(&mut self, doc: impl AsRef<Path>) -> io::Result<()> {
|
||||||
let a = read_lines(doc)?; // bail as early as possible
|
let a = read_lines(doc)?; // bail as early as possible
|
||||||
self.content.clear();
|
self.content.clear();
|
||||||
let lh;
|
let (lh, m);
|
||||||
(lh, self.content) = a;
|
((lh, m), self.content) = a;
|
||||||
self.length_hint = lh as _;
|
self.length_hint = (lh as _, m as _);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn update_scroll(&mut self, update: TextScroll) {
|
||||||
|
{
|
||||||
|
let bih = get_size_as_ldaformat(&self.screen);
|
||||||
|
let (up, right) = update.to_two_numbers(bih);
|
||||||
|
if up != 0 {
|
||||||
|
self.offset.0 = self
|
||||||
|
.offset
|
||||||
|
.0
|
||||||
|
.saturating_add_signed(-up) // real
|
||||||
|
.min(self.length_hint.0.saturating_sub(bih.0));
|
||||||
|
};
|
||||||
|
if right != 0 {
|
||||||
|
unreachable!("disabled left right handling from update");
|
||||||
|
self.offset.1 = self
|
||||||
|
.offset
|
||||||
|
.1
|
||||||
|
.saturating_add_signed(right)
|
||||||
|
.min(self.length_hint.1.saturating_sub(bih.1));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TextScroll {
|
||||||
|
const SCROLL_STEPS: u16 = 3;
|
||||||
|
pub fn to_two_numbers(&self, (height, _width): (u16, u16)) -> (i16, i16) {
|
||||||
|
match self {
|
||||||
|
TextScroll::UpOne => (1, 0),
|
||||||
|
TextScroll::DownOne => (-1, 0),
|
||||||
|
TextScroll::UpHalf => ((height / 2) as _, 0),
|
||||||
|
TextScroll::DownHalf => (-((height / 2) as i16), 0),
|
||||||
|
TextScroll::UpFull => (height as _, 0),
|
||||||
|
TextScroll::DownFull => (-(height as i16), 0),
|
||||||
|
TextScroll::Up(r) => (*r as _, 0),
|
||||||
|
TextScroll::Down(r) => (-(*r as i16), 0),
|
||||||
|
// not ever getting it
|
||||||
|
_ => unreachable!("disabled left right handling from update"),
|
||||||
|
TextScroll::Left(r) => (0, -(*r as i16)),
|
||||||
|
TextScroll::Right(r) => (0, (*r as i16)),
|
||||||
|
TextScroll::LeftOne => (0, -1),
|
||||||
|
TextScroll::RightOne => (0, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns some true if real, some false if fake, none if neither,
|
/// returns some true if real, some false if fake, none if neither,
|
||||||
/// idk what happens if both
|
/// idk what happens if both
|
||||||
fn tri_state(real: bool, fake: bool) -> Option<bool> {
|
fn _tri_state(real: bool, fake: bool) -> Option<bool> {
|
||||||
if real {
|
if real {
|
||||||
Some(true)
|
Some(true)
|
||||||
} else if fake {
|
} else if fake {
|
||||||
@@ -449,20 +579,28 @@ fn tri_state(real: bool, fake: bool) -> Option<bool> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_size_as_ldaformat(r: &Rect) -> (u16, u16) {
|
||||||
|
let Size { height, width } = r.as_size();
|
||||||
|
(height, width)
|
||||||
|
}
|
||||||
/// this works for now
|
/// this works for now
|
||||||
fn read_lines(doc: impl AsRef<Path>) -> io::Result<(usize, String)> {
|
fn read_lines(doc: impl AsRef<Path>) -> io::Result<((usize, usize), String)> {
|
||||||
let file = File::open(doc)?;
|
let file = File::open(doc)?;
|
||||||
let lenf = file.metadata()?.len() as _;
|
let lenf = file.metadata()?.len() as _;
|
||||||
let mut strg = String::with_capacity(lenf);
|
let mut strg = String::with_capacity(lenf);
|
||||||
let mut fuek = BufReader::with_capacity(lenf, file);
|
let mut fuek = BufReader::with_capacity(lenf, file);
|
||||||
let mut c = 0;
|
let mut c = 0;
|
||||||
|
let mut m = 0;
|
||||||
loop {
|
loop {
|
||||||
let r = fuek.read_line(&mut strg)?;
|
let mut str_new = String::new();
|
||||||
|
let r = fuek.read_line(&mut str_new)?;
|
||||||
if r > 0 {
|
if r > 0 {
|
||||||
c += 1;
|
c += 1;
|
||||||
|
m = m.max(str_new.len());
|
||||||
|
strg.push_str(&str_new);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((c, strg))
|
Ok(((c, m), strg))
|
||||||
}
|
}
|
||||||
+1
-1
@@ -12,7 +12,7 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
let mut r = ratatui::init();
|
let mut r = ratatui::init();
|
||||||
let mut exp = FileExplorer::new()?;
|
let mut exp = FileExplorer::new()?;
|
||||||
app::App::new()
|
app::App::new()
|
||||||
.with_doc("src/main.rs")?
|
.with_doc("src/app.rs")?
|
||||||
.with_explorer(&mut exp)
|
.with_explorer(&mut exp)
|
||||||
.run(&mut r)?;
|
.run(&mut r)?;
|
||||||
ratatui::restore();
|
ratatui::restore();
|
||||||
|
|||||||
Reference in new issue
Block a user