TUI #1
13
src/main.rs
13
src/main.rs
@ -1,6 +1,10 @@
|
|||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use ratatui::Terminal;
|
||||||
|
use ratatui::backend::CrosstermBackend;
|
||||||
|
use std::io::stdout;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
use crate::tui::Tui;
|
||||||
|
|
||||||
pub mod gui;
|
pub mod gui;
|
||||||
pub mod tui;
|
pub mod tui;
|
||||||
@ -30,16 +34,17 @@ fn main() -> Result<()> {
|
|||||||
// If the CLI was provided a directory, convert it to absolute.
|
// If the CLI was provided a directory, convert it to absolute.
|
||||||
Some(path) => std::path::absolute(path)?,
|
Some(path) => std::path::absolute(path)?,
|
||||||
// If no path was provided, use the current directory.
|
// If no path was provided, use the current directory.
|
||||||
None => std::env::current_dir().unwrap_or_else(|_|
|
None => std::env::current_dir().unwrap_or(
|
||||||
// If we can't find the CWD, attempt to open the home directory.
|
// If we can't find the CWD, attempt to open the home directory.
|
||||||
dirs::home_dir().expect("Failed to access filesystem.")),
|
dirs::home_dir().context("Failed to obtain home directory")?,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
match args.gui {
|
match args.gui {
|
||||||
true => gui::run(root_path),
|
true => gui::run(root_path),
|
||||||
false => match args.tui {
|
false => match args.tui {
|
||||||
// Open the TUI editor if requested, otherwise use the QML GUI by default.
|
// Open the TUI editor if requested, otherwise use the QML GUI by default.
|
||||||
true => Ok(tui::Tui::new(root_path).start()?),
|
true => Ok(Tui::new(root_path)?.start()?),
|
||||||
false => {
|
false => {
|
||||||
// Relaunch the CLIDE GUI in a separate process.
|
// Relaunch the CLIDE GUI in a separate process.
|
||||||
Command::new(std::env::current_exe()?)
|
Command::new(std::env::current_exe()?)
|
||||||
|
|||||||
11
src/tui.rs
11
src/tui.rs
@ -20,12 +20,11 @@ pub struct Tui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Tui {
|
impl Tui {
|
||||||
pub fn new(root_path: std::path::PathBuf) -> Self {
|
pub fn new(root_path: std::path::PathBuf) -> Result<Self> {
|
||||||
Self {
|
Ok(Self {
|
||||||
terminal: Terminal::new(CrosstermBackend::new(stdout()))
|
terminal: Terminal::new(CrosstermBackend::new(stdout()))?,
|
||||||
.expect("Failed to initialize terminal"),
|
|
||||||
root_path,
|
root_path,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(self) -> Result<()> {
|
pub fn start(self) -> Result<()> {
|
||||||
@ -38,7 +37,7 @@ impl Tui {
|
|||||||
)?;
|
)?;
|
||||||
enable_raw_mode()?;
|
enable_raw_mode()?;
|
||||||
|
|
||||||
let app_result = app::App::new(self.root_path)
|
let app_result = app::App::new(self.root_path)?
|
||||||
.run(self.terminal)
|
.run(self.terminal)
|
||||||
.context("Failed to start the TUI editor.");
|
.context("Failed to start the TUI editor.");
|
||||||
Self::stop()?;
|
Self::stop()?;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::tui::component::{Action, Component};
|
use crate::tui::component::{Action, Component};
|
||||||
use crate::tui::editor::Editor;
|
use crate::tui::editor::Editor;
|
||||||
use crate::tui::explorer::Explorer;
|
use crate::tui::explorer::Explorer;
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Context, Result, anyhow};
|
||||||
use ratatui::buffer::Buffer;
|
use ratatui::buffer::Buffer;
|
||||||
use ratatui::crossterm::event;
|
use ratatui::crossterm::event;
|
||||||
use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
|
use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
|
||||||
@ -23,18 +23,21 @@ pub struct App<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> App<'a> {
|
impl<'a> App<'a> {
|
||||||
pub(crate) fn new(root_path: PathBuf) -> Self {
|
pub fn new(root_path: PathBuf) -> Result<Self> {
|
||||||
let mut app = Self {
|
let mut app = Self {
|
||||||
components: vec![
|
components: vec![
|
||||||
AppComponents::AppExplorer(Explorer::new(&root_path)),
|
AppComponents::AppExplorer(Explorer::new(&root_path)?),
|
||||||
AppComponents::AppEditor(Editor::new()),
|
AppComponents::AppEditor(Editor::new()),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
app.get_editor_mut()
|
app.get_editor_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_contents(&root_path.join("src/tui/app.rs"))
|
.set_contents(&root_path.join("src/tui/app.rs"))
|
||||||
.expect("Failed to set editor contents.");
|
.context(format!(
|
||||||
app
|
"Failed to initialize editor contents to path: {}",
|
||||||
|
root_path.to_string_lossy()
|
||||||
|
))?;
|
||||||
|
Ok(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_explorer(&self) -> Result<&Explorer<'a>> {
|
fn get_explorer(&self) -> Result<&Explorer<'a>> {
|
||||||
@ -77,27 +80,22 @@ impl<'a> App<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_event(&mut self) -> Option<Event> {
|
|
||||||
if !event::poll(Duration::from_millis(250)).expect("event poll failed") {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
event::read().ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
pub fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||||
loop {
|
loop {
|
||||||
// TODO: Handle events based on which component is active.
|
self.refresh_editor_contents()
|
||||||
|
.context("Failed to refresh editor contents.")?;
|
||||||
|
|
||||||
terminal.draw(|f| {
|
terminal.draw(|f| {
|
||||||
f.render_widget(&mut self, f.area());
|
f.render_widget(&mut self, f.area());
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Some(event) = self.get_event() {
|
// TODO: Handle events based on which component is active.
|
||||||
match self.handle_event(event) {
|
if event::poll(Duration::from_millis(250)).context("event poll failed")? {
|
||||||
|
match self.handle_event(event::read()?)? {
|
||||||
Action::Quit => break,
|
Action::Quit => break,
|
||||||
Action::Handled => {}
|
Action::Handled => {}
|
||||||
_ => {
|
_ => {
|
||||||
// panic!("Unhandled event: {:?}", event);
|
// anyhow::anyhow!("Unhandled event: {:?}", event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +158,7 @@ impl<'a> App<'a> {
|
|||||||
};
|
};
|
||||||
let editor = self
|
let editor = self
|
||||||
.get_editor_mut()
|
.get_editor_mut()
|
||||||
.expect("Failed to get active editor while refreshing contents.");
|
.context("Failed to get active editor while refreshing contents.")?;
|
||||||
if let Some(current_file_path) = editor.file_path.clone() {
|
if let Some(current_file_path) = editor.file_path.clone() {
|
||||||
if selected_pathbuf == current_file_path || !selected_pathbuf.is_file() {
|
if selected_pathbuf == current_file_path || !selected_pathbuf.is_file() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -208,8 +206,6 @@ impl<'a> Widget for &mut App<'a> {
|
|||||||
explorer.render(horizontal[0], buf);
|
explorer.render(horizontal[0], buf);
|
||||||
}
|
}
|
||||||
self.draw_tabs(editor_layout[0], buf);
|
self.draw_tabs(editor_layout[0], buf);
|
||||||
self.refresh_editor_contents()
|
|
||||||
.expect("Failed to refresh editor contents.");
|
|
||||||
self.get_editor_mut().unwrap().render(editor_layout[1], buf);
|
self.get_editor_mut().unwrap().render(editor_layout[1], buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,12 +223,14 @@ impl<'a> Component for App<'a> {
|
|||||||
/// (such as editor tabs, file explorer, status bars, etc..)
|
/// (such as editor tabs, file explorer, status bars, etc..)
|
||||||
///
|
///
|
||||||
/// Handles events for the App and delegates to attached Components.
|
/// Handles events for the App and delegates to attached Components.
|
||||||
fn handle_event(&mut self, event: Event) -> Action {
|
fn handle_event(&mut self, event: Event) -> Result<Action> {
|
||||||
// Handle events in the primary application.
|
// Handle events in the primary application.
|
||||||
if let Some(key_event) = event.as_key_event() {
|
if let Some(key_event) = event.as_key_event() {
|
||||||
match self.handle_key_events(key_event) {
|
let res = self
|
||||||
Action::Quit => return Action::Quit,
|
.handle_key_events(key_event)
|
||||||
Action::Handled => return Action::Handled,
|
.context("Failed to handle key events for primary App Component.");
|
||||||
|
match res {
|
||||||
|
Ok(Action::Quit) | Ok(Action::Handled) => return res,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,29 +238,29 @@ impl<'a> Component for App<'a> {
|
|||||||
// Handle events for all components.
|
// Handle events for all components.
|
||||||
for component in &mut self.components {
|
for component in &mut self.components {
|
||||||
let action = match component {
|
let action = match component {
|
||||||
AppComponents::AppEditor(editor) => editor.handle_event(event.clone()),
|
AppComponents::AppEditor(editor) => editor.handle_event(event.clone())?,
|
||||||
AppComponents::AppExplorer(explorer) => explorer.handle_event(event.clone()),
|
AppComponents::AppExplorer(explorer) => explorer.handle_event(event.clone())?,
|
||||||
AppComponents::AppComponent(comp) => comp.handle_event(event.clone()),
|
AppComponents::AppComponent(comp) => comp.handle_event(event.clone())?,
|
||||||
};
|
};
|
||||||
// Actions returned here abort the input handling iteration.
|
// Actions returned here abort the input handling iteration.
|
||||||
match action {
|
match action {
|
||||||
Action::Quit | Action::Handled => return action,
|
Action::Quit | Action::Handled => return Ok(action),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::Noop
|
Ok(Action::Noop)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles key events for the App Component only.
|
/// Handles key events for the App Component only.
|
||||||
fn handle_key_events(&mut self, key: KeyEvent) -> Action {
|
fn handle_key_events(&mut self, key: KeyEvent) -> Result<Action> {
|
||||||
match key {
|
match key {
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Char('c'),
|
code: KeyCode::Char('c'),
|
||||||
modifiers: KeyModifiers::CONTROL,
|
modifiers: KeyModifiers::CONTROL,
|
||||||
kind: KeyEventKind::Press,
|
kind: KeyEventKind::Press,
|
||||||
state: _state,
|
state: _state,
|
||||||
} => Action::Quit,
|
} => Ok(Action::Quit),
|
||||||
_ => Action::Noop,
|
_ => Ok(Action::Noop),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#![allow(dead_code, unused_variables)]
|
#![allow(dead_code, unused_variables)]
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use ratatui::crossterm::event::{Event, KeyEvent, MouseEvent};
|
use ratatui::crossterm::event::{Event, KeyEvent, MouseEvent};
|
||||||
|
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
@ -25,22 +26,22 @@ pub trait Component {
|
|||||||
/// This is used for lookup in a container of Components.
|
/// This is used for lookup in a container of Components.
|
||||||
fn id(&self) -> &str;
|
fn id(&self) -> &str;
|
||||||
|
|
||||||
fn handle_event(&mut self, event: Event) -> Action {
|
fn handle_event(&mut self, event: Event) -> Result<Action> {
|
||||||
match event {
|
match event {
|
||||||
Event::Key(key_event) => self.handle_key_events(key_event),
|
Event::Key(key_event) => self.handle_key_events(key_event),
|
||||||
_ => Action::Noop,
|
_ => Ok(Action::Noop),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_key_events(&mut self, key: KeyEvent) -> Action {
|
fn handle_key_events(&mut self, key: KeyEvent) -> Result<Action> {
|
||||||
Action::Noop
|
Ok(Action::Noop)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Action {
|
fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Result<Action> {
|
||||||
Action::Noop
|
Ok(Action::Noop)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, action: Action) -> Action {
|
fn update(&mut self, action: Action) -> Result<Action> {
|
||||||
Action::Noop
|
Ok(Action::Noop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,32 +90,32 @@ impl Component for Editor {
|
|||||||
"editor"
|
"editor"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_event(&mut self, event: Event) -> Action {
|
fn handle_event(&mut self, event: Event) -> Result<Action> {
|
||||||
if let Some(key_event) = event.as_key_event() {
|
if let Some(key_event) = event.as_key_event() {
|
||||||
// Handle events here that should not be passed on to the vim emulation handler.
|
// Handle events here that should not be passed on to the vim emulation handler.
|
||||||
match self.handle_key_events(key_event) {
|
match self.handle_key_events(key_event)? {
|
||||||
Action::Handled => return Action::Handled,
|
Action::Handled => return Ok(Action::Handled),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.event_handler.on_event(event, &mut self.state);
|
self.event_handler.on_event(event, &mut self.state);
|
||||||
Action::Pass
|
Ok(Action::Pass)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The events for the vim emulation should be handled by EditorEventHandler::on_event.
|
/// The events for the vim emulation should be handled by EditorEventHandler::on_event.
|
||||||
/// These events are custom to the clide application.
|
/// These events are custom to the clide application.
|
||||||
fn handle_key_events(&mut self, key: KeyEvent) -> Action {
|
fn handle_key_events(&mut self, key: KeyEvent) -> Result<Action> {
|
||||||
match key {
|
match key {
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Char('s'),
|
code: KeyCode::Char('s'),
|
||||||
modifiers: KeyModifiers::CONTROL,
|
modifiers: KeyModifiers::CONTROL,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
self.save().expect("Failed to save file.");
|
self.save().context("Failed to save file.")?;
|
||||||
Action::Handled
|
Ok(Action::Handled)
|
||||||
}
|
}
|
||||||
// For other events not handled here, pass to the vim emulation handler.
|
// For other events not handled here, pass to the vim emulation handler.
|
||||||
_ => Action::Noop,
|
_ => Ok(Action::Noop),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::tui::component::{Action, Component};
|
use crate::tui::component::{Action, Component};
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use ratatui::buffer::Buffer;
|
use ratatui::buffer::Buffer;
|
||||||
use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, MouseEvent, MouseEventKind};
|
use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, MouseEvent, MouseEventKind};
|
||||||
use ratatui::layout::{Alignment, Position, Rect};
|
use ratatui::layout::{Alignment, Position, Rect};
|
||||||
@ -17,33 +17,36 @@ pub struct Explorer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Explorer<'a> {
|
impl<'a> Explorer<'a> {
|
||||||
pub fn new(path: &std::path::PathBuf) -> Self {
|
pub fn new(path: &std::path::PathBuf) -> Result<Self> {
|
||||||
let explorer = Explorer {
|
let explorer = Explorer {
|
||||||
root_path: path.to_owned(),
|
root_path: path.to_owned(),
|
||||||
tree_items: Self::build_tree_from_path(path.to_owned()),
|
tree_items: Self::build_tree_from_path(path.to_owned())?,
|
||||||
tree_state: TreeState::default(),
|
tree_state: TreeState::default(),
|
||||||
};
|
};
|
||||||
explorer
|
Ok(explorer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_tree_from_path(path: std::path::PathBuf) -> TreeItem<'static, String> {
|
fn build_tree_from_path(path: std::path::PathBuf) -> Result<TreeItem<'static, String>> {
|
||||||
let mut children = vec![];
|
let mut children = vec![];
|
||||||
if let Ok(entries) = fs::read_dir(&path) {
|
if let Ok(entries) = fs::read_dir(&path) {
|
||||||
let mut paths = entries
|
let mut paths = entries
|
||||||
.map(|res| res.map(|e| e.path()))
|
.map(|res| res.map(|e| e.path()))
|
||||||
.collect::<Result<Vec<_>, std::io::Error>>()
|
.collect::<Result<Vec<_>, std::io::Error>>()
|
||||||
.expect("");
|
.context(format!(
|
||||||
|
"Failed to build vector of paths under directory: {:?}",
|
||||||
|
path
|
||||||
|
))?;
|
||||||
paths.sort();
|
paths.sort();
|
||||||
for path in paths {
|
for path in paths {
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
children.push(Self::build_tree_from_path(path));
|
children.push(Self::build_tree_from_path(path)?);
|
||||||
} else {
|
} else {
|
||||||
if let Ok(path) = std::path::absolute(&path) {
|
if let Ok(path) = std::path::absolute(&path) {
|
||||||
let path_str = path.to_string_lossy().to_string();
|
let path_str = path.to_string_lossy().to_string();
|
||||||
children.push(TreeItem::new_leaf(
|
children.push(TreeItem::new_leaf(
|
||||||
path_str,
|
path_str,
|
||||||
path.file_name()
|
path.file_name()
|
||||||
.expect("Failed to get file name from path.")
|
.context("Failed to get file name from path.")?
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
));
|
));
|
||||||
@ -53,13 +56,10 @@ impl<'a> Explorer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let abs = std::path::absolute(&path)
|
let abs = std::path::absolute(&path)
|
||||||
.expect(
|
.context(format!(
|
||||||
format!(
|
"Failed to find absolute path for TreeItem: {:?}",
|
||||||
"Failed to find absolute path for TreeItem: {}",
|
path
|
||||||
path.to_string_lossy().to_string()
|
))?
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
)
|
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string();
|
.to_string();
|
||||||
TreeItem::new(
|
TreeItem::new(
|
||||||
@ -70,13 +70,13 @@ impl<'a> Explorer<'a> {
|
|||||||
.to_string(),
|
.to_string(),
|
||||||
children,
|
children,
|
||||||
)
|
)
|
||||||
.expect("Failed to build tree from path.")
|
.context("Failed to build tree from path.")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&mut self, area: Rect, buf: &mut Buffer) {
|
pub fn render(&mut self, area: Rect, buf: &mut Buffer) -> Result<()> {
|
||||||
StatefulWidget::render(
|
StatefulWidget::render(
|
||||||
Tree::new(&self.tree_items.children())
|
Tree::new(&self.tree_items.children())
|
||||||
.expect("Failed to build tree.")
|
.context("Failed to build file Explorer Tree.")?
|
||||||
.style(Style::default())
|
.style(Style::default())
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
@ -84,7 +84,7 @@ impl<'a> Explorer<'a> {
|
|||||||
.title(
|
.title(
|
||||||
self.root_path
|
self.root_path
|
||||||
.file_name()
|
.file_name()
|
||||||
.expect("Failed to get file name from path.")
|
.context("Failed to get file name from path.")?
|
||||||
.to_string_lossy(),
|
.to_string_lossy(),
|
||||||
)
|
)
|
||||||
.title_style(Style::default().fg(Color::Green))
|
.title_style(Style::default().fg(Color::Green))
|
||||||
@ -99,7 +99,8 @@ impl<'a> Explorer<'a> {
|
|||||||
area,
|
area,
|
||||||
buf,
|
buf,
|
||||||
&mut self.tree_state,
|
&mut self.tree_state,
|
||||||
)
|
);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn selected(&self) -> Result<String> {
|
pub fn selected(&self) -> Result<String> {
|
||||||
@ -114,24 +115,24 @@ impl<'a> Component for Explorer<'a> {
|
|||||||
fn id(&self) -> &str {
|
fn id(&self) -> &str {
|
||||||
"explorer"
|
"explorer"
|
||||||
}
|
}
|
||||||
fn handle_event(&mut self, event: Event) -> Action {
|
fn handle_event(&mut self, event: Event) -> Result<Action> {
|
||||||
if let Some(key_event) = event.as_key_event() {
|
if let Some(key_event) = event.as_key_event() {
|
||||||
// Handle events here that should not be passed on to the vim emulation handler.
|
// Handle events here that should not be passed on to the vim emulation handler.
|
||||||
match self.handle_key_events(key_event) {
|
match self.handle_key_events(key_event)? {
|
||||||
Action::Handled => return Action::Handled,
|
Action::Handled => return Ok(Action::Handled),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(mouse_event) = event.as_mouse_event() {
|
if let Some(mouse_event) = event.as_mouse_event() {
|
||||||
match self.handle_mouse_events(mouse_event) {
|
match self.handle_mouse_events(mouse_event)? {
|
||||||
Action::Handled => return Action::Handled,
|
Action::Handled => return Ok(Action::Handled),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::Pass
|
Ok(Action::Pass)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_key_events(&mut self, key: KeyEvent) -> Action {
|
fn handle_key_events(&mut self, key: KeyEvent) -> Result<Action> {
|
||||||
let changed = match key.code {
|
let changed = match key.code {
|
||||||
KeyCode::Up => self.tree_state.key_up(),
|
KeyCode::Up => self.tree_state.key_up(),
|
||||||
KeyCode::Char('k') => self.tree_state.key_up(),
|
KeyCode::Char('k') => self.tree_state.key_up(),
|
||||||
@ -145,12 +146,12 @@ impl<'a> Component for Explorer<'a> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if changed {
|
if changed {
|
||||||
return Action::Handled;
|
return Ok(Action::Handled);
|
||||||
}
|
}
|
||||||
Action::Noop
|
Ok(Action::Noop)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Action {
|
fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Result<Action> {
|
||||||
let changed = match mouse.kind {
|
let changed = match mouse.kind {
|
||||||
MouseEventKind::ScrollDown => self.tree_state.scroll_down(1),
|
MouseEventKind::ScrollDown => self.tree_state.scroll_down(1),
|
||||||
MouseEventKind::ScrollUp => self.tree_state.scroll_up(1),
|
MouseEventKind::ScrollUp => self.tree_state.scroll_up(1),
|
||||||
@ -160,8 +161,8 @@ impl<'a> Component for Explorer<'a> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if changed {
|
if changed {
|
||||||
return Action::Handled;
|
return Ok(Action::Handled);
|
||||||
}
|
}
|
||||||
Action::Noop
|
Ok(Action::Noop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user