added project file recognition

This commit is contained in:
Penwing 2024-01-26 19:21:54 +01:00
parent 415122ea30
commit 94ef5675b7
3 changed files with 495 additions and 475 deletions

View file

@ -6,6 +6,7 @@ use crate::tools;
use crate::Calcifer; use crate::Calcifer;
use crate::MAX_TABS; use crate::MAX_TABS;
use crate::PATH_ROOT; use crate::PATH_ROOT;
use crate::PROJECT_EXTENSION;
use tools::hex_str_to_color; use tools::hex_str_to_color;
pub mod code_editor; pub mod code_editor;
@ -14,265 +15,277 @@ 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(Path::new(&PATH_ROOT)) .set_directory(Path::new(&PATH_ROOT))
.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 {
} ui.separator();
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.heading("Bookshelf"); ui.heading("Bookshelf");
ui.separator(); ui.separator();
let _ = self.list_files(ui, Path::new(&PATH_ROOT)); let _ = self.list_files(ui, Path::new(&PATH_ROOT));
ui.separator(); ui.separator();
}); });
} }
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();
if !entry.output.is_empty() { if !entry.output.is_empty() {
ui.colored_label(entry_color, &entry.output); ui.colored_label(entry_color, &entry.output);
ui.end_row(); ui.end_row();
} }
if !entry.error.is_empty() { if !entry.error.is_empty() {
ui.colored_label(super::RED, &entry.error); ui.colored_label(super::RED, &entry.error);
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 in terminal")).clicked() { if ui.add(egui::Button::new("open in terminal")).clicked() {
let mut path = self.tabs[self.selected_tab.to_index()].path.clone(); let mut path = self.tabs[self.selected_tab.to_index()].path.clone();
path.pop(); path.pop();
tools::send_command(format!("cd {}", path.display())); 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 && self.tabs[self.selected_tab.to_index()].language == PROJECT_EXTENSION {
self.draw_project_file(ui);
} else {
self.draw_code_file(ui);
}
});
}
self.draw_code_file(ui); fn draw_code_file(&mut self, ui: &mut egui::Ui) {
}); let current_tab = &mut self.tabs[self.selected_tab.to_index()];
} let lines = current_tab.code.chars().filter(|&c| c == '\n').count() + 1;
let mut override_cursor: Option<CCursorRange> = None;
fn draw_code_file(&mut self, ui: &mut egui::Ui) { if !self.search_menu.result_selected {
let current_tab = &mut self.tabs[self.selected_tab.to_index()]; override_cursor = Some(CCursorRange::two(
let lines = current_tab.code.chars().filter(|&c| c == '\n').count() + 1; CCursor::new(self.search_menu.get_cursor_start()),
let mut override_cursor: Option<CCursorRange> = None; CCursor::new(self.search_menu.get_cursor_end()),
));
self.search_menu.result_selected = true;
}
if !self.search_menu.result_selected { CodeEditor::default()
override_cursor = Some(CCursorRange::two( .id_source("code editor")
CCursor::new(self.search_menu.get_cursor_start()), .with_rows(max(45, lines))
CCursor::new(self.search_menu.get_cursor_end()), .with_fontsize(self.font_size)
)); .with_theme(self.theme)
self.search_menu.result_selected = true; .with_syntax(tools::to_syntax(&current_tab.language))
} .with_numlines(true)
.show(
ui,
&mut current_tab.code,
&mut current_tab.saved,
&mut current_tab.last_cursor,
&mut current_tab.scroll_offset,
override_cursor,
);
}
fn draw_project_file(&mut self, ui: &mut egui::Ui) {
ui.label("project mode");
}
CodeEditor::default() pub fn draw_windows(&mut self, ctx: &egui::Context) {
.id_source("code editor") if self.search_menu.visible {
.with_rows(max(45, lines)) self.search_menu
.with_fontsize(self.font_size) .show(ctx, &mut self.tabs, &mut self.selected_tab);
.with_theme(self.theme) }
.with_syntax(tools::to_syntax(&current_tab.language)) if self.close_tab_confirm.visible {
.with_numlines(true) self.close_tab_confirm.show(ctx);
.show( }
ui, if self.refresh_confirm.visible {
&mut current_tab.code, self.refresh_confirm.show(ctx);
&mut current_tab.saved, }
&mut current_tab.last_cursor, if self.exit_confirm.visible {
&mut current_tab.scroll_offset, self.exit_confirm.show(ctx);
override_cursor, }
); if self.exit_confirm.proceed {
} for tab in self.tabs.iter_mut() {
tab.saved = true;
}
egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::Close);
}
if self.shortcuts_menu.visible {
self.shortcuts_menu.show(ctx);
}
if self.settings_menu.visible {
self.settings_menu.show(ctx);
}
if self.settings_menu.updated {
self.theme = self.settings_menu.theme;
}
pub fn draw_windows(&mut self, ctx: &egui::Context) { self.handle_confirm();
if self.search_menu.visible { }
self.search_menu
.show(ctx, &mut self.tabs, &mut self.selected_tab);
}
if self.close_tab_confirm.visible {
self.close_tab_confirm.show(ctx);
}
if self.refresh_confirm.visible {
self.refresh_confirm.show(ctx);
}
if self.exit_confirm.visible {
self.exit_confirm.show(ctx);
}
if self.exit_confirm.proceed {
for tab in self.tabs.iter_mut() {
tab.saved = true;
}
egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::Close);
}
if self.shortcuts_menu.visible {
self.shortcuts_menu.show(ctx);
}
if self.settings_menu.visible {
self.settings_menu.show(ctx);
}
if self.settings_menu.updated {
self.theme = self.settings_menu.theme;
}
self.handle_confirm();
}
} }

