summaryrefslogtreecommitdiffstats
path: root/src/event_dispatch.rs
blob: 8331a9fdbe8cfae6d63ea66fec08e5617fcc3dd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use anyhow::Result;
use tuikit::prelude::{Event, Key, MouseButton};

use crate::config::Colors;
use crate::event_exec::{EventAction, LeaveMode};
use crate::keybindings::Bindings;
use crate::mode::{InputSimple, MarkAction, Mode, Navigate};
use crate::status::Status;

/// Struct which mutates `tabs.selected()..
/// Holds a mapping which can't be static since it's read from a config file.
/// All keys are mapped to relevent events on tabs.selected().
/// Keybindings are read from `Config`.
pub struct EventDispatcher {
    binds: Bindings,
}

impl EventDispatcher {
    /// Creates a map of configurable keybindings to `EventChar`
    /// The `EventChar` is then associated to a `tabs.selected(). method.
    pub fn new(binds: Bindings) -> Self {
        Self { binds }
    }

    /// Reaction to received events.
    /// Only non keyboard events are dealt here directly.
    /// Keyboard events are configurable and are sent to specific functions
    /// which needs to know those keybindings.
    pub fn dispatch(
        &self,
        status: &mut Status,
        ev: Event,
        colors: &Colors,
        current_height: usize,
    ) -> Result<()> {
        match ev {
            Event::Key(Key::WheelUp(_, col, _)) => {
                status.select_pane(col)?;
                EventAction::move_up(status, colors)?;
            }
            Event::Key(Key::WheelDown(_, col, _)) => {
                status.select_pane(col)?;
                EventAction::move_down(status, colors)?;
            }
            Event::Key(Key::SingleClick(MouseButton::Left, row, col)) => {
                status.click(row, col, current_height, colors)?;
            }
            Event::Key(
                Key::SingleClick(MouseButton::Right, row, col)
                | Key::DoubleClick(MouseButton::Left, row, col),
            ) => {
                status.click(row, col, current_height, colors)?;
                LeaveMode::right_click(status, colors)?;
            }
            Event::User(_) => status.selected().refresh_if_needed()?,

            Event::Resize { width, height } => status.resize(width, height)?,
            Event::Key(Key::Char(c)) => self.char(status, c, colors)?,
            Event::Key(key) => self.key_matcher(status, key, colors)?,
            _ => (),
        };
        Ok(())
    }

    fn key_matcher(&self, status: &mut Status, key: Key, colors: &Colors) -> Result<()> {
        match self.binds.get(&key) {
            Some(action) => action.matcher(status, colors),
            None => Ok(()),
        }
    }

    fn char(&self, status: &mut Status, c: char, colors: &Colors) -> Result<()> {
        let tab = status.selected();
        match tab.mode {
            Mode::InputSimple(InputSimple::Sort) => tab.sort(c, colors),
            Mode::InputSimple(InputSimple::RegexMatch) => {
                tab.input.insert(c);
                status.select_from_regex()?;
                Ok(())
            }
            Mode::InputSimple(_) => {
                tab.input.insert(c);
                Ok(())
            }
            Mode::InputCompleted(_) => tab.text_insert_and_complete(c),
            Mode::Normal | Mode::Tree => match self.binds.get(&Key::Char(c)) {
                Some(action) => action.matcher(status, colors),
                None => Ok(()),
            },
            Mode::NeedConfirmation(confirmed_action) => status.confirm(c, confirmed_action, colors),
            Mode::Navigate(Navigate::Trash) if c == 'x' => status.trash.remove(),
            Mode::Navigate(Navigate::EncryptedDrive) if c == 'm' => status.mount_encrypted_drive(),
            Mode::Navigate(Navigate::EncryptedDrive) if c == 'g' => status.go_to_encrypted_drive(),
            Mode::Navigate(Navigate::EncryptedDrive) if c == 'u' => status.umount_encrypted_drive(),
            Mode::Navigate(Navigate::Jump) if c == ' ' => status.jump_remove_selected_flagged(),
            Mode::Navigate(Navigate::Jump) if c == 'u' => status.clear_flags_and_reset_view(),
            Mode::Navigate(Navigate::Jump) if c == 'x' => status.delete_single_flagged(),
            Mode::Navigate(Navigate::Jump) if c == 'X' => status.trash_single_flagged(),
            Mode::Navigate(Navigate::Marks(MarkAction::Jump)) => status.marks_jump_char(c, colors),
            Mode::Navigate(Navigate::Marks(MarkAction::New)) => status.marks_new(c, colors),
            Mode::Preview | Mode::Navigate(_) => {
                if tab.reset_mode() {
                    tab.refresh_view()?;
                }
                Ok(())
            }
        }
    }
}