···1515 #[arg(short, long, value_name = "FLOAT", default_value_t = 60.0)]
1616 pub frame_rate: f64,
17171818+ /// Open the visualizer along with the tui
1919+ #[arg(short, long, default_value_t = false)]
2020+ pub visualizer: bool,
2121+1822 #[command(subcommand)]
1923 pub command: Option<Commands>,
2024}
+4-1
src/components/mod.rs
src/tui/components/mod.rs
···55};
66use tokio::sync::mpsc::UnboundedSender;
7788-use crate::{config::Config, signal::Signal, tui::Event};
88+use crate::{
99+ config::Config,
1010+ tui::{Event, Signal},
1111+};
9121013/// `Component` is a trait that represents a visual and interactive element of the user interface.
1114///
···11+use std::{
22+ process,
33+ sync::{
44+ Arc,
55+ atomic::{AtomicBool, Ordering},
66+ },
77+};
88+99+use eframe::egui;
1010+1111+/// The `Filaments Visualizer`, which is an instance of `eframe`, which uses `egui`
1212+#[derive(Default)]
1313+pub struct FilViz {
1414+ shutdown_signal: Arc<AtomicBool>,
1515+ /// example for now
1616+ text: String,
1717+}
1818+1919+impl FilViz {
2020+ /// Create a new instance of the `FiLViz`
2121+ const fn new(_cc: &eframe::CreationContext<'_>, shutdown_signal: Arc<AtomicBool>) -> Self {
2222+ // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_global_style.
2323+ // Restore app state using cc.storage (requires the "persistence" feature).
2424+ // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use
2525+ // for e.g. egui::PaintCallback.
2626+ Self {
2727+ shutdown_signal,
2828+ text: String::new(),
2929+ }
3030+ }
3131+3232+ /// Create and run the `FilViz`.
3333+ pub fn run(shutdown_signal: Arc<AtomicBool>) -> color_eyre::Result<()> {
3434+ let native_options = eframe::NativeOptions::default();
3535+ eframe::run_native(
3636+ "Filaments Visualizer",
3737+ native_options,
3838+ Box::new(|cc| Ok(Box::new(Self::new(cc, shutdown_signal)))),
3939+ )?;
4040+4141+ Ok(())
4242+ }
4343+}
4444+4545+impl eframe::App for FilViz {
4646+ fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
4747+ if self.shutdown_signal.load(Ordering::Relaxed) {
4848+ process::exit(0)
4949+ }
5050+5151+ egui::CentralPanel::default().show_inside(ui, |ui| {
5252+ ui.heading("Hello World!");
5353+ ui.text_edit_singleline(&mut self.text);
5454+ });
5555+ }
5656+}
+4-5
src/keymap.rs
src/tui/keymap.rs
···11-use std::{
22- collections::HashMap,
11+use std::{ collections::HashMap,
32 ops::{Deref, DerefMut},
43};
54···76use kdl::KdlNode;
87use strum::IntoEnumIterator;
981010-use crate::{app::Region, signal::Signal};
99+use crate::tui::{Signal, app::Region};
11101211#[derive(Debug, Clone)]
1312pub struct KeyMap(pub HashMap<Region, HashMap<Vec<KeyEvent>, Signal>>);
···173172 use crossterm::event::{KeyEvent, KeyModifiers};
174173 use kdl::KdlNode;
175174176176- use crate::{keymap::KeyMap, signal::Signal};
175175+ use crate::tui::{KeyMap, Signal, app::Region};
177176178177 #[test]
179178 fn test_quit_in_home_region() {
···193192 let keymap: KeyMap = kdl.try_into().expect("Must be a valid keymap");
194193195194 let map = keymap
196196- .get(&crate::app::Region::Home)
195195+ .get(&Region::Home)
197196 .expect("Home region must exist in keymap");
198197199198 let signal = map
+39-14
src/main.rs
···22//! My (suri.codes) personal-knowledge-system, with deeply integrated task tracking and long term goal planning capabilities.
33//!
4455-use crate::{app::App, cli::Cli};
55+use std::sync::{
66+ Arc,
77+ atomic::{AtomicBool, Ordering},
88+};
99+1010+use crate::{cli::Cli, gui::FilViz, tui::TuiApp};
611use clap::Parser;
71288-mod app;
913mod cli;
1010-mod components;
1414+mod gui;
1515+mod tui;
1616+1117mod config;
1218mod errors;
1313-mod keymap;
1419mod logging;
1515-mod signal;
1616-mod tui;
17201818-#[tokio::main]
1919-async fn main() -> color_eyre::Result<()> {
2121+fn main() -> color_eyre::Result<()> {
2022 errors::init()?;
2123 logging::init()?;
22242325 let args = Cli::parse();
24262525- // if there is any subcommand, we want to execute that, otherwise we
2626- // just run the app
2727+ // create a new tokio runtime, shared behind arc
2828+ let rt = Arc::new(tokio::runtime::Runtime::new()?);
2929+3030+ // if there are any commands, run those and exit
2731 if let Some(command) = args.command {
2828- return command.process();
3232+ return rt.block_on(async { command.process() });
2933 }
30343131- // if no command we run the app
3535+ let shutdown_signal = Arc::new(AtomicBool::new(false));
32363333- let mut app = App::new(args.tick_rate, args.frame_rate)?;
3434- app.run().await?;
3737+ // then we spawn the tui on its own thread
3838+ let tui_handle = std::thread::spawn({
3939+ let tui_rt = rt.clone();
4040+ let shutdown = shutdown_signal.clone();
4141+ move || -> color_eyre::Result<()> {
4242+ // block the tui on the same runtime as above
4343+ tui_rt.block_on(async {
4444+ let mut tui = TuiApp::new(args.tick_rate, args.frame_rate)?;
4545+ tui.run().await?;
4646+ shutdown.store(true, Ordering::Relaxed);
4747+ Ok(())
4848+ })
4949+ }
5050+ });
35515252+ // if they asked for the visualizer, we give them the visualizer
5353+ if args.visualizer {
5454+ // enter the guard so egui_async works properly
5555+ let _rt_guard = rt.enter();
5656+ FilViz::run(shutdown_signal)?;
5757+ }
5858+5959+ // join on the tui
6060+ tui_handle.join().unwrap()?;
3661 Ok(())
3762}
+3
src/signal.rs
src/tui/signal.rs
···1717 ClearScreen,
1818 Error(String),
1919 Help,
2020+ /// this is fucking temporary
2121+ Helix,
2022}
21232224impl FromStr for Signal {
···2729 "suspend" => Self::Suspend,
2830 "resume" => Self::Resume,
2931 "quit" => Self::Quit,
3232+ "helix" => Self::Helix,
3033 _ => {
3134 return Err(eyre!(format!(
3235 "Attempt to construct a non-user Signal from str: {s}"
src/tui.rs
src/tui/raw_tui.rs
+19
src/tui/mod.rs
···11+/// The tui app
22+mod app;
33+pub use app::App as TuiApp;
44+55+/// Tui components
66+mod components;
77+88+/// Raw tui abstraction
99+mod raw_tui;
1010+pub use raw_tui::Event;
1111+pub use raw_tui::Tui;
1212+1313+/// Keymap for mapping keybinds to regions
1414+mod keymap;
1515+pub use keymap::KeyMap;
1616+1717+/// Singals for commands needing to be processed
1818+mod signal;
1919+pub use signal::Signal;