View file

@ -12,24 +12,25 @@ use calcifer::code_editor::themes::DEFAULT_THEMES;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
mod build { mod build {
pub const SAVE_PATH: &str = "/home/penwing/Documents/.save/debug/calcifer_save.json"; pub const SAVE_PATH: &str = "/home/penwing/Documents/.save/debug/calcifer_save.json";
pub const TITLE: &str = " debug"; pub const TITLE: &str = " debug";
} }
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
mod build { mod build {
pub const SAVE_PATH: &str = "/home/penwing/Documents/.save/calcifer_save.json"; pub const SAVE_PATH: &str = "/home/penwing/Documents/.save/calcifer_save.json";
pub const TITLE: &str = ""; pub const TITLE: &str = "";
} }
use build::SAVE_PATH; use build::SAVE_PATH;
use build::TITLE; use build::TITLE;
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 PATH_ROOT: &str = "/home/penwing/Documents/"; const PATH_ROOT: &str = "/home/penwing/Documents/";
@ -37,211 +38,215 @@ 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 Path::new(SAVE_PATH).exists() { let app_state: tools::AppState = if Path::new(SAVE_PATH).exists() {
match tools::load_state(SAVE_PATH) { match tools::load_state(SAVE_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,
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,
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();
} }
} }

View file

@ -5,96 +5,98 @@ use crate::MAX_TABS;
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum TabNumber { pub enum TabNumber {
Open, Open,
Number(u8), // Using a range for numeric values Number(u8), // Using a range for numeric values
} }
impl TabNumber { impl TabNumber {
pub fn from_index(n: usize) -> TabNumber { pub fn from_index(n: usize) -> TabNumber {
match n { match n {
0..=MAX_TABS => TabNumber::Number(n as u8), 0..=MAX_TABS => TabNumber::Number(n as u8),
_ => TabNumber::Number(0), _ => TabNumber::Number(0),
} }
} }
pub fn to_index(&self) -> usize { pub fn to_index(&self) -> usize {
match self { match self {
TabNumber::Number(n) => *n as usize, TabNumber::Number(n) => *n as usize,
_ => 0, _ => 0,
} }
} }
} }
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct Tab { pub struct Tab {
pub path: PathBuf, pub path: PathBuf,
pub code: String, pub code: String,
pub language: String, pub language: String,
pub saved: bool, pub saved: bool,
pub scroll_offset: f32, pub scroll_offset: f32,
pub last_cursor: Option<CCursorRange>, pub last_cursor: Option<CCursorRange>,
} }
impl Default for Tab { impl Default for Tab {
fn default() -> Self { fn default() -> Self {
Self { Self {
path: "untitled".into(), path: "untitled".into(),
code: "// Hello there, Master".into(), code: "// Hello there, Master".into(),
language: "rs".into(), language: "rs".into(),
saved: false, saved: false,
scroll_offset: 0.0, scroll_offset: 0.0,
last_cursor: None, last_cursor: None,
} }
} }
} }
impl Tab { impl Tab {
pub fn new(path: PathBuf) -> Self { pub fn new(path: PathBuf) -> Self {
let text = read_file_contents(&path).replace(&" ".repeat(4), "\t"); let text = read_file_contents(&path).replace(&" ".repeat(4), "\t");
let file_path = format_file_path(&path, &text); let file_path = format_file_path(&path, &text);
let extension = file_path let extension = file_path
.extension() .extension()
.and_then(|ext| ext.to_str()) .and_then(|ext| ext.to_str())
.unwrap_or_default(); .unwrap_or_default();
println!("language : {}", extension);
Self { Self {
path: file_path.clone(), path: file_path.clone(),
code: text, code: text,
language: extension.into(), language: extension.into(),
saved: true, saved: true,
scroll_offset: 0.0, scroll_offset: 0.0,
last_cursor: None, last_cursor: None,
} }
} }
pub fn get_name(&self) -> String { pub fn get_name(&self) -> String {
self.path self.path
.file_name() .file_name()
.map_or("untitled".to_string(), |name| { .map_or("untitled".to_string(), |name| {
name.to_string_lossy().to_string() name.to_string_lossy().to_string()
}) })
} }
pub fn refresh(&mut self) { pub fn refresh(&mut self) {
let text = read_file_contents(&self.path).replace(&" ".repeat(4), "\t"); let text = read_file_contents(&self.path).replace(&" ".repeat(4), "\t");
let file_path = format_file_path(&self.path, &text); let file_path = format_file_path(&self.path, &text);
self.code = text; self.code = text;
self.path = file_path; self.path = file_path;
self.saved = true; self.saved = true;
} }
} }
fn read_file_contents(path: &Path) -> String { fn read_file_contents(path: &Path) -> String {
read_to_string(path) read_to_string(path)
.map_err(|err| format!("// Error reading file: {}", err)) .map_err(|err| format!("// Error reading file: {}", err))
.unwrap_or_else(|err_msg| err_msg) .unwrap_or_else(|err_msg| err_msg)
} }
fn format_file_path(path: &Path, contents: &str) -> PathBuf { fn format_file_path(path: &Path, contents: &str) -> PathBuf {
if contents.contains("Error reading file") { if contents.contains("Error reading file") {
"untitled".into() "untitled".into()
} else { } else {
path.to_path_buf() path.to_path_buf()
} }
} }