terminal checkpoint before async

This commit is contained in:
Penwing 2024-01-24 13:26:52 +01:00
parent 0d38cd53fa
commit ec1b855686
7 changed files with 153 additions and 56 deletions

View file

@ -26,3 +26,9 @@ Added indent recognition (when there is a line break, the indentation level is k
Added testing Added testing
Added Ctrl+T : turn 4 spaces into tab across the whole document Added Ctrl+T : turn 4 spaces into tab across the whole document
Added Time debug Added Time debug
Added Tree toggle for performance
Added Alt+Arrows to move through tabs
Added Zoom
Added cd
Added terminal color

View file

@ -1 +1 @@
{"tabs":["/home/penwing/Documents/notes/victory2.txt"],"theme":6} {"tabs":["/home/penwing/Documents/notes/victory2.txt","/home/penwing/Documents/projects/rust/calcifer/src/calcifer/code_editor/themes/sonokai.rs"],"theme":4}

View file

@ -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 std::{env, path::Path, path::PathBuf, cmp::max, io, fs, cmp::min};
use crate::tools; use crate::tools;
use crate::TIME_LABELS; use crate::TIME_LABELS;
use crate::PATH_ROOT;
pub mod code_editor; pub mod code_editor;
use code_editor::CodeEditor; use code_editor::CodeEditor;
@ -16,6 +17,13 @@ impl super::Calcifer {
.resizable(false) .resizable(false)
.show(ctx, |ui| { .show(ctx, |ui| {
ui.horizontal(|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 "); ui.label("Theme ");
egui::ComboBox::from_label("") egui::ComboBox::from_label("")
.selected_text(format!("{}", self.theme.name)) .selected_text(format!("{}", self.theme.name))
@ -28,7 +36,9 @@ impl super::Calcifer {
}); });
ui.separator(); 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(); ui.separator();
if self.debug_display { if self.debug_display {
@ -44,15 +54,13 @@ impl super::Calcifer {
} }
pub fn draw_tree_panel(&mut self, ctx: &egui::Context) { pub fn draw_tree_panel(&mut self, ctx: &egui::Context) {
if !self.tree_display {
return
}
egui::SidePanel::left("file_tree_panel").show(ctx, |ui| { egui::SidePanel::left("file_tree_panel").show(ctx, |ui| {
ui.heading("Bookshelf"); 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(); ui.separator();
let _ = self.list_files(ui, Path::new("/home/penwing/Documents/")); let _ = self.list_files(ui, Path::new(&PATH_ROOT));
ui.separator(); ui.separator();
}); });
} }
@ -63,11 +71,15 @@ impl super::Calcifer {
.min_height(0.0) .min_height(0.0)
.show(ctx, |ui| { .show(ctx, |ui| {
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |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.label("");
ui.horizontal(|ui| { 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; 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)); 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)) { 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.horizontal_wrapped(|ui| {
ui.spacing_mut().item_spacing.y = 0.0; ui.spacing_mut().item_spacing.y = 0.0;
for entry in &self.command_history { 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(); ui.end_row();
if entry.output != "" { if entry.output != "" {
ui.label(&entry.output); ui.colored_label(entry_color, &entry.output);
ui.end_row(); ui.end_row();
} }
if entry.error != "" { if entry.error != "" {
@ -138,9 +150,16 @@ impl super::Calcifer {
pub fn draw_content_panel(&mut self, ctx: &egui::Context) { pub fn draw_content_panel(&mut self, ctx: &egui::Context) {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.horizontal(|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.label("Picked file:");
ui.monospace(self.tabs[self.selected_tab.to_index()].path.to_string_lossy().to_string()); ui.monospace(self.tabs[self.selected_tab.to_index()].path.to_string_lossy().to_string());
}); });
ui.separator();
if self.selected_tab == tools::TabNumber::None { if self.selected_tab == tools::TabNumber::None {
return return
@ -165,7 +184,7 @@ impl super::Calcifer {
CodeEditor::default().id_source("code editor") CodeEditor::default().id_source("code editor")
.with_rows(max(45,lines)) .with_rows(max(45,lines))
.with_fontsize(14.0) .with_fontsize(self.font_size)
.with_theme(self.theme) .with_theme(self.theme)
.with_syntax(tools::to_syntax(&current_tab.language)) .with_syntax(tools::to_syntax(&current_tab.language))
.with_numlines(true) .with_numlines(true)
@ -249,6 +268,15 @@ impl super::Calcifer {
current_tab.code = current_tab.code.replace(" ", "\t") 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<()> { fn list_files(&mut self, ui: &mut egui::Ui, path: &Path) -> io::Result<()> {
if let Some(name) = path.file_name() { if let Some(name) = path.file_name() {
if path.is_dir() { if path.is_dir() {
@ -300,4 +328,17 @@ impl super::Calcifer {
self.tabs.remove(index); self.tabs.remove(index);
return tools::TabNumber::from_index(min(index, self.tabs.len() - 1)) 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
}
} }

1
src/calcifer_save.json Normal file
View file

@ -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}

View file

@ -13,6 +13,7 @@ const RED : egui::Color32 = egui::Color32::from_rgb(235, 108, 99);
const SAVE_PATH : &str = "calcifer_save.json"; const SAVE_PATH : &str = "calcifer_save.json";
const TIME_LABELS : [&str; 5] = ["settings", "tree", "terminal", "tabs", "content"]; const TIME_LABELS : [&str; 5] = ["settings", "tree", "terminal", "tabs", "content"];
const MAX_FPS : f32 = 30.0; const MAX_FPS : f32 = 30.0;
const PATH_ROOT : &str = "/home/penwing/Documents/";
fn main() -> Result<(), eframe::Error> { fn main() -> Result<(), eframe::Error> {
@ -55,6 +56,7 @@ struct Calcifer {
command_history: Vec<tools::CommandEntry>, command_history: Vec<tools::CommandEntry>,
theme: ColorTheme, theme: ColorTheme,
font_size: f32,
search: tools::search::SearchWindow, search: tools::search::SearchWindow,
searching: bool, searching: bool,
@ -62,6 +64,8 @@ struct Calcifer {
debug_display: bool, debug_display: bool,
time_watch: Vec<f32>, time_watch: Vec<f32>,
next_frame: time::Instant, next_frame: time::Instant,
tree_display: bool,
} }
@ -75,6 +79,7 @@ impl Default for Calcifer {
command_history: Vec::new(), command_history: Vec::new(),
theme: DEFAULT_THEMES[0], theme: DEFAULT_THEMES[0],
font_size: 14.0,
search: tools::search::SearchWindow::default(), search: tools::search::SearchWindow::default(),
searching: false, searching: false,
@ -82,6 +87,8 @@ impl Default for Calcifer {
debug_display: false, debug_display: false,
time_watch: vec![0.0; TIME_LABELS.len()], time_watch: vec![0.0; TIME_LABELS.len()],
next_frame: time::Instant::now(), next_frame: time::Instant::now(),
tree_display: false,
} }
} }
} }
@ -94,18 +101,34 @@ impl eframe::App for Calcifer {
let mut watch = time::Instant::now(); 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) { if ctx.input( |i| i.key_pressed(egui::Key::T) && i.modifiers.ctrl) {
self.indent_with_tabs(); 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) { if ctx.input( |i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl && i.modifiers.shift) {
self.handle_save_file(self.save_tab_as()); 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) { if ctx.input( |i| i.key_pressed(egui::Key::F) && i.modifiers.ctrl) {
self.searching = !self.searching.clone(); self.searching = !self.searching.clone();
if self.searching { if self.searching {

View file

@ -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 crate::calcifer::code_editor::Syntax;
use eframe::egui; use eframe::egui;
use egui::text_edit::CCursorRange; use egui::text_edit::CCursorRange;
@ -179,6 +179,17 @@ pub fn to_syntax(language : &str) -> Syntax {
pub fn run_command(cmd : String) -> CommandEntry { pub fn run_command(cmd : String) -> CommandEntry {
let mut entry = CommandEntry::default(); let mut entry = CommandEntry::default();
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") let output = Command::new("sh")
.arg("-c") .arg("-c")
.arg(cmd.clone()) .arg(cmd.clone())
@ -188,6 +199,7 @@ pub fn run_command(cmd : String) -> CommandEntry {
entry.command = cmd; entry.command = cmd;
entry.output = (&String::from_utf8_lossy(&output.stdout)).to_string(); entry.output = (&String::from_utf8_lossy(&output.stdout)).to_string();
entry.error = (&String::from_utf8_lossy(&output.stderr)).to_string(); entry.error = (&String::from_utf8_lossy(&output.stderr)).to_string();
}
entry 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::<Vec<_>>().join("/"))
}
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

View file

@ -227,10 +227,9 @@ impl SearchWindow {
self.search(tabs, selected_tab); self.search(tabs, selected_tab);
} }
println!("trying to replace {} with {}", self.search_text, self.replace_text);
for element in &self.results { 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()].code = tabs[element.tab.to_index()].code.replace(&self.search_text, &self.replace_text);
tabs[element.tab.to_index()].saved = false;
} }
} }
} }