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, "");
});
});
}
pub fn draw_tree_panel(&mut self, ctx: &egui::Context) { if self.tabs[self.selected_tab.to_index()].language == PROJECT_EXTENSION {
if !self.tree_visible { ui.separator();
return; self.project_mode = self.toggle(ui, self.project_mode, "🛠");
} }
egui::SidePanel::left("file_tree_panel").show(ctx, |ui| { });
ui.heading("Bookshelf"); });
ui.separator(); }
let _ = self.list_files(ui, Path::new(&PATH_ROOT));
ui.separator();
});
}
pub fn draw_bottom_tray(&mut self, ctx: &egui::Context) { pub fn draw_tree_panel(&mut self, ctx: &egui::Context) {
egui::TopBottomPanel::bottom("tray") if !self.tree_visible {
.default_height(self.font_size * 1.2) return;
.resizable(false) }
.show(ctx, |ui| { egui::SidePanel::left("file_tree_panel").show(ctx, |ui| {
ui.label(self.profiler()); ui.heading("Bookshelf");
}); ui.separator();
} let _ = self.list_files(ui, Path::new(&PATH_ROOT));
ui.separator();
});
}
pub fn draw_terminal_panel(&mut self, ctx: &egui::Context) { pub fn draw_bottom_tray(&mut self, ctx: &egui::Context) {
if !self.terminal_visible { egui::TopBottomPanel::bottom("tray")
return; .default_height(self.font_size * 1.2)
} .resizable(false)
egui::TopBottomPanel::bottom("terminal") .show(ctx, |ui| {
.default_height(super::TERMINAL_HEIGHT) ui.label(self.profiler());
.height_range(Rangef::new( });
super::TERMINAL_RANGE.start, }
super::TERMINAL_RANGE.end,
))
.resizable(true)
.show(ctx, |ui| {
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
let command_color = hex_str_to_color(self.theme.functions);
let entry_color = hex_str_to_color(self.theme.literals);
let bg_color = hex_str_to_color(self.theme.bg);
ui.label(""); pub fn draw_terminal_panel(&mut self, ctx: &egui::Context) {
if !self.terminal_visible {
return;
}
egui::TopBottomPanel::bottom("terminal")
.default_height(super::TERMINAL_HEIGHT)
.height_range(Rangef::new(
super::TERMINAL_RANGE.start,
super::TERMINAL_RANGE.end,
))
.resizable(true)
.show(ctx, |ui| {
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
let command_color = hex_str_to_color(self.theme.functions);
let entry_color = hex_str_to_color(self.theme.literals);
let bg_color = hex_str_to_color(self.theme.bg);
ui.horizontal(|ui| { ui.label("");
if ui.add(egui::Button::new("")).clicked() {
self.command_history = vec![];
}
ui.style_mut().visuals.extreme_bg_color = bg_color;
let Self { command, .. } = self;
ui.colored_label(
command_color,
tools::format_path(
&env::current_dir().unwrap_or_else(|_| PathBuf::from("/")),
),
);
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)) { ui.horizontal(|ui| {
self.command_history if ui.add(egui::Button::new("")).clicked() {
.push(tools::send_command(self.command.clone())); self.command_history = vec![];
self.command = "".into(); }
response.request_focus(); ui.style_mut().visuals.extreme_bg_color = bg_color;
} let Self { command, .. } = self;
}); ui.colored_label(
ui.separator(); command_color,
egui::ScrollArea::vertical() tools::format_path(
.stick_to_bottom(true) &env::current_dir().unwrap_or_else(|_| PathBuf::from("/")),
.show(ui, |ui| { ),
ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| { );
ui.separator(); let response = ui.add(
ui.horizontal_wrapped(|ui| { egui::TextEdit::singleline(command)
ui.spacing_mut().item_spacing.y = 0.0; .desired_width(f32::INFINITY)
for entry in &mut self.command_history { .lock_focus(true),
entry.update(); );
ui.colored_label(
command_color,
format!("\n{} {}", entry.env, entry.command),
);
ui.end_row();
if !entry.output.is_empty() {
ui.colored_label(entry_color, &entry.output);
ui.end_row();
}
if !entry.error.is_empty() {
ui.colored_label(super::RED, &entry.error);
ui.end_row();
}
}
});
});
});
});
});
}
pub fn draw_tab_panel(&mut self, ctx: &egui::Context) { if response.lost_focus() && ctx.input(|i| i.key_pressed(egui::Key::Enter)) {
egui::TopBottomPanel::top("tabs") self.command_history
.resizable(false) .push(tools::send_command(self.command.clone()));
.show(ctx, |ui| { self.command = "".into();
ui.horizontal(|ui| { response.request_focus();
ui.style_mut().visuals.selection.bg_fill = }
hex_str_to_color(self.theme.functions); });
ui.style_mut().visuals.hyperlink_color = hex_str_to_color(self.theme.functions); ui.separator();
for (index, tab) in self.tabs.clone().iter().enumerate() { egui::ScrollArea::vertical()
let mut title = tab.get_name(); .stick_to_bottom(true)
if !tab.saved { .show(ui, |ui| {
title += " ~"; ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| {
} ui.separator();
if self.selected_tab == tools::TabNumber::from_index(index) { ui.horizontal_wrapped(|ui| {
ui.style_mut().visuals.override_text_color = ui.spacing_mut().item_spacing.y = 0.0;
Some(hex_str_to_color(self.theme.bg)); for entry in &mut self.command_history {
} entry.update();
ui.selectable_value( ui.colored_label(
&mut self.selected_tab, command_color,
tools::TabNumber::from_index(index), format!("\n{} {}", entry.env, entry.command),
title, );
); ui.end_row();
if !entry.output.is_empty() {
ui.colored_label(entry_color, &entry.output);
ui.end_row();
}
if !entry.error.is_empty() {
ui.colored_label(super::RED, &entry.error);
ui.end_row();
}
}
});
});
});
});
});
}
ui.style_mut().visuals.override_text_color = None; pub fn draw_tab_panel(&mut self, ctx: &egui::Context) {
egui::TopBottomPanel::top("tabs")
.resizable(false)
.show(ctx, |ui| {
ui.horizontal(|ui| {
ui.style_mut().visuals.selection.bg_fill =
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() {
let mut title = tab.get_name();
if !tab.saved {
title += " ~";
}
if self.selected_tab == tools::TabNumber::from_index(index) {
ui.style_mut().visuals.override_text_color =
Some(hex_str_to_color(self.theme.bg));
}
ui.selectable_value(
&mut self.selected_tab,
tools::TabNumber::from_index(index),
title,
);
if ui.link("X").clicked() && !self.close_tab_confirm.visible { ui.style_mut().visuals.override_text_color = None;
if self.tabs.len() > 1 {
if tab.saved {
self.delete_tab(index);
} else {
self.close_tab_confirm.ask();
self.tab_to_close = index;
}
} else {
egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::Close);
}
}
ui.separator();
}
if self.tabs.len() < MAX_TABS {
ui.selectable_value(&mut self.selected_tab, tools::TabNumber::Open, "+");
}
if self.selected_tab == tools::TabNumber::Open {
self.open_file(None);
}
});
});
}
pub fn draw_content_panel(&mut self, ctx: &egui::Context) { if ui.link("X").clicked() && !self.close_tab_confirm.visible {
egui::CentralPanel::default().show(ctx, |ui| { if self.tabs.len() > 1 {
ui.horizontal(|ui| { if tab.saved {
if ui.add(egui::Button::new("open in terminal")).clicked() { self.delete_tab(index);
let mut path = self.tabs[self.selected_tab.to_index()].path.clone(); } else {
path.pop(); self.close_tab_confirm.ask();
tools::send_command(format!("cd {}", path.display())); self.tab_to_close = index;
} }
} else {
egui::Context::send_viewport_cmd(ctx, egui::ViewportCommand::Close);
}
}
ui.separator();
}
if self.tabs.len() < MAX_TABS {
ui.selectable_value(&mut self.selected_tab, tools::TabNumber::Open, "+");
}
if self.selected_tab == tools::TabNumber::Open {
self.open_file(None);
}
});
});
}
ui.label("Picked file:"); pub fn draw_content_panel(&mut self, ctx: &egui::Context) {
ui.monospace( egui::CentralPanel::default().show(ctx, |ui| {
self.tabs[self.selected_tab.to_index()] ui.horizontal(|ui| {
.path if ui.add(egui::Button::new("open in terminal")).clicked() {
.to_string_lossy() let mut path = self.tabs[self.selected_tab.to_index()].path.clone();
.to_string(), path.pop();
); tools::send_command(format!("cd {}", path.display()));
}); }
ui.separator(); ui.label("Picked file:");
ui.monospace(
self.tabs[self.selected_tab.to_index()]
.path
.to_string_lossy()
.to_string(),
);
});
self.draw_code_file(ui); 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);
}
});
}
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,
); );
} }
pub fn draw_windows(&mut self, ctx: &egui::Context) { fn draw_project_file(&mut self, ui: &mut egui::Ui) {
if self.search_menu.visible { ui.label("project mode");
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(); pub fn draw_windows(&mut self, ctx: &egui::Context) {
} 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,
tree_visible: bool, project_mode: bool,
profiler_visible: bool,
terminal_visible: bool,
close_tab_confirm: tools::confirm::ConfirmWindow, tree_visible: bool,
tab_to_close: usize, profiler_visible: bool,
refresh_confirm: tools::confirm::ConfirmWindow, terminal_visible: bool,
exit_confirm: tools::confirm::ConfirmWindow,
search_menu: tools::search::SearchWindow, close_tab_confirm: tools::confirm::ConfirmWindow,
settings_menu: tools::settings::SettingsWindow, tab_to_close: usize,
shortcuts_menu: tools::shortcuts::ShortcutsWindow, refresh_confirm: tools::confirm::ConfirmWindow,
exit_confirm: tools::confirm::ConfirmWindow,
time_watch: Vec<f32>, search_menu: tools::search::SearchWindow,
next_frame: time::Instant, settings_menu: tools::settings::SettingsWindow,
shortcuts_menu: tools::shortcuts::ShortcutsWindow,
time_watch: Vec<f32>,
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,
tree_visible: false, project_mode: true,
profiler_visible: false,
terminal_visible: false,
close_tab_confirm: tools::confirm::ConfirmWindow::new( tree_visible: false,
"You have some unsaved changes, Do you still want to close this document ?", profiler_visible: false,
"Confirm Close", terminal_visible: false,
),
tab_to_close: 0,
refresh_confirm: tools::confirm::ConfirmWindow::new(
"You have some unsaved changes, Do you still want to refresh this document ?",
"Confirm Refresh",
),
exit_confirm: tools::confirm::ConfirmWindow::new("", "Confirm Exit"),
search_menu: tools::search::SearchWindow::default(), close_tab_confirm: tools::confirm::ConfirmWindow::new(
settings_menu: tools::settings::SettingsWindow::new(DEFAULT_THEMES[0]), "You have some unsaved changes, Do you still want to close this document ?",
shortcuts_menu: tools::shortcuts::ShortcutsWindow::new(), "Confirm Close",
),
tab_to_close: 0,
refresh_confirm: tools::confirm::ConfirmWindow::new(
"You have some unsaved changes, Do you still want to refresh this document ?",
"Confirm Refresh",
),
exit_confirm: tools::confirm::ConfirmWindow::new("", "Confirm Exit"),
time_watch: vec![0.0; TIME_LABELS.len()], search_menu: tools::search::SearchWindow::default(),
next_frame: time::Instant::now(), settings_menu: tools::settings::SettingsWindow::new(DEFAULT_THEMES[0]),
} shortcuts_menu: tools::shortcuts::ShortcutsWindow::new(),
}
time_watch: vec![0.0; TIME_LABELS.len()],
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();
Self { println!("language : {}", extension);
path: file_path.clone(),
code: text,
language: extension.into(),
saved: true,
scroll_offset: 0.0,
last_cursor: None,
}
}
pub fn get_name(&self) -> String { Self {
self.path path: file_path.clone(),
.file_name() code: text,
.map_or("untitled".to_string(), |name| { language: extension.into(),
name.to_string_lossy().to_string() saved: true,
}) scroll_offset: 0.0,
} last_cursor: None,
}
}
pub fn refresh(&mut self) { pub fn get_name(&self) -> String {
let text = read_file_contents(&self.path).replace(&" ".repeat(4), "\t"); self.path
let file_path = format_file_path(&self.path, &text); .file_name()
.map_or("untitled".to_string(), |name| {
name.to_string_lossy().to_string()
})
}
self.code = text; pub fn refresh(&mut self) {
self.path = file_path; let text = read_file_contents(&self.path).replace(&" ".repeat(4), "\t");
self.saved = true; let file_path = format_file_path(&self.path, &text);
}
self.code = text;
self.path = file_path;
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()
} }
} }