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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
use crate::commands::numbered_command;
use crate::commands::quit::QuitAction;
use crate::config::AppKeyMapping;
use crate::context::AppContext;
use crate::event::process_event;
use crate::event::AppEvent;
use crate::key_command::{AppExecute, CommandKeybind};
use crate::preview::preview_default;
use crate::tab::JoshutoTab;
use crate::traits::ToString;
use crate::ui;
use crate::ui::views;
use crate::ui::views::TuiView;
use uuid::Uuid;
use termion::event::{Event, Key};
use tui::layout::Rect;
pub fn run_loop(
backend: &mut ui::AppBackend,
context: &mut AppContext,
keymap_t: AppKeyMapping,
) -> std::io::Result<()> {
let curr_path = std::env::current_dir()?;
if let Ok(area) = backend.terminal_ref().size() {
// pre-calculate some ui attributes
calculate_ui_context(context, area);
}
{
let id = Uuid::new_v4();
// Initialize an initial tab
let tab = JoshutoTab::new(
curr_path,
context.ui_context_ref(),
context.config_ref().display_options_ref(),
)?;
context.tab_context_mut().insert_tab(id, tab);
// trigger a preview of child
preview_default::load_preview(context);
}
while context.quit == QuitAction::DoNot {
// do the ui
if let Ok(area) = backend.terminal_ref().size() {
// pre-calculate some ui attributes
calculate_ui_context(context, area);
// render the ui
backend.render(TuiView::new(context));
// invoke preview hooks, if appropriate
context.update_external_preview();
}
// wait for an event and pop it
let event = match context.poll_event() {
Ok(event) => event,
Err(_) => return Ok(()), // TODO
};
// handle the event
match event {
AppEvent::Termion(Event::Mouse(event)) => {
process_event::process_mouse(event, context, backend, &keymap_t);
preview_default::load_preview(context);
}
AppEvent::Termion(key) => {
if context.message_queue_ref().current_message().is_some() {
context.message_queue_mut().pop_front();
}
match key {
// in the event where mouse input is not supported
// but we still want to register scroll
Event::Unsupported(s) => {
process_event::process_unsupported(context, backend, &keymap_t, s);
}
Event::Key(Key::Char(c)) if c.is_numeric() && c != '0' => {
if let Err(e) =
numbered_command::numbered_command(c, context, backend, &keymap_t)
{
context.message_queue_mut().push_error(e.to_string());
}
}
key => match keymap_t.default_view.get(&key) {
None => {
context
.message_queue_mut()
.push_info(format!("Unmapped input: {}", key.to_string()));
}
Some(CommandKeybind::SimpleKeybind(command)) => {
if let Err(e) = command.execute(context, backend, &keymap_t) {
context.message_queue_mut().push_error(e.to_string());
}
}
Some(CommandKeybind::CompositeKeybind(m)) => {
let cmd = process_event::get_input_while_composite(backend, context, m);
if let Some(command) = cmd {
if let Err(e) = command.execute(context, backend, &keymap_t) {
context.message_queue_mut().push_error(e.to_string());
}
}
}
},
}
preview_default::load_preview(context);
context.flush_event();
}
event => process_event::process_noninteractive(event, context),
}
// update the file system supervisor that watches for changes in the FS
if context.config_ref().watch_files {
context.update_watcher();
}
} // end of main loop
Ok(())
}
fn calculate_ui_context(context: &mut AppContext, area: Rect) {
let area = Rect {
y: area.top() + 1,
height: area.height - 2,
..area
};
let config = context.config_ref();
let display_options = config.display_options_ref();
let constraints = views::get_constraints(context);
let layout = if display_options.show_borders() {
views::calculate_layout_with_borders(area, constraints)
} else {
views::calculate_layout(area, constraints)
};
context.ui_context_mut().layout = layout;
}
|