diff --git a/Cargo.toml b/Cargo.toml index 8ee159f..b38d858 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] eframe = "0.32" egui = "0.32" +egui_extras = { version = "0.32", features = ["syntect"] } serde = { version = "1.0.219", features = ["derive"] } rfd = "0.15.4" toml = "0.9.2" diff --git a/src/app/config.rs b/src/app/config.rs index 7f14af5..1cba26d 100644 --- a/src/app/config.rs +++ b/src/app/config.rs @@ -65,11 +65,9 @@ impl Default for Config { impl Config { pub fn config_path() -> Option { let config_dir = if let Some(config_dir) = dirs::config_dir() { - config_dir.join(format!("{}", env!("CARGO_PKG_NAME"))) + config_dir.join(env!("CARGO_PKG_NAME")) } else if let Some(home_dir) = dirs::home_dir() { - home_dir - .join(".config") - .join(format!("{}", env!("CARGO_PKG_NAME"))) + home_dir.join(".config").join(env!("CARGO_PKG_NAME")) } else { return None; }; diff --git a/src/main.rs b/src/main.rs index 3621bd3..0a0716a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,21 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] use eframe::egui; +use std::env; +use std::io::IsTerminal; mod app; mod io; mod ui; -use app::{config::Config, TextEditor}; +use app::{TextEditor, config::Config}; fn main() -> eframe::Result { + let _args: Vec = env::args().collect(); + if std::io::stdin().is_terminal() { + println!("This is a GUI application, are you sure you want to launch from terminal?"); + // return Ok(()); + } + let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default() .with_min_inner_size([600.0, 400.0]) diff --git a/src/ui/central_panel/editor.rs b/src/ui/central_panel/editor.rs index acd273a..24441ca 100644 --- a/src/ui/central_panel/editor.rs +++ b/src/ui/central_panel/editor.rs @@ -1,8 +1,76 @@ use crate::app::TextEditor; use eframe::egui; +use egui_extras::syntax_highlighting::{self, CodeTheme}; use super::find_highlight; +fn get_language_from_extension(file_path: Option<&std::path::Path>) -> String { + if let Some(path) = file_path { + if let Some(extension) = path.extension().and_then(|ext| ext.to_str()) { + match extension.to_lowercase().as_str() { + "rs" => "rs".to_string(), + "py" => "py".to_string(), + "js" => "js".to_string(), + "ts" => "ts".to_string(), + "tsx" => "tsx".to_string(), + "jsx" => "jsx".to_string(), + "c" => "c".to_string(), + "cpp" | "cc" | "cxx" => "cpp".to_string(), + "h" | "hpp" => "cpp".to_string(), + "java" => "java".to_string(), + "go" => "go".to_string(), + "php" => "php".to_string(), + "rb" => "rb".to_string(), + "cs" => "cs".to_string(), + "swift" => "swift".to_string(), + "kt" => "kt".to_string(), + "scala" => "scala".to_string(), + "sh" | "bash" | "zsh" | "fish" => "sh".to_string(), + "html" | "htm" => "html".to_string(), + "xml" => "xml".to_string(), + "css" => "css".to_string(), + "scss" | "sass" => "scss".to_string(), + "json" => "json".to_string(), + "yaml" | "yml" => "yaml".to_string(), + "toml" => "toml".to_string(), + "md" | "markdown" => "md".to_string(), + "sql" => "sql".to_string(), + "lua" => "lua".to_string(), + "vim" => "vim".to_string(), + "dockerfile" => "dockerfile".to_string(), + "makefile" => "makefile".to_string(), + _ => "txt".to_string(), + } + } else { + // Check filename for special cases + if let Some(filename) = path.file_name().and_then(|name| name.to_str()) { + match filename.to_lowercase().as_str() { + "dockerfile" => "dockerfile".to_string(), + "makefile" => "makefile".to_string(), + "cargo.toml" | "pyproject.toml" => "toml".to_string(), + "package.json" => "json".to_string(), + _ => "txt".to_string(), + } + } else { + "txt".to_string() + } + } + } else { + "txt".to_string() + } +} + +fn create_code_theme_from_visuals(visuals: &egui::Visuals, font_size: f32) -> CodeTheme { + // For now, just use the appropriate base theme (dark/light) + // The base themes should automatically work well with the system colors + // since egui's syntax highlighting respects the overall UI theme + if visuals.dark_mode { + CodeTheme::dark(font_size) + } else { + CodeTheme::light(font_size) + } +} + pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::Response { let _current_match_position = app.get_current_match_position(); let show_find = app.show_find; @@ -96,6 +164,23 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R f32::INFINITY }; + // Determine the language for syntax highlighting + let language = get_language_from_extension(active_tab.file_path.as_deref()); + + // Create a code theme based on the current system theme visuals + let theme = create_code_theme_from_visuals(ui.visuals(), font_size); + + let mut layouter = |ui: &egui::Ui, string: &dyn egui::TextBuffer, wrap_width: f32| { + let text = string.as_str(); + let mut layout_job = if language == "txt" { + syntax_highlighting::highlight(ui.ctx(), &ui.style().clone(), &theme, text, "") + } else { + syntax_highlighting::highlight(ui.ctx(), &ui.style().clone(), &theme, text, &language) + }; + layout_job.wrap.max_width = wrap_width; + ui.fonts(|f| f.layout_job(layout_job)) + }; + let text_edit = egui::TextEdit::multiline(&mut active_tab.content) .frame(false) .font(egui::TextStyle::Monospace) @@ -104,6 +189,7 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R .desired_rows(0) .lock_focus(!show_find) .cursor_at_end(false) + .layouter(&mut layouter) .id(egui::Id::new("main_text_editor")); let output = if word_wrap { diff --git a/src/ui/preferences_window.rs b/src/ui/preferences_window.rs index 3ecd285..c888e6e 100644 --- a/src/ui/preferences_window.rs +++ b/src/ui/preferences_window.rs @@ -4,8 +4,8 @@ use eframe::egui; pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) { let visuals = &ctx.style().visuals; let screen_rect = ctx.screen_rect(); - let window_width = (screen_rect.width() * 0.6).min(400.0).max(300.0); - let window_height = (screen_rect.height() * 0.7).min(500.0).max(250.0); + let window_width = (screen_rect.width() * 0.6).clamp(300.0, 400.0); + let window_height = (screen_rect.height() * 0.7).clamp(250.0, 500.0); let max_size = egui::Vec2::new(window_width, window_height); egui::Window::new("Preferences")