checkpoint for theming
This commit is contained in:
parent
fd26344b5f
commit
4651d7caf4
@ -12,3 +12,5 @@ rfd = "0.15.4"
|
||||
toml = "0.9.2"
|
||||
dirs = "6.0"
|
||||
libc = "0.2.174"
|
||||
syntect = "5.2.0"
|
||||
plist = "1.7.4"
|
||||
|
||||
@ -46,6 +46,7 @@ theme = "System"
|
||||
line_side = false
|
||||
font_family = "Monospace"
|
||||
font_size = 16.0
|
||||
syntax_highlighting = true
|
||||
```
|
||||
|
||||
### Options
|
||||
@ -55,6 +56,7 @@ font_size = 16.0
|
||||
| `auto_hide_toolbar` | `false` | If `true`, the menu bar at the top will be hidden. Move your mouse to the top of the window to reveal it. |
|
||||
| `hide_tab_bar` | 'true' | If `false`, a separate tab bar will be drawn below the toolbar. |
|
||||
| `show_line_numbers` | `false` | If `true`, line numbers will be displayed on the side specified by `line_side`. |
|
||||
| `syntax_highlighting` | `false` | If `true`, text will be highlighted based on detected language. |
|
||||
| `line_side` | `false` | If `false`, line numbers are on the left. If `true`, they are on the right. |
|
||||
| `word_wrap` | `false` | If `true`, lines will wrap when they reach the edge of the window. |
|
||||
| `font_family` | `"Proportional"` | The font family used for the editor text. |
|
||||
@ -65,9 +67,8 @@ font_size = 16.0
|
||||
In order of importance.
|
||||
| Feature | Info |
|
||||
| ------- | ---- |
|
||||
| **Find/Replace:** | Functioning. |
|
||||
| **State/Cache:** | A toggleable option to keep an application state and prevent "Quit without saving" warnings. |
|
||||
| **Syntax Highlighting/LSP:** | Looking at allowing you to use/attach your own tools for this. |
|
||||
| **LSP:** | Looking at allowing you to use/attach your own tools for this. |
|
||||
| **Choose Font** | More than just Monospace/Proportional. |
|
||||
| **Vim Mode:** | It's in-escapable. |
|
||||
| **CLI Mode:** | 💀 |
|
||||
|
||||
111
src/app/theme.rs
111
src/app/theme.rs
@ -1,5 +1,7 @@
|
||||
use eframe::egui;
|
||||
use egui_extras::syntax_highlighting::CodeTheme;
|
||||
use plist::{Dictionary, Value};
|
||||
use std::collections::BTreeMap;
|
||||
use syntect::highlighting::{Theme as SyntectTheme, ThemeSet, ThemeSettings, Color as SyntectColor, UnderlineOption};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize, Default)]
|
||||
pub enum Theme {
|
||||
@ -196,11 +198,108 @@ fn detect_system_dark_mode() -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_code_theme_from_visuals(visuals: &egui::Visuals, font_size: f32) -> CodeTheme {
|
||||
if visuals.dark_mode {
|
||||
CodeTheme::dark(font_size)
|
||||
} else {
|
||||
CodeTheme::light(font_size)
|
||||
fn egui_color_to_syntect(color: egui::Color32) -> SyntectColor {
|
||||
SyntectColor {
|
||||
r: color.r(),
|
||||
g: color.g(),
|
||||
b: color.b(),
|
||||
a: color.a(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_code_theme_from_visuals(visuals: &egui::Visuals, font_size: f32) -> ThemeSet {
|
||||
let text_color = visuals.override_text_color.unwrap_or(visuals.text_color());
|
||||
let bg_color = visuals.extreme_bg_color;
|
||||
let selection_color = visuals.selection.bg_fill;
|
||||
let comment_color = blend_colors(text_color, bg_color, 0.6);
|
||||
let keyword_color = if visuals.dark_mode {
|
||||
blend_colors(egui::Color32::from_rgb(100, 149, 237), text_color, 0.8) // CornflowerBlue-like
|
||||
} else {
|
||||
blend_colors(egui::Color32::from_rgb(0, 0, 139), text_color, 0.8) // DarkBlue-like
|
||||
};
|
||||
let string_color = if visuals.dark_mode {
|
||||
blend_colors(egui::Color32::from_rgb(144, 238, 144), text_color, 0.8) // LightGreen-like
|
||||
} else {
|
||||
blend_colors(egui::Color32::from_rgb(0, 128, 0), text_color, 0.8) // Green-like
|
||||
};
|
||||
let number_color = if visuals.dark_mode {
|
||||
blend_colors(egui::Color32::from_rgb(255, 165, 0), text_color, 0.8) // Orange-like
|
||||
} else {
|
||||
blend_colors(egui::Color32::from_rgb(165, 42, 42), text_color, 0.8) // Brown-like
|
||||
};
|
||||
let function_color = if visuals.dark_mode {
|
||||
blend_colors(egui::Color32::from_rgb(255, 20, 147), text_color, 0.8) // DeepPink-like
|
||||
} else {
|
||||
blend_colors(egui::Color32::from_rgb(128, 0, 128), text_color, 0.8) // Purple-like
|
||||
};
|
||||
|
||||
let plist_theme = build_custom_theme_plist("System", &format!("{:?}", bg_color), &format!("{:?}", text_color), &format!("{:?}", comment_color), &format!("{:?}", string_color), &format!("{:?}", keyword_color));
|
||||
let file = std::fs::File::create("system.tmTheme").unwrap();
|
||||
let writer = std::io::BufWriter::new(file);
|
||||
|
||||
let _ =plist::to_writer_xml(writer, &plist_theme);
|
||||
|
||||
let loaded_file = std::fs::File::open("system.tmTheme").unwrap();
|
||||
let mut loaded_reader = std::io::BufReader::new(loaded_file);
|
||||
let loaded_theme = ThemeSet::load_from_reader(&mut loaded_reader).unwrap();
|
||||
let mut set = ThemeSet::new();
|
||||
set.add_from_folder(".").unwrap();
|
||||
return set;
|
||||
|
||||
}
|
||||
|
||||
fn build_custom_theme_plist(
|
||||
theme_name: &str,
|
||||
background_color: &str,
|
||||
foreground_color: &str,
|
||||
comment_color: &str,
|
||||
string_color: &str,
|
||||
keyword_color: &str,
|
||||
) -> Value {
|
||||
let mut root_dict = Dictionary::new();
|
||||
root_dict.insert("name".to_string(), Value::String(theme_name.to_string()));
|
||||
|
||||
let mut settings_array = Vec::new();
|
||||
|
||||
// Global settings
|
||||
let mut global_settings_dict = Dictionary::new();
|
||||
let mut inner_global_settings = Dictionary::new();
|
||||
inner_global_settings.insert("background".to_string(), Value::String(background_color.to_string()));
|
||||
inner_global_settings.insert("foreground".to_string(), Value::String(foreground_color.to_string()));
|
||||
global_settings_dict.insert("settings".to_string(), Value::Dictionary(inner_global_settings));
|
||||
settings_array.push(Value::Dictionary(global_settings_dict));
|
||||
|
||||
// Comment scope
|
||||
let mut comment_scope_dict = Dictionary::new();
|
||||
comment_scope_dict.insert("name".to_string(), Value::String("Comment".to_string()));
|
||||
comment_scope_dict.insert("scope".to_string(), Value::String("comment".to_string()));
|
||||
let mut comment_settings = Dictionary::new();
|
||||
comment_settings.insert("foreground".to_string(), Value::String(comment_color.to_string()));
|
||||
comment_settings.insert("fontStyle".to_string(), Value::String("italic".to_string()));
|
||||
comment_scope_dict.insert("settings".to_string(), Value::Dictionary(comment_settings));
|
||||
settings_array.push(Value::Dictionary(comment_scope_dict));
|
||||
|
||||
// String scope
|
||||
let mut string_scope_dict = Dictionary::new();
|
||||
string_scope_dict.insert("name".to_string(), Value::String("String".to_string()));
|
||||
string_scope_dict.insert("scope".to_string(), Value::String("string".to_string()));
|
||||
let mut string_settings = Dictionary::new();
|
||||
string_settings.insert("foreground".to_string(), Value::String(string_color.to_string()));
|
||||
string_scope_dict.insert("settings".to_string(), Value::Dictionary(string_settings));
|
||||
settings_array.push(Value::Dictionary(string_scope_dict));
|
||||
|
||||
// Keyword scope
|
||||
let mut keyword_scope_dict = Dictionary::new();
|
||||
keyword_scope_dict.insert("name".to_string(), Value::String("Keyword".to_string()));
|
||||
keyword_scope_dict.insert("scope".to_string(), Value::String("keyword".to_string()));
|
||||
let mut keyword_settings = Dictionary::new();
|
||||
keyword_settings.insert("foreground".to_string(), Value::String(keyword_color.to_string()));
|
||||
keyword_scope_dict.insert("settings".to_string(), Value::Dictionary(keyword_settings));
|
||||
settings_array.push(Value::Dictionary(keyword_scope_dict));
|
||||
|
||||
// Add more scopes as needed...
|
||||
|
||||
root_dict.insert("settings".to_string(), Value::Array(settings_array));
|
||||
|
||||
Value::Dictionary(root_dict)
|
||||
}
|
||||
@ -4,7 +4,6 @@ use egui_extras::syntax_highlighting::{self};
|
||||
|
||||
use super::find_highlight;
|
||||
|
||||
|
||||
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;
|
||||
@ -101,11 +100,15 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
|
||||
};
|
||||
|
||||
let language = super::languages::get_language_from_extension(active_tab.file_path.as_deref());
|
||||
let theme = crate::app::theme::create_code_theme_from_visuals(ui.visuals(), font_size);
|
||||
|
||||
let mut layouter = |ui: &egui::Ui, string: &dyn egui::TextBuffer, wrap_width: f32| {
|
||||
// let syntect_theme =
|
||||
// crate::app::theme::create_code_theme_from_visuals(ui.visuals(), font_size);
|
||||
let text = string.as_str();
|
||||
let theme = egui_extras::syntax_highlighting::CodeTheme::dark(font_size);
|
||||
let mut layout_job = if syntax_highlighting_enabled && language != "txt" {
|
||||
// let mut settings = egui_extras::syntax_highlighting::SyntectSettings::default();
|
||||
// settings.ts = syntect_theme;
|
||||
// syntax_highlighting::highlight_with(ui.ctx(), &ui.style().clone(), &theme, text, &language, &settings)
|
||||
syntax_highlighting::highlight(ui.ctx(), &ui.style().clone(), &theme, text, &language)
|
||||
} else {
|
||||
syntax_highlighting::highlight(ui.ctx(), &ui.style().clone(), &theme, text, "")
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
pub fn get_language_from_extension(file_path: Option<&std::path::Path>) -> String {
|
||||
if let Some(path) = file_path {
|
||||
let default_lang = "txt".to_string();
|
||||
|
||||
let path = match file_path {
|
||||
Some(p) => p,
|
||||
None => return default_lang,
|
||||
};
|
||||
|
||||
if let Some(extension) = path.extension().and_then(|ext| ext.to_str()) {
|
||||
match extension.to_lowercase().as_str() {
|
||||
"rs" => "rs".to_string(),
|
||||
@ -33,23 +39,17 @@ pub fn get_language_from_extension(file_path: Option<&std::path::Path>) -> Strin
|
||||
"vim" => "vim".to_string(),
|
||||
"dockerfile" => "dockerfile".to_string(),
|
||||
"makefile" => "makefile".to_string(),
|
||||
_ => "txt".to_string(),
|
||||
_ => default_lang,
|
||||
}
|
||||
} else {
|
||||
// Check filename for special cases
|
||||
if let Some(filename) = path.file_name().and_then(|name| name.to_str()) {
|
||||
} else 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(),
|
||||
_ => default_lang,
|
||||
}
|
||||
} else {
|
||||
"txt".to_string()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
"txt".to_string()
|
||||
default_lang
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user