Refactor input processing to take action context

Various functions take some permutation of the current selection, the
terminal, and a notifier. Instead of having to juggle some number of
arguments everywhere, the `ActionContext` is constructed and then passed
around.
This commit is contained in:
Joe Wilm 2016-12-25 18:54:01 -05:00
parent 7cdf06e2be
commit 3b7c7377c9
2 changed files with 83 additions and 71 deletions

View file

@ -8,7 +8,7 @@ use glutin;
use config::Config; use config::Config;
use display::OnResize; use display::OnResize;
use input; use input::{self, ActionContext};
use selection::Selection; use selection::Selection;
use sync::FairMutex; use sync::FairMutex;
use term::{Term, SizeInfo}; use term::{Term, SizeInfo};
@ -98,18 +98,29 @@ impl<N: input::Notify> Processor<N> {
// Acquire term lock // Acquire term lock
let terminal = self.terminal.lock(); let terminal = self.terminal.lock();
let processor = &mut self.input_processor; let processor = &mut self.input_processor;
let notifier = &mut self.notifier;
{
let mut context = ActionContext {
terminal: &terminal,
notifier: &mut self.notifier,
selection: &mut self.selection,
};
processor.process_key(&mut context, state, key, mods, string);
}
self.selection.clear(); self.selection.clear();
processor.process_key(state, key, mods, notifier, *terminal.mode(), string);
}, },
glutin::Event::MouseInput(state, button) => { glutin::Event::MouseInput(state, button) => {
let terminal = self.terminal.lock(); let terminal = self.terminal.lock();
let processor = &mut self.input_processor; let processor = &mut self.input_processor;
let notifier = &mut self.notifier;
processor.mouse_input(&mut self.selection, state, button, notifier, &terminal); let mut context = ActionContext {
terminal: &terminal,
notifier: &mut self.notifier,
selection: &mut self.selection,
};
processor.mouse_input(&mut context, state, button);
*wakeup_request = true; *wakeup_request = true;
}, },
glutin::Event::MouseMoved(x, y) => { glutin::Event::MouseMoved(x, y) => {
@ -131,11 +142,17 @@ impl<N: input::Notify> Processor<N> {
terminal.dirty = true; terminal.dirty = true;
}, },
glutin::Event::MouseWheel(scroll_delta, touch_phase) => { glutin::Event::MouseWheel(scroll_delta, touch_phase) => {
let mut terminal = self.terminal.lock();
let processor = &mut self.input_processor; let processor = &mut self.input_processor;
let notifier = &mut self.notifier;
let mut context = ActionContext {
terminal: &terminal,
notifier: &mut self.notifier,
selection: &mut self.selection,
};
processor.on_mouse_wheel( processor.on_mouse_wheel(
notifier, &mut context,
scroll_delta, scroll_delta,
touch_phase, touch_phase,
); );

View file

@ -25,7 +25,7 @@
//! TODO handling xmodmap would be good //! TODO handling xmodmap would be good
use std::borrow::Cow; use std::borrow::Cow;
use copypasta::{Clipboard, Load}; use copypasta::{Clipboard, Load, Store};
use glutin::{ElementState, VirtualKeyCode, MouseButton}; use glutin::{ElementState, VirtualKeyCode, MouseButton};
use glutin::{Mods, mods}; use glutin::{Mods, mods};
use glutin::{TouchPhase, MouseScrollDelta}; use glutin::{TouchPhase, MouseScrollDelta};
@ -142,8 +142,8 @@ impl KeyBinding {
} }
#[inline] #[inline]
fn execute<N: Notify>(&self, notifier: &mut N, mode: &TermMode) { fn execute<'a, N: Notify>(&self, context: &mut ActionContext<'a, N>) {
self.binding.action.execute(notifier, mode) self.binding.action.execute(context)
} }
} }
@ -162,8 +162,8 @@ impl MouseBinding {
} }
#[inline] #[inline]
fn execute<N: Notify>(&self, notifier: &mut N, mode: &TermMode) { fn execute<'a, N: Notify>(&self, context: &mut ActionContext<'a, N>) {
self.binding.action.execute(notifier, mode) self.binding.action.execute(context)
} }
} }
@ -175,25 +175,32 @@ pub enum Action {
/// Paste contents of system clipboard /// Paste contents of system clipboard
Paste, Paste,
// Store current selection into clipboard
Copy,
/// Paste contents of selection buffer /// Paste contents of selection buffer
PasteSelection, PasteSelection,
} }
impl Action { impl Action {
#[inline] #[inline]
fn execute<N: Notify>(&self, notifier: &mut N, mode: &TermMode) { fn execute<'a, N: Notify>(&self, ctx: &mut ActionContext<'a, N>) {
match *self { match *self {
Action::Esc(ref s) => notifier.notify(s.clone().into_bytes()), Action::Esc(ref s) => ctx.notifier.notify(s.clone().into_bytes()),
Action::Copy => {
// so... need access to terminal state. and the selection.
unimplemented!();
},
Action::Paste | Action::PasteSelection => { Action::Paste | Action::PasteSelection => {
let clip = Clipboard::new().expect("get clipboard"); let clip = Clipboard::new().expect("get clipboard");
clip.load_selection() clip.load_selection()
.map(|contents| { .map(|contents| {
if mode.contains(mode::BRACKETED_PASTE) { if ctx.terminal.mode().contains(mode::BRACKETED_PASTE) {
notifier.notify(&b"\x1b[200~"[..]); ctx.notifier.notify(&b"\x1b[200~"[..]);
notifier.notify(contents.into_bytes()); ctx.notifier.notify(contents.into_bytes());
notifier.notify(&b"\x1b[201~"[..]); ctx.notifier.notify(&b"\x1b[201~"[..]);
} else { } else {
notifier.notify(contents.into_bytes()); ctx.notifier.notify(contents.into_bytes());
} }
}) })
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
@ -240,11 +247,11 @@ impl Binding {
} }
} }
// key mods escape appkey appcursor crlf pub struct ActionContext<'a, N: 'a> {
// pub notifier: &'a mut N,
// notes: appkey = DECPAM (application keypad mode); not enabled is "normal keypad" pub terminal: &'a Term,
// appcursor = DECCKM (application cursor mode); pub selection: &'a mut Selection
// crlf = LNM (Linefeed/new line); wtf is this }
impl Processor { impl Processor {
pub fn resize(&mut self, size_info: &term::SizeInfo) { pub fn resize(&mut self, size_info: &term::SizeInfo) {
@ -292,10 +299,10 @@ impl Processor {
} }
} }
pub fn mouse_report<N: Notify>( pub fn mouse_report<'a, N: Notify>(
&mut self, &mut self,
button: u8, button: u8,
notifier: &mut N, context: &mut ActionContext<'a, N>
) { ) {
let (line, column) = (self.mouse.line, self.mouse.column); let (line, column) = (self.mouse.line, self.mouse.column);
@ -309,34 +316,32 @@ impl Processor {
32 + 1 + line.0 as u8, 32 + 1 + line.0 as u8,
]; ];
notifier.notify(msg); context.notifier.notify(msg);
} }
} }
pub fn on_mouse_press<N: Notify>( pub fn on_mouse_press<'a, N: Notify>(
&mut self, &mut self,
notifier: &mut N, context: &mut ActionContext<'a, N>
terminal: &Term,
selection: &mut Selection
) { ) {
if terminal.mode().contains(mode::MOUSE_REPORT_CLICK) { if context.terminal.mode().contains(mode::MOUSE_REPORT_CLICK) {
self.mouse_report(0, notifier); self.mouse_report(0, context);
return; return;
} }
selection.clear(); context.selection.clear();
} }
pub fn on_mouse_release<N: Notify>(&mut self, notifier: &mut N, terminal: &Term) { pub fn on_mouse_release<'a, N: Notify>(&mut self, context: &mut ActionContext<'a, N>) {
if terminal.mode().contains(mode::MOUSE_REPORT_CLICK) { if context.terminal.mode().contains(mode::MOUSE_REPORT_CLICK) {
self.mouse_report(3, notifier); self.mouse_report(3, context);
return; return;
} }
} }
pub fn on_mouse_wheel<N: Notify>( pub fn on_mouse_wheel<'a, N: Notify>(
&mut self, &mut self,
notifier: &mut N, context: &mut ActionContext<'a, N>,
delta: MouseScrollDelta, delta: MouseScrollDelta,
phase: TouchPhase, phase: TouchPhase,
) { ) {
@ -349,7 +354,7 @@ impl Processor {
}; };
for _ in 0..(lines.abs() as usize) { for _ in 0..(lines.abs() as usize) {
self.mouse_report(code, notifier); self.mouse_report(code, context);
} }
}, },
MouseScrollDelta::PixelDelta(_x, y) => { MouseScrollDelta::PixelDelta(_x, y) => {
@ -371,7 +376,7 @@ impl Processor {
65 65
}; };
self.mouse_report(button, notifier); self.mouse_report(button, context);
} }
}, },
_ => (), _ => (),
@ -380,13 +385,11 @@ impl Processor {
} }
} }
pub fn mouse_input<N: Notify>( pub fn mouse_input<'a, N: Notify>(
&mut self, &mut self,
selection: &mut Selection, context: &mut ActionContext<'a, N>,
state: ElementState, state: ElementState,
button: MouseButton, button: MouseButton,
notifier: &mut N,
terminal: &Term
) { ) {
if let MouseButton::Left = button { if let MouseButton::Left = button {
// TODO handle state changes // TODO handle state changes
@ -394,10 +397,10 @@ impl Processor {
self.mouse.left_button_state = state; self.mouse.left_button_state = state;
match state { match state {
ElementState::Pressed => { ElementState::Pressed => {
self.on_mouse_press(notifier, terminal, selection); self.on_mouse_press(context);
}, },
ElementState::Released => { ElementState::Released => {
self.on_mouse_release(notifier, terminal); self.on_mouse_release(context);
} }
} }
} }
@ -408,21 +411,19 @@ impl Processor {
} }
Processor::process_mouse_bindings( Processor::process_mouse_bindings(
context,
&self.mouse_bindings[..], &self.mouse_bindings[..],
*terminal.mode(),
notifier,
mods::NONE, mods::NONE,
button button
); );
} }
pub fn process_key<N: Notify>( pub fn process_key<'a, N: Notify>(
&mut self, &mut self,
context: &mut ActionContext<'a, N>,
state: ElementState, state: ElementState,
key: Option<VirtualKeyCode>, key: Option<VirtualKeyCode>,
mods: Mods, mods: Mods,
notifier: &mut N,
mode: TermMode,
string: Option<String>, string: Option<String>,
) { ) {
if let Some(key) = key { if let Some(key) = key {
@ -431,13 +432,13 @@ impl Processor {
return; return;
} }
if Processor::process_key_bindings(&self.key_bindings[..], mode, notifier, mods, key) { if Processor::process_key_bindings(context, &self.key_bindings[..], mods, key) {
return; return;
} }
// Didn't process a binding; print the provided character // Didn't process a binding; print the provided character
if let Some(string) = string { if let Some(string) = string {
notifier.notify(string.into_bytes()); context.notifier.notify(string.into_bytes());
} }
} }
} }
@ -448,19 +449,16 @@ impl Processor {
/// for its action to be executed. /// for its action to be executed.
/// ///
/// Returns true if an action is executed. /// Returns true if an action is executed.
fn process_key_bindings<N>( fn process_key_bindings<'a, N: Notify>(
context: &mut ActionContext<'a, N>,
bindings: &[KeyBinding], bindings: &[KeyBinding],
mode: TermMode,
notifier: &mut N,
mods: Mods, mods: Mods,
key: VirtualKeyCode key: VirtualKeyCode
) -> bool ) -> bool {
where N: Notify
{
for binding in bindings { for binding in bindings {
if binding.is_triggered_by(&mode, &mods, &key) { if binding.is_triggered_by(context.terminal.mode(), &mods, &key) {
// binding was triggered; run the action // binding was triggered; run the action
binding.execute(notifier, &mode); binding.execute(context);
return true; return true;
} }
} }
@ -474,19 +472,16 @@ impl Processor {
/// for its action to be executed. /// for its action to be executed.
/// ///
/// Returns true if an action is executed. /// Returns true if an action is executed.
fn process_mouse_bindings<N>( fn process_mouse_bindings<'a, N: Notify>(
context: &mut ActionContext<'a, N>,
bindings: &[MouseBinding], bindings: &[MouseBinding],
mode: TermMode,
notifier: &mut N,
mods: Mods, mods: Mods,
button: MouseButton button: MouseButton
) -> bool ) -> bool {
where N: Notify
{
for binding in bindings { for binding in bindings {
if binding.is_triggered_by(&mode, &mods, &button) { if binding.is_triggered_by(context.terminal.mode(), &mods, &button) {
// binding was triggered; run the action // binding was triggered; run the action
binding.execute(notifier, &mode); binding.execute(context);
return true; return true;
} }
} }