Pass application context to GUI. #11
@ -30,7 +30,7 @@ impl Cli {
|
|||||||
self.tui.then(|| modes.push(RunMode::Tui));
|
self.tui.then(|| modes.push(RunMode::Tui));
|
||||||
self.gui.then(|| modes.push(RunMode::GuiAttached));
|
self.gui.then(|| modes.push(RunMode::GuiAttached));
|
||||||
match &modes[..] {
|
match &modes[..] {
|
||||||
[] => Ok(RunMode::Tui),
|
[] => Ok(RunMode::Gui),
|
||||||
[mode] => Ok(*mode),
|
[mode] => Ok(*mode),
|
||||||
multiple => Err(anyhow!(
|
multiple => Err(anyhow!(
|
||||||
"More than one run mode found {multiple:?} please select one."
|
"More than one run mode found {multiple:?} please select one."
|
||||||
|
|||||||
@ -7,6 +7,7 @@ mod explorer;
|
|||||||
mod logger;
|
mod logger;
|
||||||
mod menu_bar;
|
mod menu_bar;
|
||||||
|
|
||||||
|
use crate::AppContext;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use log::{LevelFilter, debug, info, trace};
|
use log::{LevelFilter, debug, info, trace};
|
||||||
use ratatui::Terminal;
|
use ratatui::Terminal;
|
||||||
@ -22,7 +23,6 @@ use std::io::{Stdout, stdout};
|
|||||||
use tui_logger::{
|
use tui_logger::{
|
||||||
TuiLoggerFile, TuiLoggerLevelOutput, init_logger, set_default_level, set_log_file,
|
TuiLoggerFile, TuiLoggerLevelOutput, init_logger, set_default_level, set_log_file,
|
||||||
};
|
};
|
||||||
use crate::AppContext;
|
|
||||||
|
|
||||||
struct Tui {
|
struct Tui {
|
||||||
terminal: Terminal<CrosstermBackend<Stdout>>,
|
terminal: Terminal<CrosstermBackend<Stdout>>,
|
||||||
|
|||||||
@ -17,7 +17,7 @@ use ratatui::crossterm::event::{
|
|||||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||||
use ratatui::prelude::{Color, Widget};
|
use ratatui::prelude::{Color, Widget};
|
||||||
use ratatui::widgets::{Paragraph, Wrap};
|
use ratatui::widgets::{Paragraph, Wrap};
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
@ -286,8 +286,8 @@ impl<'a> Component for App<'a> {
|
|||||||
},
|
},
|
||||||
Action::OpenTab => {
|
Action::OpenTab => {
|
||||||
if let Ok(path) = self.explorer.selected() {
|
if let Ok(path) = self.explorer.selected() {
|
||||||
let path_buf = PathBuf::from(path);
|
let path_buf = Path::new(&path);
|
||||||
self.editor_tab.open_tab(&path_buf)?;
|
self.editor_tab.open_tab(path_buf)?;
|
||||||
Ok(Action::Handled)
|
Ok(Action::Handled)
|
||||||
} else {
|
} else {
|
||||||
Ok(Action::Noop)
|
Ok(Action::Noop)
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
|
|||||||
use ratatui::layout::{Alignment, Rect};
|
use ratatui::layout::{Alignment, Rect};
|
||||||
use ratatui::prelude::{Color, Style};
|
use ratatui::prelude::{Color, Style};
|
||||||
use ratatui::widgets::{Block, Borders, Padding, Widget};
|
use ratatui::widgets::{Block, Borders, Padding, Widget};
|
||||||
|
use std::path::PathBuf;
|
||||||
use syntect::parsing::SyntaxSet;
|
use syntect::parsing::SyntaxSet;
|
||||||
|
|
||||||
pub struct Editor {
|
pub struct Editor {
|
||||||
@ -22,7 +23,7 @@ pub struct Editor {
|
|||||||
impl Editor {
|
impl Editor {
|
||||||
pub const ID: &str = "Editor";
|
pub const ID: &str = "Editor";
|
||||||
|
|
||||||
pub fn new(path: &std::path::PathBuf) -> Self {
|
pub fn new(path: &std::path::Path) -> Self {
|
||||||
trace!(target:Self::ID, "Building {}", Self::ID);
|
trace!(target:Self::ID, "Building {}", Self::ID);
|
||||||
Editor {
|
Editor {
|
||||||
state: EditorState::default(),
|
state: EditorState::default(),
|
||||||
@ -47,14 +48,14 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_contents(&mut self, path: &std::path::PathBuf) -> Result<()> {
|
pub fn set_contents(&mut self, path: &std::path::Path) -> Result<()> {
|
||||||
trace!(target:Self::ID, "Setting Editor contents from path {:?}", path);
|
trace!(target:Self::ID, "Setting Editor contents from path {:?}", path);
|
||||||
if let Ok(contents) = std::fs::read_to_string(path) {
|
if let Ok(contents) = std::fs::read_to_string(path) {
|
||||||
let lines: Vec<_> = contents
|
let lines: Vec<_> = contents
|
||||||
.lines()
|
.lines()
|
||||||
.map(|line| line.chars().collect::<Vec<char>>())
|
.map(|line| line.chars().collect::<Vec<char>>())
|
||||||
.collect();
|
.collect();
|
||||||
self.file_path = Some(path.clone());
|
self.file_path = Some(PathBuf::from(path));
|
||||||
self.state.lines = Lines::new(lines);
|
self.state.lines = Lines::new(lines);
|
||||||
self.state.cursor.row = 0;
|
self.state.cursor.row = 0;
|
||||||
self.state.cursor.col = 0;
|
self.state.cursor.col = 0;
|
||||||
@ -84,7 +85,7 @@ impl Widget for &mut Editor {
|
|||||||
.syntax_set
|
.syntax_set
|
||||||
.find_syntax_by_extension(lang)
|
.find_syntax_by_extension(lang)
|
||||||
.map(|s| s.name.to_string())
|
.map(|s| s.name.to_string())
|
||||||
.unwrap_or("Unknown".to_string());
|
.unwrap_or_else(|| String::from("Unknown"));
|
||||||
|
|
||||||
EditorView::new(&mut self.state)
|
EditorView::new(&mut self.state)
|
||||||
.wrap(true)
|
.wrap(true)
|
||||||
|
|||||||
@ -103,7 +103,7 @@ impl EditorTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_tab(&mut self, path: &std::path::PathBuf) -> Result<()> {
|
pub fn open_tab(&mut self, path: &std::path::Path) -> Result<()> {
|
||||||
trace!(target:Self::ID, "Opening new EditorTab with path {:?}", path);
|
trace!(target:Self::ID, "Opening new EditorTab with path {:?}", path);
|
||||||
if self
|
if self
|
||||||
.editors
|
.editors
|
||||||
@ -130,9 +130,7 @@ impl EditorTab {
|
|||||||
let key = self
|
let key = self
|
||||||
.tab_order
|
.tab_order
|
||||||
.get(index)
|
.get(index)
|
||||||
.ok_or(anyhow!(
|
.ok_or_else(|| anyhow!("Failed to get tab order with invalid index {index}"))?
|
||||||
"Failed to get tab order with invalid index {index}"
|
|
||||||
))?
|
|
||||||
.to_owned();
|
.to_owned();
|
||||||
match self.editors.remove(&key) {
|
match self.editors.remove(&key) {
|
||||||
None => {
|
None => {
|
||||||
@ -155,10 +153,10 @@ impl EditorTab {
|
|||||||
// TODO: Only file name is displayed in tab title, so files with the same name in different
|
// TODO: Only file name is displayed in tab title, so files with the same name in different
|
||||||
// directories will appear confusing.
|
// directories will appear confusing.
|
||||||
let tab_titles = self.tab_order.iter().map(|t| {
|
let tab_titles = self.tab_order.iter().map(|t| {
|
||||||
std::path::PathBuf::from(t)
|
std::path::Path::new(t)
|
||||||
.file_name()
|
.file_name()
|
||||||
.map(|f| f.to_string_lossy().to_string())
|
.map(|f| f.to_string_lossy().to_string())
|
||||||
.unwrap_or("Unknown".to_string())
|
.unwrap_or_else(|| String::from("Unknown"))
|
||||||
});
|
});
|
||||||
// Don't set border color based on ComponentState::focus, the Editor renders the border.
|
// Don't set border color based on ComponentState::focus, the Editor renders the border.
|
||||||
Tabs::new(tab_titles)
|
Tabs::new(tab_titles)
|
||||||
|
|||||||
@ -7,8 +7,9 @@ use ratatui::layout::{Alignment, Position, Rect};
|
|||||||
use ratatui::prelude::Style;
|
use ratatui::prelude::Style;
|
||||||
use ratatui::style::{Color, Modifier};
|
use ratatui::style::{Color, Modifier};
|
||||||
use ratatui::widgets::{Block, Borders, StatefulWidget, Widget};
|
use ratatui::widgets::{Block, Borders, StatefulWidget, Widget};
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use tui_tree_widget::{Tree, TreeItem, TreeState};
|
use tui_tree_widget::{Tree, TreeItem, TreeState};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -97,7 +98,10 @@ impl<'a> Explorer<'a> {
|
|||||||
impl<'a> Widget for &mut Explorer<'a> {
|
impl<'a> Widget for &mut Explorer<'a> {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
if let Ok(tree) = Tree::new(&self.tree_items.children()) {
|
if let Ok(tree) = Tree::new(&self.tree_items.children()) {
|
||||||
let file_name = self.root_path.file_name().unwrap_or("Unknown".as_ref());
|
let file_name = self
|
||||||
|
.root_path
|
||||||
|
.file_name()
|
||||||
|
.unwrap_or_else(|| OsStr::new("Unknown"));
|
||||||
StatefulWidget::render(
|
StatefulWidget::render(
|
||||||
tree.block(
|
tree.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
@ -143,7 +147,7 @@ impl<'a> Component for Explorer<'a> {
|
|||||||
fn handle_key_events(&mut self, key: KeyEvent) -> Result<Action> {
|
fn handle_key_events(&mut self, key: KeyEvent) -> Result<Action> {
|
||||||
if key.code == KeyCode::Enter {
|
if key.code == KeyCode::Enter {
|
||||||
if let Ok(selected) = self.selected() {
|
if let Ok(selected) = self.selected() {
|
||||||
if PathBuf::from(&selected).is_file() {
|
if Path::new(&selected).is_file() {
|
||||||
return Ok(Action::OpenTab);
|
return Ok(Action::OpenTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user