From ec1b855686ba2fcc4cd354d6baf1681e062c0f86 Mon Sep 17 00:00:00 2001 From: Penwing Date: Wed, 24 Jan 2024 13:26:52 +0100 Subject: [PATCH] terminal checkpoint before async --- README.md | 8 ++++- calcifer_save.json | 2 +- src/calcifer.rs | 71 +++++++++++++++++++++++++++++++++--------- src/calcifer_save.json | 1 + src/main.rs | 31 +++++++++++++++--- src/tools/mod.rs | 47 ++++++++++++++++++++++------ src/tools/search.rs | 49 ++++++++++++++--------------- 7 files changed, 153 insertions(+), 56 deletions(-) create mode 100644 src/calcifer_save.json diff --git a/README.md b/README.md index 01f6a3f..874e4cb 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,10 @@ Added indent recognition (when there is a line break, the indentation level is k # 1.0.3 : Added testing Added Ctrl+T : turn 4 spaces into tab across the whole document -Added Time debug \ No newline at end of file +Added Time debug +Added Tree toggle for performance +Added Alt+Arrows to move through tabs +Added Zoom +Added cd +Added terminal color + diff --git a/calcifer_save.json b/calcifer_save.json index d227408..19fa8a3 100644 --- a/calcifer_save.json +++ b/calcifer_save.json @@ -1 +1 @@ -{"tabs":["/home/penwing/Documents/notes/victory2.txt"],"theme":6} \ No newline at end of file +{"tabs":["/home/penwing/Documents/notes/victory2.txt","/home/penwing/Documents/projects/rust/calcifer/src/calcifer/code_editor/themes/sonokai.rs"],"theme":4} \ No newline at end of file diff --git a/src/calcifer.rs b/src/calcifer.rs index 1bdc140..a16a679 100644 --- a/src/calcifer.rs +++ b/src/calcifer.rs @@ -3,6 +3,7 @@ use egui::{text::CCursor, text_edit::CCursorRange}; use std::{env, path::Path, path::PathBuf, cmp::max, io, fs, cmp::min}; use crate::tools; use crate::TIME_LABELS; +use crate::PATH_ROOT; pub mod code_editor; use code_editor::CodeEditor; @@ -16,6 +17,13 @@ impl super::Calcifer { .resizable(false) .show(ctx, |ui| { ui.horizontal(|ui| { + if ui.add(egui::Button::new("open file")).clicked() { + if let Some(path) = rfd::FileDialog::new().set_directory(Path::new(&PATH_ROOT)).pick_file() { + self.selected_tab = self.open_file(&path); + } + } + ui.separator(); + ui.label("Theme "); egui::ComboBox::from_label("") .selected_text(format!("{}", self.theme.name)) @@ -28,15 +36,17 @@ impl super::Calcifer { }); ui.separator(); - ui.checkbox(&mut self.debug_display, "Debug display"); + self.tree_display = self.toggle(ui, self.tree_display, "Tree"); + ui.separator(); + self.debug_display = self.toggle(ui, self.debug_display, "Debug"); ui.separator(); if self.debug_display { let combined_string: Vec = TIME_LABELS.into_iter().zip(self.time_watch.clone().into_iter()) - .map(|(s, v)| format!("{} : {:.1} ms", s, v)).collect(); + .map(|(s, v)| format!("{} : {:.1} ms", s, v)).collect(); - let mut result = combined_string.join(" ; "); - result.push_str(&format!(" total : {:.1}", self.time_watch.clone().iter().sum::())); + let mut result = combined_string.join(" ; "); + result.push_str(&format!(" total : {:.1}", self.time_watch.clone().iter().sum::())); ui.label(result); } }); @@ -44,15 +54,13 @@ impl super::Calcifer { } pub fn draw_tree_panel(&mut self, ctx: &egui::Context) { + if !self.tree_display { + return + } egui::SidePanel::left("file_tree_panel").show(ctx, |ui| { ui.heading("Bookshelf"); - if ui.add(egui::Button::new("open file")).clicked() { - if let Some(path) = rfd::FileDialog::new().pick_file() { - self.selected_tab = self.open_file(&path); - } - } ui.separator(); - let _ = self.list_files(ui, Path::new("/home/penwing/Documents/")); + let _ = self.list_files(ui, Path::new(&PATH_ROOT)); ui.separator(); }); } @@ -63,11 +71,15 @@ impl super::Calcifer { .min_height(0.0) .show(ctx, |ui| { ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| { + let command_color = egui::Color32::from_hex(self.theme.functions).expect("Theme color issue (functions)"); + let entry_color = egui::Color32::from_hex(self.theme.literals).expect("Theme color issue (literals)"); + let bg_color = egui::Color32::from_hex(self.theme.bg).expect("Theme color issue (bg)"); + ui.label(""); ui.horizontal(|ui| { - ui.style_mut().visuals.extreme_bg_color = egui::Color32::from_hex(self.theme.bg).expect("Could not convert color"); + ui.style_mut().visuals.extreme_bg_color = bg_color; let Self { command, .. } = self; - ui.label(format!("{}>", env::current_dir().expect("Could not find Shell Environnment").file_name().expect("Could not get Shell Environnment Name").to_string_lossy().to_string())); + ui.colored_label(command_color.clone(), tools::format_path(&env::current_dir().expect("Could not find Shell Environnment"), 2)); let response = ui.add(egui::TextEdit::singleline(command).desired_width(f32::INFINITY).lock_focus(true)); if response.lost_focus() && ctx.input(|i| i.key_pressed(egui::Key::Enter)) { @@ -83,10 +95,10 @@ impl super::Calcifer { ui.horizontal_wrapped(|ui| { ui.spacing_mut().item_spacing.y = 0.0; for entry in &self.command_history { - ui.label(format!("{}> {}", entry.env, entry.command)); + ui.colored_label(command_color, format!("{}> {}", entry.env, entry.command)); ui.end_row(); if entry.output != "" { - ui.label(&entry.output); + ui.colored_label(entry_color, &entry.output); ui.end_row(); } if entry.error != "" { @@ -138,9 +150,16 @@ impl super::Calcifer { pub fn draw_content_panel(&mut self, ctx: &egui::Context) { egui::CentralPanel::default().show(ctx, |ui| { ui.horizontal(|ui| { + if ui.add(egui::Button::new("open in terminal")).clicked() { + let mut path = self.tabs[self.selected_tab.to_index()].path.clone(); + path.pop(); + tools::run_command(format!("cd {}", path.display())); + } + ui.label("Picked file:"); ui.monospace(self.tabs[self.selected_tab.to_index()].path.to_string_lossy().to_string()); }); + ui.separator(); if self.selected_tab == tools::TabNumber::None { return @@ -165,7 +184,7 @@ impl super::Calcifer { CodeEditor::default().id_source("code editor") .with_rows(max(45,lines)) - .with_fontsize(14.0) + .with_fontsize(self.font_size) .with_theme(self.theme) .with_syntax(tools::to_syntax(¤t_tab.language)) .with_numlines(true) @@ -249,6 +268,15 @@ impl super::Calcifer { current_tab.code = current_tab.code.replace(" ", "\t") } + pub fn move_through_tabs(&mut self, forward : bool) { + let new_index = if forward { + (self.selected_tab.to_index() + 1) % self.tabs.len() + } else { + self.selected_tab.to_index().checked_sub(1).unwrap_or(self.tabs.len() - 1) + }; + self.selected_tab = tools::TabNumber::from_index(new_index); + } + fn list_files(&mut self, ui: &mut egui::Ui, path: &Path) -> io::Result<()> { if let Some(name) = path.file_name() { if path.is_dir() { @@ -300,4 +328,17 @@ impl super::Calcifer { self.tabs.remove(index); return tools::TabNumber::from_index(min(index, self.tabs.len() - 1)) } + + fn toggle(&self, ui: &mut egui::Ui, display : bool, title : &str) -> bool { + let text = if display.clone() { + format!("hide {}", title) + } else { + format!("show {}", title) + }; + + if ui.add(egui::Button::new(text)).clicked() { + return !display + } + return display + } } diff --git a/src/calcifer_save.json b/src/calcifer_save.json new file mode 100644 index 0000000..1336658 --- /dev/null +++ b/src/calcifer_save.json @@ -0,0 +1 @@ +{"tabs":["/home/penwing/Documents/notes/victory2.txt","/home/penwing/Documents/projects/rust/calcifer/src/calcifer/code_editor/themes/sonokai.rs"],"theme":6} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 45cd18b..69776c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ const RED : egui::Color32 = egui::Color32::from_rgb(235, 108, 99); const SAVE_PATH : &str = "calcifer_save.json"; const TIME_LABELS : [&str; 5] = ["settings", "tree", "terminal", "tabs", "content"]; const MAX_FPS : f32 = 30.0; +const PATH_ROOT : &str = "/home/penwing/Documents/"; fn main() -> Result<(), eframe::Error> { @@ -55,6 +56,7 @@ struct Calcifer { command_history: Vec, theme: ColorTheme, + font_size: f32, search: tools::search::SearchWindow, searching: bool, @@ -62,6 +64,8 @@ struct Calcifer { debug_display: bool, time_watch: Vec, next_frame: time::Instant, + + tree_display: bool, } @@ -75,6 +79,7 @@ impl Default for Calcifer { command_history: Vec::new(), theme: DEFAULT_THEMES[0], + font_size: 14.0, search: tools::search::SearchWindow::default(), searching: false, @@ -82,6 +87,8 @@ impl Default for Calcifer { debug_display: false, time_watch: vec![0.0; TIME_LABELS.len()], next_frame: time::Instant::now(), + + tree_display: false, } } } @@ -94,17 +101,33 @@ impl eframe::App for Calcifer { let mut watch = time::Instant::now(); - if ctx.input( |i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) { - self.handle_save_file(self.save_tab()); - } - if ctx.input( |i| i.key_pressed(egui::Key::T) && i.modifiers.ctrl) { self.indent_with_tabs(); } + if ctx.input( |i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) { + self.handle_save_file(self.save_tab()); + } + if ctx.input( |i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl && i.modifiers.shift) { self.handle_save_file(self.save_tab_as()); } + + if ctx.input( |i| i.key_pressed(egui::Key::ArrowLeft) && i.modifiers.alt) { + self.move_through_tabs(false); + } + + if ctx.input( |i| i.key_pressed(egui::Key::ArrowRight) && i.modifiers.alt) { + self.move_through_tabs(true); + } + + if ctx.input( |i| i.zoom_delta() > 1.0) { + self.font_size = (self.font_size * 1.1).min(30.0); + } + + if ctx.input( |i| i.zoom_delta() < 1.0) { + self.font_size = (self.font_size / 1.1).max(10.0); + } if ctx.input( |i| i.key_pressed(egui::Key::F) && i.modifiers.ctrl) { self.searching = !self.searching.clone(); diff --git a/src/tools/mod.rs b/src/tools/mod.rs index cee1314..cac2d08 100644 --- a/src/tools/mod.rs +++ b/src/tools/mod.rs @@ -1,4 +1,4 @@ -use std::{process::Command, cmp::Ordering, env, path::PathBuf, fs::read_to_string, fs::write}; +use std::{env, process::Command, cmp::Ordering, path::PathBuf, path::Path, fs::read_to_string, fs::write, path::Component, ffi::OsStr}; use crate::calcifer::code_editor::Syntax; use eframe::egui; use egui::text_edit::CCursorRange; @@ -179,15 +179,27 @@ pub fn to_syntax(language : &str) -> Syntax { pub fn run_command(cmd : String) -> CommandEntry { let mut entry = CommandEntry::default(); - let output = Command::new("sh") - .arg("-c") - .arg(cmd.clone()) - .output() - .expect("failed to execute process"); - - entry.command = cmd; - entry.output = (&String::from_utf8_lossy(&output.stdout)).to_string(); - entry.error = (&String::from_utf8_lossy(&output.stderr)).to_string(); + if &cmd[..2] == "cd" { + let path_append = cmd[3..].replace("~", "/home/penwing"); + let path = Path::new(&path_append); + entry.command = cmd; + + if format!("{}", path.display()) != "/" { + if !env::set_current_dir(path).is_ok() { + entry.error = format!("Could not find path : {}", path.display()); + } + } + } else { + let output = Command::new("sh") + .arg("-c") + .arg(cmd.clone()) + .output() + .expect("failed to execute process"); + + entry.command = cmd; + entry.output = (&String::from_utf8_lossy(&output.stdout)).to_string(); + entry.error = (&String::from_utf8_lossy(&output.stderr)).to_string(); + } entry } @@ -209,5 +221,20 @@ pub fn sort_directories_first(a: &std::fs::DirEntry, b: &std::fs::DirEntry) -> O } +pub fn format_path(path: &Path, n_parents: usize) -> String { + let components: Vec<&OsStr> = path + .components() + .rev() + .take(n_parents + 1) // Take up to three components (root, parent, file/folder) + .filter_map(|component| match component { + Component::RootDir | Component::CurDir => None, + _ => Some(component.as_os_str()), + }) + .collect(); + + format!("{}>", components.iter().rev().map(|&c| c.to_string_lossy()).collect::>().join("/")) +} + + #[cfg(test)] mod tests; \ No newline at end of file diff --git a/src/tools/search.rs b/src/tools/search.rs index 25c1bf4..1b56ea6 100644 --- a/src/tools/search.rs +++ b/src/tools/search.rs @@ -33,7 +33,7 @@ impl Default for Selection { pub struct SearchWindow { - search_text: String, + search_text: String, searched_text: String, replace_text: String, @@ -50,9 +50,9 @@ pub struct SearchWindow { impl Default for SearchWindow { - fn default() -> Self { - Self { - search_text: "".into(), + fn default() -> Self { + Self { + search_text: "".into(), searched_text: "".into(), replace_text: "".into(), @@ -65,29 +65,29 @@ impl Default for SearchWindow { tab_selected: true, result_selected: true, - } - } + } + } } impl Demo for SearchWindow { - fn name(&self) -> &str { //'static - "Search" - } + fn name(&self) -> &str { //'static + "Search" + } - fn show(&mut self, ctx: &egui::Context, open: &mut bool, tabs: &mut Vec, selected_tab: &mut TabNumber) { - egui::Window::new(self.name()) - .open(open) - .vscroll(true) - .hscroll(true) - .show(ctx, |ui| self.ui(ui, tabs, selected_tab)); - } + fn show(&mut self, ctx: &egui::Context, open: &mut bool, tabs: &mut Vec, selected_tab: &mut TabNumber) { + egui::Window::new(self.name()) + .open(open) + .vscroll(true) + .hscroll(true) + .show(ctx, |ui| self.ui(ui, tabs, selected_tab)); + } } impl View for SearchWindow { - fn ui(&mut self, ui: &mut egui::Ui, tabs: &mut Vec, selected_tab: &mut TabNumber) { - ui.set_min_width(250.0); + fn ui(&mut self, ui: &mut egui::Ui, tabs: &mut Vec, selected_tab: &mut TabNumber) { + ui.set_min_width(250.0); let mut action : Action = Action::None; @@ -128,9 +128,9 @@ impl View for SearchWindow { self.searched_text = "".into(); } - egui::CollapsingHeader::new("Replace") - .default_open(false) - .show(ui, |ui| { + egui::CollapsingHeader::new("Replace") + .default_open(false) + .show(ui, |ui| { ui.horizontal(|ui| { let Self { replace_text, .. } = self; ui.add(egui::TextEdit::singleline(replace_text).desired_width(120.0).lock_focus(true)); @@ -138,7 +138,7 @@ impl View for SearchWindow { action = Action::Replace; } }); - }); + }); match action { Action::Update => self.search(tabs, selected_tab), @@ -147,7 +147,7 @@ impl View for SearchWindow { Action::Replace => self.replace(tabs, selected_tab), Action::None => (), } - } + } } impl SearchWindow { @@ -227,10 +227,9 @@ impl SearchWindow { self.search(tabs, selected_tab); } - println!("trying to replace {} with {}", self.search_text, self.replace_text); - for element in &self.results { tabs[element.tab.to_index()].code = tabs[element.tab.to_index()].code.replace(&self.search_text, &self.replace_text); + tabs[element.tab.to_index()].saved = false; } } } \ No newline at end of file