From 457f644f30b8d78867a8ea28a0dbd4b7c819466f Mon Sep 17 00:00:00 2001 From: Richard Menzies <52405405+WizardOhio24@users.noreply.github.com> Date: Tue, 23 Feb 2021 10:03:50 +0000 Subject: [PATCH] Support mouse scrolling (#306) Linked to #226 --- src/components/commit_details/details.rs | 15 ++++++- src/components/commitlist.rs | 16 +++++++- src/components/diff.rs | 52 +++++++++++++++++++++++- src/components/filetree.rs | 17 +++++++- src/main.rs | 3 ++ 5 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/components/commit_details/details.rs b/src/components/commit_details/details.rs index 10a4ef7b..7ab196a5 100644 --- a/src/components/commit_details/details.rs +++ b/src/components/commit_details/details.rs @@ -12,7 +12,10 @@ use asyncgit::{ sync::{self, CommitDetails, CommitId, CommitMessage}, CWD, }; -use crossterm::event::Event; +use crossterm::event::{ + Event, + MouseEventKind::{ScrollDown, ScrollUp}, +}; use itertools::Itertools; use std::clone::Clone; use std::{borrow::Cow, cell::Cell}; @@ -394,7 +397,15 @@ impl Component for DetailsComponent { fn event(&mut self, event: Event) -> Result { if self.focused { - if let Event::Key(e) = event { + if let Event::Mouse(mouse_ev) = event { + return Ok(match mouse_ev.kind { + ScrollUp => self.move_scroll_top(ScrollType::Up), + ScrollDown => { + self.move_scroll_top(ScrollType::Down) + } + _ => false, + }); + } else if let Event::Key(e) = event { return Ok(if e == self.key_config.move_up { self.move_scroll_top(ScrollType::Up) } else if e == self.key_config.move_down { diff --git a/src/components/commitlist.rs b/src/components/commitlist.rs index 16b071d9..aeb0de3e 100644 --- a/src/components/commitlist.rs +++ b/src/components/commitlist.rs @@ -11,7 +11,10 @@ use crate::{ }; use anyhow::Result; use asyncgit::sync::Tags; -use crossterm::event::Event; +use crossterm::event::{ + Event, + MouseEventKind::{ScrollDown, ScrollUp}, +}; use std::{ borrow::Cow, cell::Cell, cmp, convert::TryFrom, time::Instant, }; @@ -346,7 +349,16 @@ impl DrawableComponent for CommitList { impl Component for CommitList { fn event(&mut self, ev: Event) -> Result { - if let Event::Key(k) = ev { + if let Event::Mouse(mouse_ev) = ev { + let selection_changed = match mouse_ev.kind { + ScrollUp => self.move_selection(ScrollType::Up)?, + ScrollDown => { + self.move_selection(ScrollType::Down)? + } + _ => false, + }; + return Ok(selection_changed); + } else if let Event::Key(k) = ev { let selection_changed = if k == self.key_config.move_up { self.move_selection(ScrollType::Up)? } else if k == self.key_config.move_down { diff --git a/src/components/diff.rs b/src/components/diff.rs index b5be1565..c34b25f0 100644 --- a/src/components/diff.rs +++ b/src/components/diff.rs @@ -11,7 +11,10 @@ use crate::{ use anyhow::Result; use asyncgit::{hash, sync, DiffLine, DiffLineType, FileDiff, CWD}; use bytesize::ByteSize; -use crossterm::event::Event; +use crossterm::event::{ + Event, KeyModifiers, + MouseEventKind::{ScrollDown, ScrollUp}, +}; use std::{borrow::Cow, cell::Cell, cmp, path::Path}; use tui::{ backend::Backend, @@ -629,9 +632,54 @@ impl Component for DiffComponent { CommandBlocking::PassingOn } + #[allow(clippy::too_many_lines)] fn event(&mut self, ev: Event) -> Result { if self.focused { - if let Event::Key(e) = ev { + if let Event::Mouse(mouse_ev) = ev { + return match mouse_ev.kind { + ScrollUp => { + match mouse_ev.modifiers { + KeyModifiers::SHIFT => { + self.modify_selection(Direction::Up); + } + KeyModifiers::CONTROL => { + self.modify_selection(Direction::Up); + self.modify_selection(Direction::Up); + self.modify_selection(Direction::Up); + } + KeyModifiers::NONE => { + self.move_selection(ScrollType::Up); + } + _ => {} + }; + Ok(true) + } + ScrollDown => { + match mouse_ev.modifiers { + KeyModifiers::SHIFT => { + self.modify_selection(Direction::Down) + } + KeyModifiers::CONTROL => { + self.modify_selection( + Direction::Down, + ); + self.modify_selection( + Direction::Down, + ); + self.modify_selection( + Direction::Down, + ); + } + KeyModifiers::NONE => { + self.move_selection(ScrollType::Down); + } + _ => {} + }; + Ok(true) + } + _ => Ok(false), + }; + } else if let Event::Key(e) = ev { return if e == self.key_config.move_down { self.move_selection(ScrollType::Down); Ok(true) diff --git a/src/components/filetree.rs b/src/components/filetree.rs index 0e200664..04d034a7 100644 --- a/src/components/filetree.rs +++ b/src/components/filetree.rs @@ -15,7 +15,10 @@ use crate::{ }; use anyhow::Result; use asyncgit::{hash, StatusItem, StatusItemType}; -use crossterm::event::Event; +use crossterm::event::{ + Event, + MouseEventKind::{ScrollDown, ScrollUp}, +}; use std::{borrow::Cow, cell::Cell, convert::From, path::Path}; use tui::{backend::Backend, layout::Rect, text::Span, Frame}; @@ -395,7 +398,17 @@ impl Component for FileTreeComponent { fn event(&mut self, ev: Event) -> Result { if self.focused { - if let Event::Key(e) = ev { + if let Event::Mouse(mouse_ev) = ev { + return match mouse_ev.kind { + ScrollUp => { + Ok(self.move_selection(MoveSelection::Up)) + } + ScrollDown => { + Ok(self.move_selection(MoveSelection::Down)) + } + _ => Ok(false), + }; + } else if let Event::Key(e) = ev { return if e == self.key_config.move_down { Ok(self.move_selection(MoveSelection::Down)) } else if e == self.key_config.move_up { diff --git a/src/main.rs b/src/main.rs index 47972eae..053fac6c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,7 @@ use clap::{ }; use crossbeam_channel::{tick, unbounded, Receiver, Select}; use crossterm::{ + event::{DisableMouseCapture, EnableMouseCapture}, terminal::{ disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, @@ -167,11 +168,13 @@ fn main() -> Result<()> { fn setup_terminal() -> Result<()> { enable_raw_mode()?; io::stdout().execute(EnterAlternateScreen)?; + io::stdout().execute(EnableMouseCapture)?; Ok(()) } fn shutdown_terminal() -> Result<()> { io::stdout().execute(LeaveAlternateScreen)?; + io::stdout().execute(DisableMouseCapture)?; disable_raw_mode()?; Ok(()) }