cleaned up

This commit is contained in:
Penwing 2024-01-28 00:29:18 +01:00
parent 899ebf37b0
commit 96d803a870
6 changed files with 586 additions and 578 deletions

View file

@ -1,6 +1,6 @@
use eframe::egui; use eframe::egui;
use egui::{text::CCursor, text_edit::CCursorRange, Rangef}; use egui::{text::CCursor, text_edit::CCursorRange, Rangef};
use std::{cmp::max, env, path::PathBuf};// path::Path, use std::{cmp::max, env, path::PathBuf}; // path::Path,
use crate::tools; use crate::tools;
use crate::Calcifer; use crate::Calcifer;
@ -14,288 +14,291 @@ use code_editor::CodeEditor;
mod app_base; mod app_base;
impl Calcifer { impl Calcifer {
pub fn draw_settings(&mut self, ctx: &egui::Context) { pub fn draw_settings(&mut self, ctx: &egui::Context) {
egui::SidePanel::left("settings") egui::SidePanel::left("settings")
.resizable(false) .resizable(false)
.exact_width(self.font_size * 1.8) .exact_width(self.font_size * 1.8)
.show(ctx, |ui| { .show(ctx, |ui| {
ui.vertical(|ui| { ui.vertical(|ui| {
if ui.add(egui::Button::new("📁")).clicked() { if ui.add(egui::Button::new("📁")).clicked() {
if let Some(path) = rfd::FileDialog::new() if let Some(path) = rfd::FileDialog::new()
.set_directory(self.home.as_path()) .set_directory(self.home.as_path())
.pick_file() .pick_file()
{ {
self.open_file(Some(&path)); self.open_file(Some(&path));
} }
} }
ui.separator(); ui.separator();
self.tree_visible = self.toggle(ui, self.tree_visible, "🗐"); self.tree_visible = self.toggle(ui, self.tree_visible, "🗐");
ui.separator(); ui.separator();
self.terminal_visible = self.toggle(ui, self.terminal_visible, "🖵"); self.terminal_visible = self.toggle(ui, self.terminal_visible, "🖵");
ui.separator(); ui.separator();
self.search_menu.visible = self.toggle(ui, self.search_menu.visible, "🔍"); self.search_menu.visible = self.toggle(ui, self.search_menu.visible, "🔍");
ui.separator(); ui.separator();
self.settings_menu.visible = self.toggle(ui, self.settings_menu.visible, ""); self.settings_menu.visible = self.toggle(ui, self.settings_menu.visible, "");
ui.separator(); ui.separator();
self.shortcuts_menu.visible = self.toggle(ui, self.shortcuts_menu.visible, ""); self.shortcuts_menu.visible = self.toggle(ui, self.shortcuts_menu.visible, "");
ui.separator(); ui.separator();
self.profiler_visible = self.toggle(ui, self.profiler_visible, ""); self.profiler_visible = self.toggle(ui, self.profiler_visible, "");
if self.tabs[self.selected_tab.to_index()].language == PROJECT_EXTENSION { if self.tabs[self.selected_tab.to_index()].language == PROJECT_EXTENSION {
ui.separator(); ui.separator();
self.project_mode = self.toggle(ui, self.project_mode, "🛠"); self.project_mode = self.toggle(ui, self.project_mode, "🛠");
} }
}); });
}); });
} }
pub fn draw_tree_panel(&mut self, ctx: &egui::Context) { pub fn draw_tree_panel(&mut self, ctx: &egui::Context) {
if !self.tree_visible { if !self.tree_visible {
return; return;
} }
egui::SidePanel::left("file_tree_panel").show(ctx, |ui| { egui::SidePanel::left("file_tree_panel").show(ctx, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("Bookshelf "); ui.label("Bookshelf ");
if ui.add(egui::Button::new("📖")).clicked() { if ui.add(egui::Button::new("📖")).clicked() {
self.file_tree = tools::file_tree::generate_file_tree(self.home.as_path(), 7); self.file_tree = tools::file_tree::generate_file_tree(self.home.as_path(), 7);
} }
}); });
ui.separator(); ui.separator();
let mut n_files : usize = 0; let mut n_files: usize = 0;
if let Some(file_tree) = self.file_tree.clone() { if let Some(file_tree) = self.file_tree.clone() {
self.list_files(ui, &file_tree, 1, &mut n_files); self.list_files(ui, &file_tree, 1, &mut n_files);
} else { } else {
ui.label("No book on the Bookshelf"); ui.label("No book on the Bookshelf");
} }
ui.separator(); ui.separator();
ui.label(format!("{} files displayed", n_files)); ui.label(format!("{} files displayed", n_files));
}); });
} }
pub fn draw_bottom_tray(&mut self, ctx: &egui::Context) { pub fn draw_bottom_tray(&mut self, ctx: &egui::Context) {
egui::TopBottomPanel::bottom("tray") egui::TopBottomPanel::bottom("tray")
.default_height(self.font_size * 1.2) .default_height(self.font_size * 1.2)
.resizable(false) .resizable(false)
.show(ctx, |ui| { .show(ctx, |ui| {
ui.label(self.profiler()); ui.label(self.profiler());
}); });
} }
pub fn draw_terminal_panel(&mut self, ctx: &egui::Context) { pub fn draw_terminal_panel(&mut self, ctx: &egui::Context) {
if !self.terminal_visible { if !self.terminal_visible {
return; return;
} }
egui::TopBottomPanel::bottom("terminal") egui::TopBottomPanel::bottom("terminal")
.default_height(super::TERMINAL_HEIGHT) .default_height(super::TERMINAL_HEIGHT)
.height_range(Rangef::new( .height_range(Rangef::new(
super::TERMINAL_RANGE.start, super::TERMINAL_RANGE.start,
super::TERMINAL_RANGE.end, super::TERMINAL_RANGE.end,
)) ))
.resizable(true) .resizable(true)
.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 = hex_str_to_color(self.theme.functions); let command_color = hex_str_to_color(self.theme.functions);
let entry_color = hex_str_to_color(self.theme.literals); let entry_color = hex_str_to_color(self.theme.literals);
let bg_color = hex_str_to_color(self.theme.bg); let bg_color = hex_str_to_color(self.theme.bg);
ui.label(""); ui.label("");
ui.horizontal(|ui| { ui.horizontal(|ui| {
if ui.add(egui::Button::new("")).clicked() { if ui.add(egui::Button::new("")).clicked() {
self.command_history = vec![]; self.command_history = vec![];
} }
ui.style_mut().visuals.extreme_bg_color = bg_color; ui.style_mut().visuals.extreme_bg_color = bg_color;
let Self { command, .. } = self; let Self { command, .. } = self;
ui.colored_label( ui.colored_label(
command_color, command_color,
tools::format_path( tools::format_path(
&env::current_dir().unwrap_or_else(|_| PathBuf::from("/")), &env::current_dir().unwrap_or_else(|_| PathBuf::from("/")),
), ),
); );
let response = ui.add( let response = ui.add(
egui::TextEdit::singleline(command) egui::TextEdit::singleline(command)
.desired_width(f32::INFINITY) .desired_width(f32::INFINITY)
.lock_focus(true), .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)) {
self.command_history self.command_history
.push(tools::send_command(self.command.clone())); .push(tools::send_command(self.command.clone()));
self.command = "".into(); self.command = "".into();
response.request_focus(); response.request_focus();
} }
}); });
ui.separator(); ui.separator();
egui::ScrollArea::vertical() egui::ScrollArea::vertical()
.stick_to_bottom(true) .stick_to_bottom(true)
.show(ui, |ui| { .show(ui, |ui| {
ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| { ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| {
ui.separator(); ui.separator();
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 &mut self.command_history { for entry in &mut self.command_history {
entry.update(); entry.update();
ui.colored_label( ui.colored_label(
command_color, command_color,
format!("\n{} {}", entry.env, entry.command), format!("\n{} {}", entry.env, entry.command),
); );
ui.end_row(); ui.end_row();
for line in &entry.result { for line in &entry.result {
let color = let color =
if line.error { super::RED } else { entry_color }; if line.error { super::RED } else { entry_color };
ui.colored_label(color, &line.text); ui.colored_label(color, &line.text);
ui.end_row(); ui.end_row();
} }
} }
}); });
}); });
}); });
}); });
}); });
} }
pub fn draw_tab_panel(&mut self, ctx: &egui::Context) { pub fn draw_tab_panel(&mut self, ctx: &egui::Context) {
egui::TopBottomPanel::top("tabs") egui::TopBottomPanel::top("tabs")
.resizable(false) .resizable(false)
.show(ctx, |ui| { .show(ctx, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.style_mut().visuals.selection.bg_fill = ui.style_mut().visuals.selection.bg_fill =
hex_str_to_color(self.theme.functions); hex_str_to_color(self.theme.functions);
ui.style_mut().visuals.hyperlink_color = hex_str_to_color(self.theme.functions); ui.style_mut().visuals.hyperlink_color = hex_str_to_color(self.theme.functions);
for (index, tab) in self.tabs.clone().iter().enumerate() { for (index, tab) in self.tabs.clone().iter().enumerate() {
let mut title = tab.get_name(); let mut title = tab.get_name();
if !tab.saved { if !tab.saved {
title += " ~"; title += " ~";
} }
if self.selected_tab == tools::TabNumber::from_index(index) { if self.selected_tab == tools::TabNumber::from_index(index) {
ui.style_mut().visuals.override_text_color = ui.style_mut().visuals.override_text_color =
Some(hex_str_to_color(self.theme.bg)); Some(hex_str_to_color(self.theme.bg));
} }
ui.selectable_value( ui.selectable_value(
&mut self.selected_tab, &mut self.selected_tab,
tools::TabNumber::from_index(index), tools::TabNumber::from_index(index),
title, title,
); );
ui.style_mut().visuals.override_text_color = None; ui.style_mut().visuals.override_text_color = None;
if ui.link("X").clicked() && !self.close_tab_confirm.visible { if ui.link("X").clicked() && !self.close_tab_confirm.visible {
if self.tabs.len() > 1 { if self.tabs.len() > 1 {
if tab.saved { if tab.saved {
self.delete_tab(index); self.delete_tab(index);
} else { } else {
self.close_tab_confirm.ask(); self.close_tab_confirm.ask();
self.tab_to_close = index; self.tab_to_close = index;
} }
} else { } else {
egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::Close); egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::Close);
} }
} }
ui.separator(); ui.separator();
} }
if self.tabs.len() < MAX_TABS { if self.tabs.len() < MAX_TABS {
ui.selectable_value(&mut self.selected_tab, tools::TabNumber::Open, "+"); ui.selectable_value(&mut self.selected_tab, tools::TabNumber::Open, "+");
} }
if self.selected_tab == tools::TabNumber::Open { if self.selected_tab == tools::TabNumber::Open {
self.open_file(None); self.open_file(None);
} }
}); });
}); });
} }
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 directory in terminal")).clicked() { if ui
let mut path = self.tabs[self.selected_tab.to_index()].path.clone(); .add(egui::Button::new("open directory in terminal"))
path.pop(); .clicked()
tools::send_command(format!("cd {}", path.display())); {
} let mut path = self.tabs[self.selected_tab.to_index()].path.clone();
path.pop();
tools::send_command(format!("cd {}", path.display()));
}
ui.label("Picked file:"); ui.label("Picked file:");
ui.monospace( ui.monospace(
self.tabs[self.selected_tab.to_index()] self.tabs[self.selected_tab.to_index()]
.path .path
.to_string_lossy() .to_string_lossy()
.to_string(), .to_string(),
); );
}); });
ui.separator(); ui.separator();
if self.project_mode if self.project_mode
&& self.tabs[self.selected_tab.to_index()].language == PROJECT_EXTENSION && self.tabs[self.selected_tab.to_index()].language == PROJECT_EXTENSION
{ {
self.draw_project_file(ui); self.draw_project_file(ui);
} else { } else {
self.draw_code_file(ui); self.draw_code_file(ui);
} }
}); });
} }
fn draw_code_file(&mut self, ui: &mut egui::Ui) { fn draw_code_file(&mut self, ui: &mut egui::Ui) {
let current_tab = &mut self.tabs[self.selected_tab.to_index()]; let current_tab = &mut self.tabs[self.selected_tab.to_index()];
let lines = current_tab.code.chars().filter(|&c| c == '\n').count() + 1; let lines = current_tab.code.chars().filter(|&c| c == '\n').count() + 1;
let mut override_cursor: Option<CCursorRange> = None; let mut override_cursor: Option<CCursorRange> = None;
if !self.search_menu.result_selected { if !self.search_menu.result_selected {
override_cursor = Some(CCursorRange::two( override_cursor = Some(CCursorRange::two(
CCursor::new(self.search_menu.get_cursor_start()), CCursor::new(self.search_menu.get_cursor_start()),
CCursor::new(self.search_menu.get_cursor_end()), CCursor::new(self.search_menu.get_cursor_end()),
)); ));
self.search_menu.result_selected = true; self.search_menu.result_selected = true;
} }
CodeEditor::default() CodeEditor::default()
.id_source("code editor") .id_source("code editor")
.with_rows(max(45, lines)) .with_rows(max(45, lines))
.with_fontsize(self.font_size) .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)
.show( .show(
ui, ui,
&mut current_tab.code, &mut current_tab.code,
&mut current_tab.saved, &mut current_tab.saved,
&mut current_tab.last_cursor, &mut current_tab.last_cursor,
&mut current_tab.scroll_offset, &mut current_tab.scroll_offset,
override_cursor, override_cursor,
); );
} }
fn draw_project_file(&mut self, ui: &mut egui::Ui) { fn draw_project_file(&mut self, ui: &mut egui::Ui) {
ui.label("project mode"); ui.label("project mode");
} }
pub fn draw_windows(&mut self, ctx: &egui::Context) { pub fn draw_windows(&mut self, ctx: &egui::Context) {
if self.search_menu.visible { if self.search_menu.visible {
self.search_menu self.search_menu
.show(ctx, &mut self.tabs, &mut self.selected_tab); .show(ctx, &mut self.tabs, &mut self.selected_tab);
} }
if self.close_tab_confirm.visible { if self.close_tab_confirm.visible {
self.close_tab_confirm.show(ctx); self.close_tab_confirm.show(ctx);
} }
if self.refresh_confirm.visible { if self.refresh_confirm.visible {
self.refresh_confirm.show(ctx); self.refresh_confirm.show(ctx);
} }
if self.exit_confirm.visible { if self.exit_confirm.visible {
self.exit_confirm.show(ctx); self.exit_confirm.show(ctx);
} }
if self.exit_confirm.proceed { if self.exit_confirm.proceed {
for tab in self.tabs.iter_mut() { for tab in self.tabs.iter_mut() {
tab.saved = true; tab.saved = true;
} }
egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::Close); egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::Close);
} }
if self.shortcuts_menu.visible { if self.shortcuts_menu.visible {
self.shortcuts_menu.show(ctx); self.shortcuts_menu.show(ctx);
} }
if self.settings_menu.visible { if self.settings_menu.visible {
self.settings_menu.show(ctx); self.settings_menu.show(ctx);
} }
if self.settings_menu.updated { if self.settings_menu.updated {
self.theme = self.settings_menu.theme; self.theme = self.settings_menu.theme;
} }
self.handle_confirm(); self.handle_confirm();
} }
} }

