TUI #1
@ -1,11 +1,12 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use cxx_qt_lib::QString;
|
use cxx_qt_lib::QString;
|
||||||
|
use log::trace;
|
||||||
|
|
||||||
pub mod colors;
|
pub mod colors;
|
||||||
pub mod filesystem;
|
pub mod filesystem;
|
||||||
|
|
||||||
pub fn run(root_path: std::path::PathBuf) -> Result<()> {
|
pub fn run(root_path: std::path::PathBuf) -> Result<()> {
|
||||||
println!("Starting the GUI editor at {:?}", root_path);
|
trace!(target:"gui::run()", "Starting the GUI editor at {root_path:?}");
|
||||||
|
|
||||||
use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl};
|
use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl};
|
||||||
|
|
||||||
|
|||||||
@ -73,10 +73,10 @@ impl qobject::FileSystem {
|
|||||||
return QString::default();
|
return QString::default();
|
||||||
}
|
}
|
||||||
if !fs::metadata(path.to_string())
|
if !fs::metadata(path.to_string())
|
||||||
.expect(format!("Failed to get file metadata {}", path).as_str())
|
.expect(format!("Failed to get file metadata {path:?}").as_str())
|
||||||
.is_file()
|
.is_file()
|
||||||
{
|
{
|
||||||
warn!("Attempted to open file {} that is not a valid file", path);
|
warn!(target:"FileSystem", "Attempted to open file {path:?} that is not a valid file");
|
||||||
return QString::default();
|
return QString::default();
|
||||||
}
|
}
|
||||||
let ss = SyntaxSet::load_defaults_nonewlines();
|
let ss = SyntaxSet::load_defaults_nonewlines();
|
||||||
@ -118,7 +118,7 @@ impl qobject::FileSystem {
|
|||||||
fn set_directory(self: std::pin::Pin<&mut Self>, path: &QString) -> QModelIndex {
|
fn set_directory(self: std::pin::Pin<&mut Self>, path: &QString) -> QModelIndex {
|
||||||
if !path.is_empty()
|
if !path.is_empty()
|
||||||
&& fs::metadata(path.to_string())
|
&& fs::metadata(path.to_string())
|
||||||
.expect(format!("Failed to get metadata for path {}", path).as_str())
|
.expect(format!("Failed to get metadata for path {path:?}").as_str())
|
||||||
.is_dir()
|
.is_dir()
|
||||||
{
|
{
|
||||||
self.set_root_path(path)
|
self.set_root_path(path)
|
||||||
|
|||||||
19
src/main.rs
19
src/main.rs
@ -1,10 +1,8 @@
|
|||||||
|
use crate::tui::Tui;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use ratatui::Terminal;
|
use log::{info, trace};
|
||||||
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;
|
||||||
@ -39,14 +37,21 @@ fn main() -> Result<()> {
|
|||||||
dirs::home_dir().context("Failed to obtain home directory")?,
|
dirs::home_dir().context("Failed to obtain home directory")?,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
info!(target:"main()", "Root path detected: {root_path:?}");
|
||||||
|
|
||||||
match args.gui {
|
match args.gui {
|
||||||
true => gui::run(root_path),
|
true => {
|
||||||
|
trace!(target:"main()", "Starting GUI");
|
||||||
|
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::new(root_path)?.start()?),
|
true => {
|
||||||
|
trace!(target:"main()", "Starting TUI");
|
||||||
|
Ok(Tui::new(root_path)?.start()?)
|
||||||
|
}
|
||||||
false => {
|
false => {
|
||||||
// Relaunch the CLIDE GUI in a separate process.
|
trace!(target:"main()", "Starting GUI in a new process");
|
||||||
Command::new(std::env::current_exe()?)
|
Command::new(std::env::current_exe()?)
|
||||||
.args(&["--gui", root_path.to_str().unwrap()])
|
.args(&["--gui", root_path.to_str().unwrap()])
|
||||||
.stdout(Stdio::null())
|
.stdout(Stdio::null())
|
||||||
|
|||||||
@ -5,7 +5,7 @@ mod explorer;
|
|||||||
mod logger;
|
mod logger;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use log::{LevelFilter, debug};
|
use log::{LevelFilter, debug, info};
|
||||||
use ratatui::Terminal;
|
use ratatui::Terminal;
|
||||||
use ratatui::backend::CrosstermBackend;
|
use ratatui::backend::CrosstermBackend;
|
||||||
use ratatui::crossterm::event::{
|
use ratatui::crossterm::event::{
|
||||||
@ -38,7 +38,7 @@ impl Tui {
|
|||||||
.output_file(false)
|
.output_file(false)
|
||||||
.output_separator(':');
|
.output_separator(':');
|
||||||
set_log_file(file_options);
|
set_log_file(file_options);
|
||||||
debug!(target:"Tui", "Logging to file: {}", dir.to_str().unwrap());
|
debug!(target:"Tui", "Logging to file: {dir:?}");
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
terminal: Terminal::new(CrosstermBackend::new(stdout()))?,
|
terminal: Terminal::new(CrosstermBackend::new(stdout()))?,
|
||||||
@ -47,7 +47,7 @@ impl Tui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(self) -> Result<()> {
|
pub fn start(self) -> Result<()> {
|
||||||
println!("Starting the TUI editor at {:?}", self.root_path);
|
info!(target:"Tui", "Starting the TUI editor at {:?}", self.root_path);
|
||||||
ratatui::crossterm::execute!(
|
ratatui::crossterm::execute!(
|
||||||
stdout(),
|
stdout(),
|
||||||
EnterAlternateScreen,
|
EnterAlternateScreen,
|
||||||
@ -64,6 +64,7 @@ impl Tui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn stop() -> Result<()> {
|
fn stop() -> Result<()> {
|
||||||
|
info!(target:"Tui", "Stopping the TUI editor");
|
||||||
disable_raw_mode()?;
|
disable_raw_mode()?;
|
||||||
ratatui::crossterm::execute!(
|
ratatui::crossterm::execute!(
|
||||||
stdout(),
|
stdout(),
|
||||||
|
|||||||
@ -2,14 +2,14 @@ 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 crate::tui::logger::Logger;
|
use crate::tui::logger::Logger;
|
||||||
use anyhow::{Context, Result, anyhow, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
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};
|
||||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||||
use ratatui::prelude::{Color, Style, Widget};
|
use ratatui::prelude::{Color, Style, Widget};
|
||||||
use ratatui::widgets::{Block, Borders, Padding, Paragraph, Tabs, Wrap};
|
use ratatui::widgets::{Block, Borders, Padding, Tabs};
|
||||||
use ratatui::{DefaultTerminal, symbols};
|
use ratatui::{DefaultTerminal, symbols};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -27,56 +27,11 @@ pub enum AppComponents<'a> {
|
|||||||
/// Usage: get_component_mut::<Editor>() OR get_component::<Editor>()
|
/// Usage: get_component_mut::<Editor>() OR get_component::<Editor>()
|
||||||
///
|
///
|
||||||
/// Implementing this trait for each AppComponent allows for easy lookup in the vector.
|
/// Implementing this trait for each AppComponent allows for easy lookup in the vector.
|
||||||
trait ComponentOf<T> {
|
pub(crate) trait ComponentOf<T> {
|
||||||
fn as_ref(&self) -> Option<&T>;
|
fn as_ref(&self) -> Option<&T>;
|
||||||
fn as_mut(&mut self) -> Option<&mut T>;
|
fn as_mut(&mut self) -> Option<&mut T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ComponentOf<Logger> for AppComponents<'a> {
|
|
||||||
fn as_ref(&self) -> Option<&Logger> {
|
|
||||||
if let AppComponents::AppLogger(ref e) = *self {
|
|
||||||
return Some(e);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
fn as_mut(&mut self) -> Option<&mut Logger> {
|
|
||||||
if let AppComponents::AppLogger(ref mut e) = *self {
|
|
||||||
return Some(e);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ComponentOf<Editor> for AppComponents<'a> {
|
|
||||||
fn as_ref(&self) -> Option<&Editor> {
|
|
||||||
if let AppComponents::AppEditor(ref e) = *self {
|
|
||||||
return Some(e);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
fn as_mut(&mut self) -> Option<&mut Editor> {
|
|
||||||
if let AppComponents::AppEditor(ref mut e) = *self {
|
|
||||||
return Some(e);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ComponentOf<Explorer<'a>> for AppComponents<'a> {
|
|
||||||
fn as_ref(&self) -> Option<&Explorer<'a>> {
|
|
||||||
if let AppComponents::AppExplorer(ref e) = *self {
|
|
||||||
return Some(e);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
fn as_mut(&mut self) -> Option<&mut Explorer<'a>> {
|
|
||||||
if let AppComponents::AppExplorer(ref mut e) = *self {
|
|
||||||
return Some(e);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct App<'a> {
|
pub struct App<'a> {
|
||||||
components: Vec<AppComponents<'a>>,
|
components: Vec<AppComponents<'a>>,
|
||||||
}
|
}
|
||||||
@ -94,8 +49,7 @@ impl<'a> App<'a> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.set_contents(&root_path.join("src/tui/app.rs"))
|
.set_contents(&root_path.join("src/tui/app.rs"))
|
||||||
.context(format!(
|
.context(format!(
|
||||||
"Failed to initialize editor contents to path: {}",
|
"Failed to initialize editor contents to path: {root_path:?}"
|
||||||
root_path.to_string_lossy()
|
|
||||||
))?;
|
))?;
|
||||||
Ok(app)
|
Ok(app)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::tui::component::{Action, Component};
|
use crate::tui::component::{Action, Component};
|
||||||
|
|
||||||
|
use crate::tui::app::{AppComponents, ComponentOf};
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
use edtui::{
|
use edtui::{
|
||||||
EditorEventHandler, EditorState, EditorTheme, EditorView, LineNumbers, Lines, SyntaxHighlighter,
|
EditorEventHandler, EditorState, EditorTheme, EditorView, LineNumbers, Lines, SyntaxHighlighter,
|
||||||
@ -22,6 +23,21 @@ pub struct Editor {
|
|||||||
syntax_set: SyntaxSet,
|
syntax_set: SyntaxSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ComponentOf<Editor> for AppComponents<'a> {
|
||||||
|
fn as_ref(&self) -> Option<&Editor> {
|
||||||
|
if let AppComponents::AppEditor(ref e) = *self {
|
||||||
|
return Some(e);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn as_mut(&mut self) -> Option<&mut Editor> {
|
||||||
|
if let AppComponents::AppEditor(ref mut e) = *self {
|
||||||
|
return Some(e);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Editor {
|
Editor {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::tui::app::{AppComponents, ComponentOf};
|
||||||
use crate::tui::component::{Action, Component};
|
use crate::tui::component::{Action, Component};
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
use ratatui::buffer::Buffer;
|
use ratatui::buffer::Buffer;
|
||||||
@ -16,6 +17,21 @@ pub struct Explorer<'a> {
|
|||||||
tree_state: TreeState<String>,
|
tree_state: TreeState<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ComponentOf<Explorer<'a>> for AppComponents<'a> {
|
||||||
|
fn as_ref(&self) -> Option<&Explorer<'a>> {
|
||||||
|
if let AppComponents::AppExplorer(ref e) = *self {
|
||||||
|
return Some(e);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn as_mut(&mut self) -> Option<&mut Explorer<'a>> {
|
||||||
|
if let AppComponents::AppExplorer(ref mut e) = *self {
|
||||||
|
return Some(e);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Explorer<'a> {
|
impl<'a> Explorer<'a> {
|
||||||
pub fn new(path: &std::path::PathBuf) -> Result<Self> {
|
pub fn new(path: &std::path::PathBuf) -> Result<Self> {
|
||||||
let explorer = Explorer {
|
let explorer = Explorer {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::tui::app::{AppComponents, ComponentOf};
|
||||||
use crate::tui::component::{Action, Component};
|
use crate::tui::component::{Action, Component};
|
||||||
use ratatui::buffer::Buffer;
|
use ratatui::buffer::Buffer;
|
||||||
use ratatui::crossterm::event::{Event, KeyCode, KeyEvent};
|
use ratatui::crossterm::event::{Event, KeyCode, KeyEvent};
|
||||||
@ -12,6 +13,21 @@ pub struct Logger {
|
|||||||
state: TuiWidgetState,
|
state: TuiWidgetState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ComponentOf<Logger> for AppComponents<'a> {
|
||||||
|
fn as_ref(&self) -> Option<&Logger> {
|
||||||
|
if let AppComponents::AppLogger(ref e) = *self {
|
||||||
|
return Some(e);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn as_mut(&mut self) -> Option<&mut Logger> {
|
||||||
|
if let AppComponents::AppLogger(ref mut e) = *self {
|
||||||
|
return Some(e);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Logger {
|
impl Logger {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user