respond to mouse events

This commit is contained in:
alice pellerin
2026-03-21 03:08:07 -05:00
parent 1bd5d41123
commit 348c33143e
4 changed files with 82 additions and 21 deletions
+2 -2
View File
@@ -285,7 +285,7 @@ impl Buffer {
self.clamp_screen_to_primary_cursor(window_size); self.clamp_screen_to_primary_cursor(window_size);
} }
fn scroll_down(&mut self, window_size: WindowSize) { pub fn scroll_down(&mut self, window_size: WindowSize) {
if self.contents.len() <= 5 * BYTES_PER_LINE { return; } if self.contents.len() <= 5 * BYTES_PER_LINE { return; }
self.scroll_position = min( self.scroll_position = min(
@@ -297,7 +297,7 @@ impl Buffer {
self.combine_cursors_if_overlapping(); self.combine_cursors_if_overlapping();
} }
fn scroll_up(&mut self, window_size: WindowSize) { pub fn scroll_up(&mut self, window_size: WindowSize) {
self.scroll_position = self.scroll_position.saturating_sub(BYTES_PER_LINE); self.scroll_position = self.scroll_position.saturating_sub(BYTES_PER_LINE);
self.primary_cursor.clamp(self.scroll_position, window_size.visible_byte_count()); self.primary_cursor.clamp(self.scroll_position, window_size.visible_byte_count());
self.combine_cursors_if_overlapping(); self.combine_cursors_if_overlapping();
+74 -16
View File
@@ -1,7 +1,7 @@
use std::{env, process::exit}; use std::{env, process::exit};
use crossterm::{event::{self, Event, KeyCode, KeyEvent, KeyModifiers}, terminal::window_size}; use crossterm::{ExecutableCommand, event::{self, DisableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind}, terminal::window_size};
use ratatui::{style::Stylize, text::Span}; use ratatui::{DefaultTerminal, style::Stylize, text::Span};
use crate::{BYTES_PER_LINE, action::AppAction, buffer::Buffer, config::Config}; use crate::{BYTES_PER_LINE, action::AppAction, buffer::Buffer, config::Config, cursor::Cursor};
mod widget; mod widget;
@@ -35,41 +35,43 @@ impl App {
exit(1); exit(1);
} }
let window_size = WindowSize {
rows: window_size().unwrap().rows as usize,
covered_rows: if buffers.len() > 1 {
2 // status line and tab bar
} else {
1 // status line
},
};
Self { Self {
config: Config::default(), config: Config::default(),
buffers, buffers,
current_buffer_index: 0, current_buffer_index: 0,
window_size: WindowSize { window_size,
rows: window_size().unwrap().rows as usize,
// 1 because of the status line
covered_rows: 1,
},
should_quit: false, should_quit: false,
} }
} }
#[allow(clippy::too_many_lines)] pub fn handle_events(&mut self, terminal: &mut DefaultTerminal) {
pub fn handle_events(&mut self) {
#[allow(clippy::collapsible_match)]
match event::read().unwrap() { match event::read().unwrap() {
Event::Resize(_, height) => { Event::Resize(_, height) => {
self.window_size.rows = height as usize; self.window_size.rows = height as usize;
} }
Event::Key(key_event) => self.handle_key(key_event), Event::Key(key_event) => self.handle_key(key_event, terminal),
// Event::Mouse(mouse_event) => { Event::Mouse(mouse_event) => self.handle_mouse(mouse_event),
// mouse_event.kind
// },
_ => {} _ => {}
} }
} }
fn handle_key(&mut self, key_event: KeyEvent) { fn handle_key(&mut self, key_event: KeyEvent, terminal: &mut DefaultTerminal) {
if key_event.modifiers == KeyModifiers::CONTROL && if key_event.modifiers == KeyModifiers::CONTROL &&
key_event.code == KeyCode::Char('c') key_event.code == KeyCode::Char('c')
{ {
terminal.backend_mut().execute(DisableMouseCapture).unwrap();
crossterm::terminal::disable_raw_mode().unwrap(); crossterm::terminal::disable_raw_mode().unwrap();
ratatui::restore(); ratatui::restore();
exit(130); exit(130);
@@ -92,6 +94,62 @@ impl App {
} }
} }
fn handle_mouse(&mut self, mouse_event: MouseEvent) {
let tab_bar_rows = usize::from(self.buffers.len() > 1);
let current_buffer = &mut self.buffers[self.current_buffer_index];
match mouse_event.kind {
MouseEventKind::Down(_) => {
let byte_column = match mouse_event.column {
10..=11 => Some(0),
13..=14 => Some(1),
16..=17 => Some(2),
19..=20 => Some(3),
23..=24 => Some(4),
26..=27 => Some(5),
29..=30 => Some(6),
32..=33 => Some(7),
36..=37 => Some(8),
39..=40 => Some(9),
42..=43 => Some(10),
45..=46 => Some(11),
49..=50 => Some(12),
52..=53 => Some(13),
55..=56 => Some(14),
58..=59 => Some(15),
_ => None,
};
if let Some(byte_column) = byte_column &&
mouse_event.row as usize - tab_bar_rows < self.window_size.hex_rows()
{
current_buffer.primary_cursor = Cursor::at(
current_buffer.scroll_position +
(mouse_event.row as usize - tab_bar_rows) * BYTES_PER_LINE +
byte_column
);
current_buffer.cursors.clear();
}
},
MouseEventKind::ScrollDown => {
for _ in 0..3 {
current_buffer.scroll_down(self.window_size);
}
},
MouseEventKind::ScrollUp => {
for _ in 0..3 {
current_buffer.scroll_up(self.window_size);
}
},
_ => (),
}
}
fn quit_if_saved(&mut self) { fn quit_if_saved(&mut self) {
if self.buffers.iter().all(Buffer::all_changes_saved) { if self.buffers.iter().all(Buffer::all_changes_saved) {
self.quit(); self.quit();
+1 -1
View File
@@ -88,7 +88,7 @@ impl Buffer {
primary_cursor: Cursor::default(), primary_cursor: Cursor::default(),
cursors: Vec::new(), cursors: Vec::new(),
marks: HashSet::from([0, 4, 12, 15, 16, 17]), marks: HashSet::new(),
mode: Mode::Normal, mode: Mode::Normal,
partial_action: None, partial_action: None,
+5 -2
View File
@@ -5,6 +5,7 @@
#![feature(hash_set_entry)] #![feature(hash_set_entry)]
use app::App; use app::App;
use crossterm::{QueueableCommand, event::{DisableMouseCapture, EnableMouseCapture}};
mod app; mod app;
mod buffer; mod buffer;
@@ -22,9 +23,9 @@ const BYTES_PER_CHUNK: usize = 4;
const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK; const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK;
// TODO: // TODO:
// - m mark offset
// - search // - search
// - s/A-k/A-K // - s/A-k/A-K
// - C-a/C-x
// - modifications // - modifications
// - insert/append // - insert/append
// - mode // - mode
@@ -56,15 +57,17 @@ fn main() {
let mut app = App::new(); let mut app = App::new();
let mut terminal = ratatui::init(); let mut terminal = ratatui::init();
crossterm::terminal::enable_raw_mode().unwrap(); crossterm::terminal::enable_raw_mode().unwrap();
terminal.backend_mut().queue(EnableMouseCapture).unwrap();
while !app.should_quit { while !app.should_quit {
terminal.draw(|frame| { terminal.draw(|frame| {
frame.render_widget(&app, frame.area()); frame.render_widget(&app, frame.area());
}).unwrap(); }).unwrap();
app.handle_events(); app.handle_events(&mut terminal);
} }
terminal.backend_mut().queue(DisableMouseCapture).unwrap();
crossterm::terminal::disable_raw_mode().unwrap(); crossterm::terminal::disable_raw_mode().unwrap();
ratatui::restore(); ratatui::restore();