View file

@ -2,14 +2,14 @@ use eframe::egui;
use egui::Color32; use egui::Color32;
use std::{cmp::min, fs, path::Path, path::PathBuf}; use std::{cmp::min, fs, path::Path, path::PathBuf};
use crate::save_path;
use crate::tools; use crate::tools;
use crate::Calcifer; use crate::Calcifer;
use crate::DEFAULT_THEMES; use crate::DEFAULT_THEMES;
use crate::MAX_TABS; use crate::MAX_TABS;
use crate::TIME_LABELS; use crate::TIME_LABELS;
use crate::save_path;
use tools::hex_str_to_color;
use tools::file_tree; use tools::file_tree;
use tools::hex_str_to_color;
impl Calcifer { impl Calcifer {
pub fn handle_confirm(&mut self) { pub fn handle_confirm(&mut self) {
@ -123,7 +123,7 @@ impl Calcifer {
} }
pub fn open_file(&mut self, path_option: Option<&Path>) { pub fn open_file(&mut self, path_option: Option<&Path>) {
if let Some(path) = path_option.clone() { if let Some(path) = path_option {
for (index, tab) in self.tabs.clone().iter().enumerate() { for (index, tab) in self.tabs.clone().iter().enumerate() {
if tab.path == path { if tab.path == path {
self.selected_tab = tools::TabNumber::from_index(index); self.selected_tab = tools::TabNumber::from_index(index);
@ -186,7 +186,13 @@ impl Calcifer {
result result
} }
pub fn list_files(&mut self, ui: &mut egui::Ui, file: &file_tree::File, depth: isize, n_files: &mut usize) { pub fn list_files(
&mut self,
ui: &mut egui::Ui,
file: &file_tree::File,
depth: isize,
n_files: &mut usize,
) {
*n_files += 1; *n_files += 1;
if let Some(folder_content) = &file.folder_content { if let Some(folder_content) = &file.folder_content {
@ -194,23 +200,19 @@ impl Calcifer {
.default_open(depth > 0) .default_open(depth > 0)
.show(ui, |ui| { .show(ui, |ui| {
if !self.tree_dir_opened.contains(&file.name) { if !self.tree_dir_opened.contains(&file.name) {
return return;
} }
for deeper_file in folder_content { for deeper_file in folder_content {
self.list_files(ui, &deeper_file, depth - 1, n_files); self.list_files(ui, deeper_file, depth - 1, n_files);
} }
}); });
if collapsing_response.fully_closed() { if collapsing_response.fully_closed() {
self.tree_dir_opened.retain(|s| s != &file.name); self.tree_dir_opened.retain(|s| s != &file.name);
} else { } else if !self.tree_dir_opened.contains(&file.name) {
if !self.tree_dir_opened.contains(&file.name) { self.tree_dir_opened.push(file.name.clone());
self.tree_dir_opened.push(file.name.clone());
}
}
} else {
if ui.button(&file.name).clicked() {
self.open_file(Some(&file.path));
} }
} else if ui.button(&file.name).clicked() {
self.open_file(Some(&file.path));
} }
} }
} }

View file

@ -6,8 +6,8 @@ use eframe::egui;
use egui::FontFamily::Proportional; use egui::FontFamily::Proportional;
use egui::FontId; use egui::FontId;
use egui::TextStyle::{Body, Button, Heading, Monospace, Small}; use egui::TextStyle::{Body, Button, Heading, Monospace, Small};
use std::{ops::Range, path::PathBuf, sync::Arc, thread, time};
use homedir::get_my_home; use homedir::get_my_home;
use std::{ops::Range, path::PathBuf, sync::Arc, thread, time};
use calcifer::code_editor::themes::DEFAULT_THEMES; use calcifer::code_editor::themes::DEFAULT_THEMES;
@ -17,248 +17,257 @@ const TITLE: &str = " debug";
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
const TITLE: &str = ""; const TITLE: &str = "";
const ALLOWED_FILE_EXTENSIONS: [&str; 6] = ["", "rs", "toml", "txt", "project", "sh"];
const ALLOWED_FILE_EXTENSIONS: [&str; 6] = [
"", "rs", "toml", "txt", "project", "sh",
];
const PROJECT_EXTENSION: &str = "project"; const PROJECT_EXTENSION: &str = "project";
const TERMINAL_HEIGHT: f32 = 200.0; const TERMINAL_HEIGHT: f32 = 200.0;
const TERMINAL_RANGE: Range<f32> = 100.0..500.0; const TERMINAL_RANGE: Range<f32> = 100.0..500.0;
const RED: egui::Color32 = egui::Color32::from_rgb(235, 108, 99); const RED: egui::Color32 = egui::Color32::from_rgb(235, 108, 99);
const TIME_LABELS: [&str; 7] = [ const TIME_LABELS: [&str; 7] = [
"input", "settings", "tree", "terminal", "tabs", "content", "windows", "input", "settings", "tree", "terminal", "tabs", "content", "windows",
]; ];
const MAX_FPS: f32 = 30.0; const MAX_FPS: f32 = 30.0;
const DISPLAY_PATH_DEPTH: usize = 3; const DISPLAY_PATH_DEPTH: usize = 3;
const MAX_TABS: usize = 20; const MAX_TABS: usize = 20;
fn main() -> Result<(), eframe::Error> { fn main() -> Result<(), eframe::Error> {
let icon_data = tools::load_icon().unwrap_or_default(); let icon_data = tools::load_icon().unwrap_or_default();
let options = eframe::NativeOptions { let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default() viewport: egui::ViewportBuilder::default()
.with_inner_size([1200.0, 800.0]) .with_inner_size([1200.0, 800.0])
.with_icon(Arc::new(icon_data)), .with_icon(Arc::new(icon_data)),
..Default::default() ..Default::default()
}; };
// Attempt to load previous state // Attempt to load previous state
let app_state: tools::AppState = if save_path().exists() { let app_state: tools::AppState = if save_path().exists() {
match tools::load_state(save_path().as_path()) { match tools::load_state(save_path().as_path()) {
Ok(app_state) => app_state, Ok(app_state) => app_state,
Err(_) => tools::AppState::default(), Err(_) => tools::AppState::default(),
} }
} else { } else {
tools::AppState::default() tools::AppState::default()
}; };
eframe::run_native( eframe::run_native(
&format!("Calcifer{}", TITLE), &format!("Calcifer{}", TITLE),
options, options,
Box::new(move |_cc| Box::from(Calcifer::from_app_state(app_state))), Box::new(move |_cc| Box::from(Calcifer::from_app_state(app_state))),
) )
} }
struct Calcifer { struct Calcifer {
selected_tab: tools::TabNumber, selected_tab: tools::TabNumber,
tabs: Vec<tools::Tab>, tabs: Vec<tools::Tab>,
command: String, command: String,
command_history: Vec<tools::CommandEntry>, command_history: Vec<tools::CommandEntry>,
theme: ColorTheme, theme: ColorTheme,
font_size: f32, font_size: f32,
project_mode: bool, project_mode: bool,
home: PathBuf, home: PathBuf,
tree_dir_opened: Vec<String>, tree_dir_opened: Vec<String>,
file_tree: Option<tools::file_tree::File>, file_tree: Option<tools::file_tree::File>,
tree_visible: bool, tree_visible: bool,
profiler_visible: bool, profiler_visible: bool,
terminal_visible: bool, terminal_visible: bool,
close_tab_confirm: tools::confirm::ConfirmWindow, close_tab_confirm: tools::confirm::ConfirmWindow,
tab_to_close: usize, tab_to_close: usize,
refresh_confirm: tools::confirm::ConfirmWindow, refresh_confirm: tools::confirm::ConfirmWindow,
exit_confirm: tools::confirm::ConfirmWindow, exit_confirm: tools::confirm::ConfirmWindow,
search_menu: tools::search::SearchWindow, search_menu: tools::search::SearchWindow,
settings_menu: tools::settings::SettingsWindow, settings_menu: tools::settings::SettingsWindow,
shortcuts_menu: tools::shortcuts::ShortcutsWindow, shortcuts_menu: tools::shortcuts::ShortcutsWindow,
time_watch: Vec<f32>, time_watch: Vec<f32>,
next_frame: time::Instant, next_frame: time::Instant,
} }
impl Default for Calcifer { impl Default for Calcifer {
fn default() -> Self { fn default() -> Self {
Self { Self {
selected_tab: tools::TabNumber::from_index(0), selected_tab: tools::TabNumber::from_index(0),
tabs: vec![tools::Tab::default()], tabs: vec![tools::Tab::default()],
command: String::new(), command: String::new(),
command_history: Vec::new(), command_history: Vec::new(),
theme: DEFAULT_THEMES[0], theme: DEFAULT_THEMES[0],
font_size: 14.0, font_size: 14.0,
project_mode: true, project_mode: true,
home: get_my_home().unwrap().unwrap(), home: get_my_home().unwrap().unwrap(),
tree_dir_opened: vec![], tree_dir_opened: vec![],
file_tree: None, file_tree: None,
tree_visible: false, tree_visible: false,
profiler_visible: false, profiler_visible: false,
terminal_visible: false, terminal_visible: false,
close_tab_confirm: tools::confirm::ConfirmWindow::new( close_tab_confirm: tools::confirm::ConfirmWindow::new(
"You have some unsaved changes, Do you still want to close this document ?", "You have some unsaved changes, Do you still want to close this document ?",
"Confirm Close", "Confirm Close",
), ),
tab_to_close: 0, tab_to_close: 0,
refresh_confirm: tools::confirm::ConfirmWindow::new( refresh_confirm: tools::confirm::ConfirmWindow::new(
"You have some unsaved changes, Do you still want to refresh this document ?", "You have some unsaved changes, Do you still want to refresh this document ?",
"Confirm Refresh", "Confirm Refresh",
), ),
exit_confirm: tools::confirm::ConfirmWindow::new("", "Confirm Exit"), exit_confirm: tools::confirm::ConfirmWindow::new("", "Confirm Exit"),
search_menu: tools::search::SearchWindow::default(), search_menu: tools::search::SearchWindow::default(),
settings_menu: tools::settings::SettingsWindow::new(DEFAULT_THEMES[0]), settings_menu: tools::settings::SettingsWindow::new(DEFAULT_THEMES[0]),
shortcuts_menu: tools::shortcuts::ShortcutsWindow::new(), shortcuts_menu: tools::shortcuts::ShortcutsWindow::new(),
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(),
} }
} }
} }
impl eframe::App for Calcifer { impl eframe::App for Calcifer {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
thread::sleep(time::Duration::from_secs_f32( thread::sleep(time::Duration::from_secs_f32(
((1.0 / MAX_FPS) - self.next_frame.elapsed().as_secs_f32()).max(0.0), ((1.0 / MAX_FPS) - self.next_frame.elapsed().as_secs_f32()).max(0.0),
)); ));
self.next_frame = time::Instant::now(); self.next_frame = time::Instant::now();
let mut watch = time::Instant::now(); let mut watch = time::Instant::now();
let mut style = (*ctx.style()).clone(); let mut style = (*ctx.style()).clone();
style.text_styles = [ style.text_styles = [
(Heading, FontId::new(self.font_size * 1.6, Proportional)), (Heading, FontId::new(self.font_size * 1.6, Proportional)),
(Body, FontId::new(self.font_size, Proportional)), (Body, FontId::new(self.font_size, Proportional)),
(Monospace, FontId::new(self.font_size, Proportional)), (Monospace, FontId::new(self.font_size, Proportional)),
(Button, FontId::new(self.font_size, Proportional)), (Button, FontId::new(self.font_size, Proportional)),
(Small, FontId::new(self.font_size, Proportional)), (Small, FontId::new(self.font_size, Proportional)),
] ]
.into(); .into();
ctx.set_style(style); ctx.set_style(style);
if ctx.input(|i| i.key_pressed(egui::Key::R) && i.modifiers.ctrl) if ctx.input(|i| i.key_pressed(egui::Key::R) && i.modifiers.ctrl)
&& !self.refresh_confirm.visible && !self.refresh_confirm.visible
{ {
if self.tabs[self.selected_tab.to_index()].saved { if self.tabs[self.selected_tab.to_index()].saved {
self.tabs[self.selected_tab.to_index()].refresh(); self.tabs[self.selected_tab.to_index()].refresh();
} else { } else {
self.refresh_confirm.ask(); self.refresh_confirm.ask();
} }
} }
if ctx.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) { if ctx.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) {
self.handle_save_file(self.save_tab()); 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) { if ctx.input(|i| i.key_pressed(egui::Key::ArrowLeft) && i.modifiers.alt) {
self.move_through_tabs(false); self.move_through_tabs(false);
} }
if ctx.input(|i| i.key_pressed(egui::Key::ArrowRight) && i.modifiers.alt) { if ctx.input(|i| i.key_pressed(egui::Key::ArrowRight) && i.modifiers.alt) {
self.move_through_tabs(true); self.move_through_tabs(true);
} }
if ctx.input(|i| i.zoom_delta() > 1.0) { if ctx.input(|i| i.zoom_delta() > 1.0) {
self.font_size = (self.font_size * 1.1).min(30.0); self.font_size = (self.font_size * 1.1).min(30.0);
} }
if ctx.input(|i| i.zoom_delta() < 1.0) { if ctx.input(|i| i.zoom_delta() < 1.0) {
self.font_size = (self.font_size / 1.1).max(10.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.search_menu.visible = !self.search_menu.visible; self.search_menu.visible = !self.search_menu.visible;
self.search_menu.initialized = !self.search_menu.visible; self.search_menu.initialized = !self.search_menu.visible;
} }
if ctx.input(|i| i.viewport().close_requested()) { if ctx.input(|i| i.viewport().close_requested()) {
let mut unsaved_tabs: Vec<usize> = vec![]; let mut unsaved_tabs: Vec<usize> = vec![];
for (index, tab) in self.tabs.iter().enumerate() { for (index, tab) in self.tabs.iter().enumerate() {
if !tab.saved { if !tab.saved {
unsaved_tabs.push(index); unsaved_tabs.push(index);
} }
} }
if !unsaved_tabs.is_empty() { if !unsaved_tabs.is_empty() {
let mut unsaved_tabs_names: String = "".to_string(); let mut unsaved_tabs_names: String = "".to_string();
for index in unsaved_tabs.iter() { for index in unsaved_tabs.iter() {
unsaved_tabs_names.push_str(&self.tabs[*index].get_name()); unsaved_tabs_names.push_str(&self.tabs[*index].get_name());
} }
egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::CancelClose); egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::CancelClose);
self.exit_confirm.prompt = format!( self.exit_confirm.prompt = format!(
"You have some unsaved changes :\n{}\nDo you still want to exit ?", "You have some unsaved changes :\n{}\nDo you still want to exit ?",
unsaved_tabs_names unsaved_tabs_names
); );
self.exit_confirm.ask(); self.exit_confirm.ask();
} }
} }
self.time_watch[0] = watch.elapsed().as_micros() as f32 / 1000.0; self.time_watch[0] = watch.elapsed().as_micros() as f32 / 1000.0;
watch = time::Instant::now(); watch = time::Instant::now();
self.draw_settings(ctx); self.draw_settings(ctx);
self.time_watch[1] = watch.elapsed().as_micros() as f32 / 1000.0; self.time_watch[1] = watch.elapsed().as_micros() as f32 / 1000.0;
watch = time::Instant::now(); watch = time::Instant::now();
self.draw_tree_panel(ctx); self.draw_tree_panel(ctx);
self.time_watch[2] = watch.elapsed().as_micros() as f32 / 1000.0; self.time_watch[2] = watch.elapsed().as_micros() as f32 / 1000.0;
watch = time::Instant::now(); watch = time::Instant::now();
self.draw_bottom_tray(ctx); self.draw_bottom_tray(ctx);
self.draw_terminal_panel(ctx); self.draw_terminal_panel(ctx);
self.time_watch[3] = watch.elapsed().as_micros() as f32 / 1000.0; self.time_watch[3] = watch.elapsed().as_micros() as f32 / 1000.0;
watch = time::Instant::now(); watch = time::Instant::now();
self.draw_tab_panel(ctx); self.draw_tab_panel(ctx);
self.time_watch[4] = watch.elapsed().as_micros() as f32 / 1000.0; self.time_watch[4] = watch.elapsed().as_micros() as f32 / 1000.0;
watch = time::Instant::now(); watch = time::Instant::now();
self.draw_content_panel(ctx); self.draw_content_panel(ctx);
self.time_watch[5] = watch.elapsed().as_micros() as f32 / 1000.0; self.time_watch[5] = watch.elapsed().as_micros() as f32 / 1000.0;
watch = time::Instant::now(); watch = time::Instant::now();
self.draw_windows(ctx); self.draw_windows(ctx);
self.time_watch[6] = watch.elapsed().as_micros() as f32 / 1000.0; self.time_watch[6] = watch.elapsed().as_micros() as f32 / 1000.0;
} }
fn on_exit(&mut self, _gl: std::option::Option<&eframe::glow::Context>) { fn on_exit(&mut self, _gl: std::option::Option<&eframe::glow::Context>) {
self.save_state(); self.save_state();
} }
} }
fn save_path() -> PathBuf { fn save_path() -> PathBuf {
if TITLE.is_empty() { if TITLE.is_empty() {
get_my_home().unwrap().unwrap().as_path().join(".calcifer").join("save.json").to_path_buf() get_my_home()
} else { .unwrap()
get_my_home().unwrap().unwrap().as_path().join(".calcifer").join("debug").join("save.json").to_path_buf() .unwrap()
} .as_path()
.join(".calcifer")
.join("save.json")
.to_path_buf()
} else {
get_my_home()
.unwrap()
.unwrap()
.as_path()
.join(".calcifer")
.join("debug")
.join("save.json")
.to_path_buf()
}
} }

View file

@ -14,7 +14,6 @@ pub struct File {
pub folder_open: bool, pub folder_open: bool,
} }
impl File { impl File {
pub fn new_file(name: String, path: PathBuf) -> Self { pub fn new_file(name: String, path: PathBuf) -> Self {
Self { Self {
@ -26,7 +25,6 @@ impl File {
} }
} }
pub fn generate_file_tree(path: &Path, depth: isize) -> Option<File> { pub fn generate_file_tree(path: &Path, depth: isize) -> Option<File> {
if let Some(file_name) = path.file_name() { if let Some(file_name) = path.file_name() {
if file_name.to_string_lossy().starts_with('.') { if file_name.to_string_lossy().starts_with('.') {
@ -52,7 +50,10 @@ pub fn generate_file_tree(path: &Path, depth: isize) -> Option<File> {
match fs::read_dir(path) { match fs::read_dir(path) {
Err(err) => { Err(err) => {
return Some(File::new_file(format!("Error reading directory: {}", err), path.to_path_buf())); Some(File::new_file(
format!("Error reading directory: {}", err),
path.to_path_buf(),
))
} }
Ok(entries) => { Ok(entries) => {
let mut paths: Vec<Result<fs::DirEntry, io::Error>> = entries let mut paths: Vec<Result<fs::DirEntry, io::Error>> = entries
@ -60,7 +61,7 @@ pub fn generate_file_tree(path: &Path, depth: isize) -> Option<File> {
.collect(); .collect();
paths.sort_by(|a, b| match (a, b) { paths.sort_by(|a, b| match (a, b) {
(Ok(entry_a), Ok(entry_b)) => tools::sort_directories_first(&entry_a, &entry_b), (Ok(entry_a), Ok(entry_b)) => tools::sort_directories_first(entry_a, entry_b),
(Err(_), Ok(_)) => std::cmp::Ordering::Greater, (Err(_), Ok(_)) => std::cmp::Ordering::Greater,
(Ok(_), Err(_)) => std::cmp::Ordering::Less, (Ok(_), Err(_)) => std::cmp::Ordering::Less,
(Err(_), Err(_)) => std::cmp::Ordering::Equal, (Err(_), Err(_)) => std::cmp::Ordering::Equal,
@ -88,12 +89,12 @@ pub fn generate_file_tree(path: &Path, depth: isize) -> Option<File> {
return None; return None;
} }
return Some(File { Some(File {
name, name,
path: path.to_path_buf(), path: path.to_path_buf(),
folder_content: Some(folder_content), folder_content: Some(folder_content),
folder_open: false, folder_open: false,
}); })
} }
} }
} }

View file

@ -5,16 +5,16 @@ use egui::Color32;
use image::GenericImageView; use image::GenericImageView;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
cmp::Ordering, error::Error, ffi::OsStr, fs, fs::read_to_string, fs::OpenOptions, io::Write, cmp::Ordering, error::Error, ffi::OsStr, fs, fs::read_to_string, fs::OpenOptions, io::Write,
path::Component, path::Path, path::PathBuf, path::Component, path::Path, path::PathBuf,
}; };
//my tools; //my tools;
pub mod confirm; pub mod confirm;
pub mod file_tree;
pub mod search; pub mod search;
pub mod settings; pub mod settings;
pub mod shortcuts; pub mod shortcuts;
pub mod file_tree;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub mod terminal; pub mod terminal;
@ -31,99 +31,99 @@ pub use tabs::*;
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)] #[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
pub struct AppState { pub struct AppState {
pub tabs: Vec<PathBuf>, pub tabs: Vec<PathBuf>,
pub theme: usize, pub theme: usize,
} }
pub fn save_state(state: &AppState, file_path: &Path) -> Result<(), std::io::Error> { pub fn save_state(state: &AppState, file_path: &Path) -> Result<(), std::io::Error> {
let serialized_state = serde_json::to_string(state)?; let serialized_state = serde_json::to_string(state)?;
if let Some(parent_dir) = file_path.parent() { if let Some(parent_dir) = file_path.parent() {
fs::create_dir_all(parent_dir)?; fs::create_dir_all(parent_dir)?;
} }
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.write(true) .write(true)
.create(true) .create(true)
.truncate(true) .truncate(true)
.open(file_path)?; .open(file_path)?;
file.write_all(serialized_state.as_bytes())?; file.write_all(serialized_state.as_bytes())?;
println!("Saved state at {}", file_path.display()); println!("Saved state at {}", file_path.display());
Ok(()) Ok(())
} }
pub fn load_state(file_path: &Path) -> Result<AppState, std::io::Error> { pub fn load_state(file_path: &Path) -> Result<AppState, std::io::Error> {
let serialized_state = read_to_string(file_path)?; let serialized_state = read_to_string(file_path)?;
Ok(serde_json::from_str(&serialized_state)?) Ok(serde_json::from_str(&serialized_state)?)
} }
pub fn load_icon() -> Result<egui::IconData, Box<dyn Error>> { pub fn load_icon() -> Result<egui::IconData, Box<dyn Error>> {
let (icon_rgba, icon_width, icon_height) = { let (icon_rgba, icon_width, icon_height) = {
let icon = include_bytes!("../../assets/icon.png"); let icon = include_bytes!("../../assets/icon.png");
let image = image::load_from_memory(icon)?; let image = image::load_from_memory(icon)?;
let rgba = image.clone().into_rgba8().to_vec(); let rgba = image.clone().into_rgba8().to_vec();
let (width, height) = image.dimensions(); let (width, height) = image.dimensions();
(rgba, width, height) (rgba, width, height)
}; };
Ok(egui::IconData { Ok(egui::IconData {
rgba: icon_rgba, rgba: icon_rgba,
width: icon_width, width: icon_width,
height: icon_height, height: icon_height,
}) })
} }
pub fn to_syntax(language: &str) -> Syntax { pub fn to_syntax(language: &str) -> Syntax {
match language { match language {
"py" => Syntax::python(), "py" => Syntax::python(),
"rs" => Syntax::rust(), "rs" => Syntax::rust(),
_ => Syntax::shell(), _ => Syntax::shell(),
} }
} }
pub fn sort_directories_first(a: &std::fs::DirEntry, b: &std::fs::DirEntry) -> Ordering { pub fn sort_directories_first(a: &std::fs::DirEntry, b: &std::fs::DirEntry) -> Ordering {
let a_is_dir = a.path().is_dir(); let a_is_dir = a.path().is_dir();
let b_is_dir = b.path().is_dir(); let b_is_dir = b.path().is_dir();
// Directories come first, then files // Directories come first, then files
if a_is_dir && !b_is_dir { if a_is_dir && !b_is_dir {
Ordering::Less Ordering::Less
} else if !a_is_dir && b_is_dir { } else if !a_is_dir && b_is_dir {
Ordering::Greater Ordering::Greater
} else { } else {
// Both are either directories or files, sort alphabetically // Both are either directories or files, sort alphabetically
a.path().cmp(&b.path()) a.path().cmp(&b.path())
} }
} }
pub fn format_path(path: &Path) -> String { pub fn format_path(path: &Path) -> String {
let components: Vec<&OsStr> = path let components: Vec<&OsStr> = path
.components() .components()
.rev() .rev()
.take(DISPLAY_PATH_DEPTH) .take(DISPLAY_PATH_DEPTH)
.filter_map(|component| match component { .filter_map(|component| match component {
Component::RootDir | Component::CurDir => None, Component::RootDir | Component::CurDir => None,
_ => Some(component.as_os_str()), _ => Some(component.as_os_str()),
}) })
.collect(); .collect();
format!( format!(
"{}>", "{}>",
components components
.iter() .iter()
.rev() .rev()
.map(|&c| c.to_string_lossy()) .map(|&c| c.to_string_lossy())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("/") .join("/")
) )
} }
pub fn hex_str_to_color(hex_str: &str) -> Color32 { pub fn hex_str_to_color(hex_str: &str) -> Color32 {
Color32::from_hex(hex_str).unwrap_or_else(|_| Color32::BLACK) Color32::from_hex(hex_str).unwrap_or_else(|_| Color32::BLACK)
} }
#[cfg(test)] #[cfg(test)]

View file

@ -1,57 +1,50 @@
// Placeholder // Placeholder
pub struct Line { pub struct Line {
pub text: String, pub text: String,
pub error: bool, pub error: bool,
} }
impl Line { impl Line {
fn output(text: String) -> Self { fn error(text: String) -> Self {
Self { Self {
text: remove_line_break(text), text: remove_line_break(text),
error: false, error: true,
} }
} }
fn error(text: String) -> Self {
Self {
text: remove_line_break(text),
error: true,
}
}
} }
pub struct CommandEntry { pub struct CommandEntry {
pub env: String, pub env: String,
pub command: String, pub command: String,
pub result: Vec<Line>, pub result: Vec<Line>,
} }
impl CommandEntry { impl CommandEntry {
pub fn new(env: String, command: String) -> Self { pub fn new(env: String, command: String) -> Self {
CommandEntry { CommandEntry {
env, env,
command, command,
result: vec![Line::error("General Kenobi".to_string())], result: vec![Line::error("General Kenobi".to_string())],
} }
} }
pub fn update(&mut self) { pub fn update(&mut self) {
return return;
} }
} }
pub fn send_command(command: String) -> CommandEntry { pub fn send_command(_command: String) -> CommandEntry {
return CommandEntry::new("windows>".to_string(), "hello there".to_string()); return CommandEntry::new("windows>".to_string(), "hello there".to_string());
} }
fn remove_line_break(input: String) -> String { fn remove_line_break(input: String) -> String {
let mut text = input.clone(); let mut text = input.clone();
while text.ends_with('\n') { while text.ends_with('\n') {
text.pop(); text.pop();
if text.ends_with('\r') { if text.ends_with('\r') {
text.pop(); text.pop();
} }
} }
text text
} }