diff --git a/Cargo.lock b/Cargo.lock index c2c348a..e1d9860 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -573,7 +573,6 @@ name = "calcifer" version = "0.1.1" dependencies = [ "eframe", - "egui_code_editor", "egui_extras", "env_logger", "image", @@ -939,15 +938,6 @@ dependencies = [ "winit", ] -[[package]] -name = "egui_code_editor" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3d41044cbf017fde94efde48b19637f63d94fa46dd6e41913cfeed74f023bc" -dependencies = [ - "egui", -] - [[package]] name = "egui_extras" version = "0.25.0" diff --git a/Cargo.toml b/Cargo.toml index 1d7ff3c..6ef8bd9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ env_logger = { version = "0.10.1", default-features = false, features = [ ] } rfd = "0.12.1" egui_extras = "0.25.0" -egui_code_editor = {version = "0.2.3"} image = "0.24.8" serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" diff --git a/calcifer_save.json b/calcifer_save.json index e72f6c1..bf40fac 100644 --- a/calcifer_save.json +++ b/calcifer_save.json @@ -1 +1 @@ -{"tabs":["/home/penwing/Documents/projects/rust/calcifer/src/main.rs","/home/penwing/Documents/notes/victory2.txt","/home/penwing/Documents/projects/rust/calcifer/src/tools/search.rs"],"theme":6} \ No newline at end of file +{"tabs":["/home/penwing/Documents/projects/rust/calcifer/src/main.rs","/home/penwing/Documents/notes/victory2.txt","/home/penwing/Documents/projects/rust/calcifer/src/tools/search.rs"],"theme":5} \ No newline at end of file diff --git a/src/calcifer.rs b/src/calcifer.rs index 60c8cef..b4868b3 100644 --- a/src/calcifer.rs +++ b/src/calcifer.rs @@ -1,9 +1,13 @@ use eframe::egui; -use eframe::egui::{text::CCursor, text_edit::CCursorRange}; +//use egui::{text::CCursor, text_edit::CCursorRange}; use std::{env, path::Path, path::PathBuf, cmp::max, io, fs, cmp::min}; use crate::tools; -use crate::tools::themes::CustomColorTheme; -use egui_code_editor::CodeEditor; +//use tools::themes::CustomColorTheme; + +pub mod code_editor; +use code_editor::CodeEditor; +use code_editor::themes::DEFAULT_THEMES; + impl super::Calcifer { @@ -18,8 +22,7 @@ impl super::Calcifer { .show_ui(ui, |ui| { ui.style_mut().wrap = Some(false); ui.set_min_width(60.0); - for i in 0..CustomColorTheme::max() { - let theme = CustomColorTheme::from_index(i); + for theme in DEFAULT_THEMES { ui.selectable_value(&mut self.theme, theme, theme.name); } }); @@ -119,7 +122,7 @@ impl super::Calcifer { }); } - 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| { ui.horizontal(|ui| { ui.label("Picked file:"); @@ -134,6 +137,45 @@ impl super::Calcifer { }); } + 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 scroll_area = egui::ScrollArea::vertical() + //.vertical_scroll_offset(current_tab.scroll_offset) + //.show(ui, |ui| { + let mut _output = CodeEditor::default() + .id_source("code editor") + .with_rows(max(80, lines)) + .with_fontsize(14.0) + .with_theme(self.theme) + .with_syntax(tools::to_syntax(¤t_tab.language)) + .with_numlines(true) + .show(ui, &mut current_tab.code); + //if !self.search.result_selected { + //output.state.set_ccursor_range(Some(CCursorRange::two( + //CCursor::new(self.search.get_cursor_start()), + //CCursor::new(self.search.get_cursor_end()), + //))); + //println!("Changed Cursor : from {} to {}", self.search.get_cursor_start(), self.search.get_cursor_end()); + //self.search.result_selected = true; + //} + //}); + //ui.label(format!("Scroll : {}", scroll_area.state.offset.y.clone())); + + if current_tab.history.len() < 1 { + current_tab.history.push(current_tab.code.clone()); + } + + if ¤t_tab.code != current_tab.history.last().expect("There should be an history") { + current_tab.history.push(current_tab.code.clone()); + current_tab.saved = false; + if current_tab.history.len() > super::HISTORY_LENGTH { + current_tab.history.remove(0); + } + } + } + pub fn save_tab(&self) -> Option { if self.tabs[self.selected_tab.to_index()].path.file_name().expect("Could not get Tab Name").to_string_lossy().to_string() == "untitled" { return self.save_tab_as(); @@ -178,7 +220,7 @@ impl super::Calcifer { pub fn from_app_state(app_state: tools::AppState) -> Self { let mut new = Self { - theme: tools::themes::CustomColorTheme::from_index(app_state.theme), + theme: DEFAULT_THEMES[min(app_state.theme, DEFAULT_THEMES.len() - 1)], tabs: Vec::new(), ..Default::default() }; @@ -197,7 +239,10 @@ impl super::Calcifer { } pub fn save_state(&self) { - let state_theme = tools::themes::CustomColorTheme::to_index(self.theme); + let mut state_theme : usize = 0; + if let Some(theme) = DEFAULT_THEMES.iter().position(|&r| r == self.theme) { + state_theme = theme; + } let mut state_tabs = vec![]; @@ -212,42 +257,6 @@ impl super::Calcifer { let _ = tools::save_state(&app_state, super::SAVE_PATH); } - 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; - - egui::ScrollArea::vertical().show(ui, |ui| { - let mut output = CodeEditor::default() - .id_source("code editor") - .with_rows(max(80, lines)) - .with_fontsize(14.0) - .with_theme(self.theme) - .with_syntax(tools::to_syntax(¤t_tab.language)) - .with_numlines(true) - .show(ui, &mut current_tab.code); - if !self.search.result_selected { - output.state.set_ccursor_range(Some(CCursorRange::two( - CCursor::new(self.search.get_cursor_start()), - CCursor::new(self.search.get_cursor_end()), - ))); - println!("Changed Cursor : from {} to {}", self.search.get_cursor_start(), self.search.get_cursor_end()); - self.search.result_selected = true; - } - }); - - if current_tab.history.len() < 1 { - current_tab.history.push(current_tab.code.clone()); - } - - if ¤t_tab.code != current_tab.history.last().expect("There should be an history") { - current_tab.history.push(current_tab.code.clone()); - current_tab.saved = false; - if current_tab.history.len() > super::HISTORY_LENGTH { - current_tab.history.remove(0); - } - } - } - fn list_files(&mut self, ui: &mut egui::Ui, path: &Path) -> io::Result<()> { if let Some(name) = path.file_name() { if path.is_dir() { @@ -284,6 +293,7 @@ impl super::Calcifer { language: path.to_str().unwrap().split('.').last().unwrap().into(), saved: true, history: vec![], + scroll_offset: 0.0, }; self.tabs.push(new_tab); diff --git a/src/calcifer/code_editor/highlighting.rs b/src/calcifer/code_editor/highlighting.rs new file mode 100644 index 0000000..a1a779c --- /dev/null +++ b/src/calcifer/code_editor/highlighting.rs @@ -0,0 +1,244 @@ +use super::syntax::{Syntax, TokenType, QUOTES, SEPARATORS}; +use std::mem; +use super::CodeEditor; +use eframe::egui::text::LayoutJob; +use eframe::egui; + +#[derive(Default, Debug, PartialEq, PartialOrd, Eq, Ord)] +/// Lexer and Token +pub struct Token { + ty: TokenType, + buffer: String, +} + +impl Token { + pub fn new>(ty: TokenType, buffer: S) -> Self { + Token { + ty, + buffer: buffer.into(), + } + } + pub fn ty(&self) -> TokenType { + self.ty + } + pub fn buffer(&self) -> &str { + &self.buffer + } + + fn first(&mut self, c: char, syntax: &Syntax) -> Option { + self.buffer.push(c); + let mut token = None; + self.ty = match c { + c if c.is_whitespace() => { + self.ty = TokenType::Whitespace(c); + token = self.drain(self.ty); + TokenType::Whitespace(c) + } + c if syntax.is_keyword(c.to_string().as_str()) => TokenType::Keyword, + c if syntax.is_type(c.to_string().as_str()) => TokenType::Type, + c if syntax.is_special(c.to_string().as_str()) => TokenType::Special, + c if syntax.comment == c.to_string().as_str() => TokenType::Comment(false), + c if syntax.comment_multiline[0] == c.to_string().as_str() => TokenType::Comment(true), + _ => TokenType::from(c), + }; + token + } + + fn drain(&mut self, ty: TokenType) -> Option { + let mut token = None; + if !self.buffer().is_empty() { + token = Some(Token { + buffer: mem::take(&mut self.buffer), + ty: self.ty, + }); + } + self.ty = ty; + token + } + + fn push_drain(&mut self, c: char, ty: TokenType) -> Option { + self.buffer.push(c); + self.drain(ty) + } + + fn drain_push(&mut self, c: char, ty: TokenType) -> Option { + let token = self.drain(self.ty); + self.buffer.push(c); + self.ty = ty; + token + } + + /// Syntax highlighting + pub fn highlight(&mut self, editor: &CodeEditor, text: &str) -> LayoutJob { + *self = Token::default(); + let mut job = LayoutJob::default(); + for c in text.chars() { + for token in self.automata(c, &editor.syntax) { + editor.append(&mut job, &token); + } + } + editor.append(&mut job, self); + job + } + + /// Lexer + pub fn tokens(&mut self, syntax: &Syntax, text: &str) -> Vec { + let mut tokens: Vec = text + .chars() + .flat_map(|c| self.automata(c, syntax)) + .collect(); + + if !self.buffer.is_empty() { + tokens.push(mem::take(self)); + } + tokens + } + + fn automata(&mut self, c: char, syntax: &Syntax) -> Vec { + use TokenType as Ty; + let mut tokens = vec![]; + match (self.ty, Ty::from(c)) { + (Ty::Comment(false), Ty::Whitespace('\n')) => { + self.buffer.push(c); + let n = self.buffer.pop(); + tokens.extend(self.drain(Ty::Whitespace(c))); + if let Some(n) = n { + tokens.extend(self.push_drain(n, self.ty)); + } + } + (Ty::Comment(false), _) => { + self.buffer.push(c); + } + (Ty::Comment(true), _) => { + self.buffer.push(c); + if self.buffer.ends_with(syntax.comment_multiline[1]) { + tokens.extend(self.drain(Ty::Unknown)); + } + } + (Ty::Literal | Ty::Punctuation(_), Ty::Whitespace(_)) => { + tokens.extend(self.drain(Ty::Whitespace(c))); + tokens.extend(self.first(c, syntax)); + } + (Ty::Literal, _) => match c { + c if c == '(' => { + self.ty = Ty::Function; + tokens.extend(self.drain(Ty::Punctuation(c))); + tokens.extend(self.push_drain(c, Ty::Unknown)); + } + c if !c.is_alphanumeric() && !SEPARATORS.contains(&c) => { + tokens.extend(self.drain(self.ty)); + self.buffer.push(c); + self.ty = if QUOTES.contains(&c) { + Ty::Str(c) + } else { + Ty::Punctuation(c) + }; + } + _ => { + self.buffer.push(c); + self.ty = { + if self.buffer.starts_with(syntax.comment) { + Ty::Comment(false) + } else if self.buffer.starts_with(syntax.comment_multiline[0]) { + Ty::Comment(true) + } else if syntax.is_keyword(&self.buffer) { + Ty::Keyword + } else if syntax.is_type(&self.buffer) { + Ty::Type + } else if syntax.is_special(&self.buffer) { + Ty::Special + } else { + Ty::Literal + } + }; + } + }, + (Ty::Numeric(false), Ty::Punctuation('.')) => { + self.buffer.push(c); + self.ty = Ty::Numeric(true); + } + (Ty::Numeric(_), Ty::Numeric(_)) => { + self.buffer.push(c); + } + (Ty::Numeric(_), Ty::Literal) => { + tokens.extend(self.drain(self.ty)); + self.buffer.push(c); + } + (Ty::Numeric(_), _) | (Ty::Punctuation(_), Ty::Literal | Ty::Numeric(_)) => { + tokens.extend(self.drain(self.ty)); + tokens.extend(self.first(c, syntax)); + } + (Ty::Punctuation(_), Ty::Str(_)) => { + tokens.extend(self.drain_push(c, Ty::Str(c))); + } + (Ty::Punctuation(_), _) => { + if !(syntax.comment.starts_with(&self.buffer) + || syntax.comment_multiline[0].starts_with(&self.buffer)) + { + tokens.extend(self.drain(self.ty)); + tokens.extend(self.first(c, syntax)); + } else { + self.buffer.push(c); + if self.buffer.starts_with(syntax.comment) { + self.ty = Ty::Comment(false); + } else if self.buffer.starts_with(syntax.comment_multiline[0]) { + self.ty = Ty::Comment(true); + } else if let Some(c) = self.buffer.pop() { + tokens.extend(self.drain(Ty::Punctuation(c))); + tokens.extend(self.first(c, syntax)); + } + } + } + (Ty::Str(q), _) => { + let control = self.buffer.ends_with('\\'); + self.buffer.push(c); + if c == q && !control { + tokens.extend(self.drain(Ty::Unknown)); + } + } + (Ty::Whitespace(_) | Ty::Unknown, _) => { + tokens.extend(self.first(c, syntax)); + } + // Keyword, Type, Special + (_reserved, Ty::Literal | Ty::Numeric(_)) => { + self.buffer.push(c); + self.ty = if syntax.is_keyword(&self.buffer) { + Ty::Keyword + } else if syntax.is_type(&self.buffer) { + Ty::Type + } else if syntax.is_special(&self.buffer) { + Ty::Special + } else { + Ty::Literal + }; + } + (reserved, _) => { + self.ty = reserved; + tokens.extend(self.drain(self.ty)); + tokens.extend(self.first(c, syntax)); + } + } + tokens + } +} + + + +impl eframe::egui::util::cache::ComputerMut<(&CodeEditor, &str), LayoutJob> for Token { + fn compute(&mut self, (cache, text): (&CodeEditor, &str)) -> LayoutJob { + self.highlight(cache, text) + } +} + +pub type HighlightCache = egui::util::cache::FrameCache; + +pub fn highlight(ctx: &egui::Context, cache: &CodeEditor, text: &str) -> LayoutJob { + ctx.memory_mut(|mem| mem.caches.cache::().get((cache, text))) +} + + +impl CodeEditor { + fn append(&self, job: &mut LayoutJob, token: &Token) { + job.append(token.buffer(), 0.0, self.format(token.ty())); + } +} diff --git a/src/calcifer/code_editor/mod.rs b/src/calcifer/code_editor/mod.rs new file mode 100644 index 0000000..3375cc1 --- /dev/null +++ b/src/calcifer/code_editor/mod.rs @@ -0,0 +1,228 @@ +#![allow(dead_code)] +pub mod highlighting; +mod syntax; +pub mod themes; + + +use eframe::egui::widgets::text_edit::TextEditOutput; +//use eframe::egui::ScrollArea; +use eframe::egui; +use highlighting::highlight; +//pub use highlighting::Token; +use std::hash::{Hash, Hasher}; +pub use syntax::{Syntax, TokenType}; +pub use themes::ColorTheme; +//pub use themes::DEFAULT_THEMES; + +#[derive(Clone, Debug, PartialEq)] +/// CodeEditor struct which stores settings for highlighting. +pub struct CodeEditor { + id: String, + theme: ColorTheme, + syntax: Syntax, + numlines: bool, + fontsize: f32, + rows: usize, + vscroll: bool, + stick_to_bottom: bool, + shrink: bool, +} + +impl Hash for CodeEditor { + fn hash(&self, state: &mut H) { + self.theme.hash(state); + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + (self.fontsize as u32).hash(state); + self.syntax.hash(state); + } +} + +impl Default for CodeEditor { + fn default() -> CodeEditor { + CodeEditor { + id: String::from("Code Editor"), + theme: ColorTheme::GRUVBOX, + syntax: Syntax::rust(), + numlines: true, + fontsize: 10.0, + rows: 10, + vscroll: true, + stick_to_bottom: false, + shrink: false, + } + } +} + +impl CodeEditor { + pub fn id_source(self, id_source: impl Into) -> Self { + CodeEditor { + id: id_source.into(), + ..self + } + } + + /// Minimum number of rows to show. + /// + /// **Default: 10** + pub fn with_rows(self, rows: usize) -> Self { + CodeEditor { rows, ..self } + } + + /// Use custom Color Theme + /// + /// **Default: Gruvbox** + pub fn with_theme(self, theme: ColorTheme) -> Self { + CodeEditor { theme, ..self } + } + + /// Use custom font size + /// + /// **Default: 10.0** + pub fn with_fontsize(self, fontsize: f32) -> Self { + CodeEditor { fontsize, ..self } + } + + #[cfg(feature = "egui")] + /// Use UI font size + pub fn with_ui_fontsize(self, ui: &mut egui::Ui) -> Self { + CodeEditor { + fontsize: egui::TextStyle::Monospace.resolve(ui.style()).size, + ..self + } + } + + /// Show or hide lines numbering + /// + /// **Default: true** + pub fn with_numlines(self, numlines: bool) -> Self { + CodeEditor { numlines, ..self } + } + + /// Use custom syntax for highlighting + /// + /// **Default: Rust** + pub fn with_syntax(self, syntax: Syntax) -> Self { + CodeEditor { syntax, ..self } + } + + /// Turn on/off scrolling on the vertical axis. + /// + /// **Default: true** + pub fn vscroll(self, vscroll: bool) -> Self { + CodeEditor { vscroll, ..self } + } + /// Should the containing area shrink if the content is small? + /// + /// **Default: false** + pub fn auto_shrink(self, shrink: bool) -> Self { + CodeEditor { shrink, ..self } + } + + /// Stick to bottom + /// The scroll handle will stick to the bottom position even while the content size + /// changes dynamically. This can be useful to simulate terminal UIs or log/info scrollers. + /// The scroll handle remains stuck until user manually changes position. Once "unstuck" + /// it will remain focused on whatever content viewport the user left it on. If the scroll + /// handle is dragged to the bottom it will again become stuck and remain there until manually + /// pulled from the end position. + /// + /// **Default: false** + pub fn stick_to_bottom(self, stick_to_bottom: bool) -> Self { + CodeEditor { + stick_to_bottom, + ..self + } + } + + pub fn format(&self, ty: TokenType) -> egui::text::TextFormat { + let font_id = egui::FontId::monospace(self.fontsize); + let color = self.theme.type_color(ty); + egui::text::TextFormat::simple(font_id, color) + } + + fn numlines_show(&self, ui: &mut egui::Ui, text: &str) { + let total = if text.ends_with('\n') || text.is_empty() { + text.lines().count() + 1 + } else { + text.lines().count() + } + .max(self.rows); + let max_indent = total.to_string().len(); + let mut counter = (1..=total) + .map(|i| { + let label = i.to_string(); + format!( + "{}{label}", + " ".repeat(max_indent.saturating_sub(label.len())) + ) + }) + .collect::>() + .join("\n"); + + #[allow(clippy::cast_precision_loss)] + let width = max_indent as f32 * self.fontsize * 0.5; + + let mut layouter = |ui: &egui::Ui, string: &str, _wrap_width: f32| { + let layout_job = egui::text::LayoutJob::single_section( + string.to_string(), + egui::TextFormat::simple( + egui::FontId::monospace(self.fontsize), + self.theme.type_color(TokenType::Comment(true)), + ), + ); + ui.fonts(|f| f.layout_job(layout_job)) + }; + + ui.add( + egui::TextEdit::multiline(&mut counter) + .id_source(format!("{}_numlines", self.id)) + .font(egui::TextStyle::Monospace) + .interactive(false) + .frame(false) + .desired_rows(self.rows) + .desired_width(width) + .layouter(&mut layouter), + ); + } + + //#[cfg(feature = "egui")] + /// Show Code Editor + pub fn show(&mut self, ui: &mut egui::Ui, text: &mut String) -> TextEditOutput { + let mut text_edit_output: Option = None; + let mut code_editor = |ui: &mut egui::Ui| { + ui.horizontal_top(|h| { + self.theme.modify_style(h, self.fontsize); + if self.numlines { + self.numlines_show(h, text); + } + egui::ScrollArea::horizontal() + .id_source(format!("{}_inner_scroll", self.id)) + .show(h, |ui| { + let mut layouter = |ui: &egui::Ui, string: &str, _wrap_width: f32| { + let layout_job = highlight(ui.ctx(), self, string); + ui.fonts(|f| f.layout_job(layout_job)) + }; + let output = egui::TextEdit::multiline(text) + .id_source(&self.id) + .lock_focus(true) + .desired_rows(self.rows) + .frame(true) + .desired_width(if self.shrink { 0.0 } else { f32::MAX }) + .layouter(&mut layouter) + .show(ui); + text_edit_output = Some(output); + }); + }); + }; + if self.vscroll { + egui::ScrollArea::vertical() + .id_source(format!("{}_outer_scroll", self.id)) + .stick_to_bottom(self.stick_to_bottom) + .show(ui, code_editor); + } else { + code_editor(ui); + } + + text_edit_output.expect("TextEditOutput should exist at this point") + } +} diff --git a/src/calcifer/code_editor/syntax/asm.rs b/src/calcifer/code_editor/syntax/asm.rs new file mode 100644 index 0000000..96796b9 --- /dev/null +++ b/src/calcifer/code_editor/syntax/asm.rs @@ -0,0 +1,1181 @@ +use super::Syntax; +use std::collections::BTreeSet; + +impl Syntax { + pub fn asm() -> Self { + Syntax { + language: "Assembly", + case_sensitive: false, + comment: ";", + comment_multiline: ["/*", "*/"], + keywords: BTreeSet::from([ + "vaddpd", + "divsd", + "vrcp14ps", + "haddps", + "outsd", + "scasw", + "vaesenclast", + "pcmpgtq", + "popcnt", + "lodsw", + "int", + "vbroadcasti64x4", + "rdpmc", + "prefetcht0", + "setnp", + "cvtpi2pd", + "cvtsd2si", + "vbroadcastf64x2", + "vscalefps", + "vfnmadd132sd", + "vpminuq", + "vfixupimmps", + "vcvtss2sd", + "vpminud", + "vfnmsub213sd", + "kshiftrb", + "vfpclassss", + "vaddsubpd", + "sar", + "vfnmadd231ss", + "monitor", + "vgatherqps", + "vmovdqu32", + "vpmovm2d", + "vprolvd", + "vpgatherdq", + "setae", + "aas", + "iret", + "vpsllw", + "vfmsub213pd", + "rcl", + "pavgw", + "vpsrlvw", + "vpandd", + "lldt", + "vcvtps2pd", + "vpabsw", + "vpmovzxbw", + "pmaxub", + "vpmovq2m", + "vpconflictd", + "jz", + "vcvtph2ps", + "vfmsub132ps", + "vpunpcklbw", + "vrsqrt28ss", + "movmskpd", + "fucompp", + "vpmulhuw", + "minpd", + "vpermi2ps", + "fninit1", + "pmaxsw", + "movntdq", + "vfnmsub231pd", + "vexpandpd", + "vsqrtss", + "setpe", + "vpgatherqq", + "vp4dpwssds", + "mul", + "fprem1", + "vcvtph2psx", + "cbw", + "minps", + "imm8", + "vpermt2w", + "addsubpd", + "kandnb", + "vpbroadcastd", + "vsubss", + "vpaddw", + "setnb", + "sha256rnds2", + "vmulss", + "vmovddup", + "movups", + "movupd", + "vfnmadd231sd", + "jnae", + "pblendvb", + "fdivr", + "psignw", + "packusdw", + "test", + "ib", + "scas", + "kaddd", + "vmovhps", + "movnti", + "paddsw", + "ib1", + "fld", + "pand", + "fldln2", + "hlt", + "rol", + "getsec", + "vpcmpeqq", + "pmullw", + "emms", + "vhsubpd", + "movsx", + "movapd", + "vpmaxuw", + "vpdpbusds", + "pcmpeqb", + "nop", + "vmovlpd", + "fdiv", + "divpd", + "vmovntdqa", + "mulss", + "jne", + "finit", + "packsswb", + "vrcpps", + "sha1nexte", + "vmulpd", + "pminud", + "subss", + "cmovnge", + "vpsubw", + "cvtpd2dq", + "or", + "rsqrtss", + "vpsubq", + "vpshldvd", + "cvtdq2ps", + "vpcmpgtw", + "vpacksswb", + "setp", + "xor", + "cvtpd2pi", + "movdiri", + "vpmullw", + "vpmovsdw", + "vxorps", + "vpmulhrsw", + "rdpkru", + "rcpps", + "vpminsb", + "vrcp28pd", + "jpe", + "fcomp", + "vpmaxsb", + "cvtps2pd", + "vandnpd", + "vmulps", + "vphaddsw", + "blendvps", + "kshiftrd", + "vfnmadd213ss", + "vhaddpd", + "aam", + "cmovnbe", + "wbinvd", + "paddusw", + "vcvtpd2udq", + "setnbe", + "kortestb", + "vmovdqu64", + "minss", + "vplzcntd", + "vpmovusdw", + "pmovzxdq", + "punpckhdq", + "vpunpckhwd", + "stos", + "cmove", + "ltr", + "fsubr", + "vpblendmq", + "setnz", + "setle", + "pminsb", + "kortestq", + "vpbroadcastw", + "vpminub", + "punpckhwd", + "fcmovbe", + "cqo", + "vpermilpd", + "sete", + "vpunpcklqdq", + "fimul", + "sets", + "movdqa", + "vorpd", + "rcpss", + "cmovns", + "vunpcklpd", + "idiv", + "pxor", + "fcmove", + "pmovzxbw", + "kxnorb", + "pmovmskb", + "xorps", + "fist", + "hsubpd", + "cmpxchg", + "vmaskmovps", + "movntps", + "pmaxuw", + "jl", + "vfmadd231ps", + "vpmovsxbq", + "pcmpgtd", + "in", + "vpcmpgtq", + "vpmaddwd", + "je", + "kortestw", + "vpexpandq", + "jnz", + "pcmpgtw", + "kmovb", + "prefetchnta", + "lsl", + "vmaxpd", + "lodsb", + "kunpckdq", + "vpmuludq", + "vrsqrtps", + "vpmaxuq", + "comiss", + "vpxor", + "unpckhpd", + "jo", + "vpsravw", + "pmuldq", + "shlx", + "vfmaddsub213pd", + "fclex", + "v4fmaddps", + "vpsubd", + "vbroadcastf128", + "vcvtsd2usi", + "vcompressps", + "cmovc", + "vp2intersectq", + "vpblendmd", + "fucomp", + "vrcp28sd", + "vfmsubadd132ps", + "popf", + "cvtss2si", + "cvttsd2si", + "pmaxsd", + "vrsqrt14ps", + "cvttps2dq", + "vpsignb", + "vmovhpd", + "vpexpandd", + "fisttp", + "vunpcklps", + "pext", + "lzcnt", + "cvtdq2pd", + "psubw", + "cvtsi2sd", + "pmovzxbq", + "pcmpeqd", + "vfmsub132pd", + "movmskps", + "fnclex1", + "vpmovm2q", + "cdq", + "bndcl", + "psadbw", + "cld", + "vpcompressq", + "fucomip", + "vcvttpd2dq", + "/is4", + "vpgatherqd", + "vaesenc", + "vmovmskps", + "vpmovsxbd", + "vpermi2q", + "vpmaxsq", + "addss", + "ib", + "vbroadcastf32x4", + "imul", + "vdivss", + "fisub", + "aesdeclast", + "cmovle", + "paddb", + "pmaxsb", + "vfnmsub213ps", + "vpermt2q", + "vandpd", + "vandps", + "vpmadd52huq", + "jc", + "kshiftrq", + "clc", + "pminub", + "vcvtps2udq", + "vpcompressb", + "vpcompressw", + "vfmsubadd231pd", + "setnl", + "vfmsub231ss", + "vfnmsub132pd", + "subpd", + "vpmovsqb", + "kord", + "invd", + "pushad", + "cmovge", + "vaesdec", + "les", + "vexp2ps", + "prefetcht1", + "pmulld", + "vpmovm2w", + "vpmovusqb", + "vrangess", + "rcr", + "fsubp", + "sha256msg1", + "vfnmadd132ss", + "jrcxz", + "vsqrtsd", + "vpmovdb", + "kaddq", + "vscalefss", + "paddq", + "bndmov", + "pmovsxbd", + "psrlq", + "fldl2t", + "vcvtqq2ps", + "vfmsub213sd", + "blendvpd", + "pmulhrsw", + "subps", + "vpermilps", + "pop", + "vpabsb", + "vdivpd", + "loop", + "adc", + "vmovaps", + "outsb", + "sha1msg2", + "vrsqrtss", + "vpmovusdb", + "vpavgw", + "jp", + "fcmovb", + "addps", + "addpd", + "kshiftld", + "pabsd", + "vpavgb", + "por", + "punpckldq", + "vfmadd132ps", + "vbroadcasti32x8", + "div", + "popfd", + "setns", + "jno", + "vmovss", + "tzcnt", + "cmovpe", + "vpackuswb", + "js", + "vptestnmb", + "punpcklqdq", + "vpsubsb", + "vmulsd", + "vfmsubadd213pd", + "vpmovd2m", + "kxorb", + "vpmovuswb", + "vpsignd", + "vfnmsub213pd", + "pdep", + "vpdpwssds", + "kxorq", + "vcvtdq2ps", + "vrsqrt28sd", + "btr", + "movs", + "kxnord", + "korb", + "pmovsxwq", + "movlps", + "sha256msg2", + "vptestmw", + "vmovd", + "vcvttss2usi", + "movddup", + "sysenter", + "vbroadcastf32x8", + "lds", + "vrcp14pd", + "vucomiss", + "vpaddusb", + "vfmaddsub132pd", + "comisd", + "cvttpd2dq", + "fprem", + "vpmadd52luq", + "vexp2pd", + "kxord", + "kunpckwd", + "scasd", + "psllw", + "ja", + "jnc", + "vmovshdup", + "stosw", + "vcvttsd2usi", + "v4fnmaddps", + "vtestps", + "paddw", + "movlhps", + "phsubw", + "vphminposuw", + "vpmovzxwq", + "vrsqrt28ps", + "vrsqrt14ss", + "vcvtdq2pd", + "vpsignw", + "vpsadbw", + "vhaddps", + "vplzcntq", + "bextr", + "lgdt", + "psubusw", + "vpminsd", + "vpermq", + "lidt", + "swapgs", + "invpcid", + "psignb", + "vptest", + "vpshldvq", + "fidiv", + "vpmaxsw", + "fldpi", + "aad", + "vfmadd132ss", + "kandnq", + "vbroadcastsd", + "vfnmsub213ss", + "sbb", + "cmovo", + "aesdec", + "cmps", + "outs", + "vcvttpd2qq", + "lgs", + "fcomip", + "cmovna", + "jnge", + "cvtsi2ss", + "lods", + "cmpsq", + "pmovsxbw", + "pmuludq", + "vpxord", + "gf2p8mulb", + "not", + "vmovsd", + "vpord", + "vpunpckldq", + "vcvttps2uqq", + "vfmsubadd231ps", + "fnsave1", + "vgetexpps", + "cmovno", + "vmovdqu8", + "ktestb", + "vaddsubps", + "vporq", + "vmaxsd", + "vpsubusb", + "pabsb", + "pmovsxbq", + "cvtps2pi", + "vpsraw", + "setnge", + "vorps", + "vcvttps2qq", + "vpcmpeqd", + "vfnmadd132ps", + "pmaddubsw", + "vbroadcastss", + "vpsrlvq", + "vpsraq", + "ud2", + "vmovdqu16", + "sub", + "wrmsr", + "vpsllvq", + "cvttss2si", + "wait", + "psubsw", + "cvtpd2ps", + "daa", + "movzx", + "fidivr", + "fisubr", + "fucomi", + "packuswb", + "vaddps", + "maskmovdqu", + "pmaddwd", + "pminuw", + "vpunpckhdq", + "fyl2xp1", + "kxnorq", + "movntdqa", + "vexpandps", + "vfnmsub132sd", + "vcvtps2phx", + "jnle", + "bound", + "movntpd", + "vpdpwssd", + "pmovsxdq", + "vptestnmd", + "mulps", + "ktestw", + "faddp", + "vlddqu", + "paddsb", + "vdivsd", + "paddd", + "vpmovwb", + "cmovl", + "movshdup", + "ror", + "vfnmadd231pd", + "vp2intersectd", + "cmovae", + "vsubps", + "vpaddd", + "vpandn", + "vrsqrt14sd", + "psubb", + "fcmovnb", + "iretq", + "vblendmps", + "cwd", + "cpuid", + "vpsravq", + "vptestmb", + "bzhi", + "vfmsub213ss", + "fstp", + "vbroadcasti128", + "kmovq", + "vpabsd", + "psignd", + "vcvtudq2pd", + "vpermt2d", + "vscalefsd", + "arpl", + "vpcmpgtd", + "cmpsb", + "vbroadcastf64x4", + "kshiftlw", + "lodsd", + "vpmovswb", + "vminss", + "vphaddw", + "vmovdqa64", + "fsave", + "vrcp28ps", + "vfmadd231ss", + "vxorpd", + "vscalefpd", + "kortestd", + "phaddsw", + "vpshufbitqmb", + "andnps", + "vcvtsi2ss", + "fnstenv1", + "lmsw", + "lodsq", + "vmovlps", + "vpcmpeqw", + "dec", + "kshiftrw", + "vpermt2pd", + "vpsrlvd", + "fldl2e", + "setb", + "vmovmskpd", + "vpsllvd", + "vmovdqa", + "bswap", + "vpermw", + "setbe", + "movlpd", + "vcvtusi2ss", + "jecxz", + "shr", + "vfmsub213ps", + "bts", + "fwait", + "vphsubw", + "bsr", + "vpermi2w", + "vpermps", + "scasq", + "vfnmadd132pd", + "cmpsd", + "orpd", + "aaa", + "andps", + "knotd", + "vpmulhw", + "vunpckhps", + "pslld", + "ktestq", + "pushf", + "sti", + "32", + "jcxz", + "unpcklpd", + "vpaddq", + "vbroadcastf32x2", + "vpmaskmovq", + "bndcn", + "vpsravd", + "xorpd", + "vpbroadcastq", + "aesimc", + "knotb", + "mulpd", + "vpmovsxwd", + "sldt", + "xsetbv", + "movsw", + "fsub", + "cvtpi2ps", + "vmovntpd", + "sqrtpd", + "vaesimc", + "bndmk", + "kshiftlq", + "maxpd", + "vpminsw", + "psrad", + "ficom", + "vtestpd", + "xlatb", + "vcvtsi2sd", + "vpackssdw", + "kandb", + "shrx", + "vpabsq", + "vrcpss", + "knotq", + "movsd", + "pmovsxwd", + "maxsd", + "mwait", + "enter", + "vpconflictq", + "vcvtps2uqq", + "vprorvq", + "cmovnc", + "phaddd", + "sysexit", + "vgetexpsd", + "movsq", + "vptestmq", + "pcmpeqw", + "vrcp28ss", + "vmovupd", + "fbld", + "vbroadcasti64x2", + "insw", + "vpshrdvq", + "vpbroadcastb", + "pcmpgtb", + "kandd", + "ins", + "vpsllvw", + "vfmadd213ss", + "vpcmpgtb", + "vfmsub231ps", + "pusha", + "fsubrp", + "setz", + "fsincos", + "vcvtpd2uqq", + "vpexpandw", + "vpandnd", + "cmpsw", + "rdtsc", + "mov", + "vpblendmb", + "vpcompressd", + "vpmovusqd", + "outsw", + "jng", + "fild", + "vcvtss2si", + "vpermi2d", + "sahf", + "cli", + "cvtps2dq", + "fdivrp", + "lar", + "setnle", + "vcvtsd2si", + "vminps", + "psubd", + "sqrtsd", + "vsubpd", + "fcom", + "vcomisd", + "inc", + "vpdpbusd", + "vcvtuqq2ps", + "cvttps2pi", + "vblendmpd", + "movsxd", + "vunpckhpd", + "pmovzxbd", + "vpmovqw", + "seta", + "psraw", + "kmovd", + "vfmadd213pd", + "vpaddsb", + "vgatherqpd", + "bndcu", + "vpsubusw", + "smsw", + "vpbroadcastmw2d", + "fptan", + "fmul", + "phsubd", + "vpmovzxbd", + "vandnps", + "vpandq", + "vcvttpd2udq", + "movdq2q", + "setge", + "vhsubps", + "vfmsubadd213ps", + "vpmovsxdq", + "vfmadd213sd", + "into", + "vfmsubadd132pd", + "pmulhuw", + "fiadd", + "setpo", + "vpopcntw", + "cmovb", + "psrlw", + "vpermd", + "vcvttsd2si", + "vpmovsxwq", + "fstenv", + "sha1msg1", + "vmovups", + "vfnmadd213ps", + "vpslld", + "vpaddusw", + "crc32", + "vfmadd213ps", + "vpermpd", + "pavgb", + "mulx", + "ret", + "vpopcntb", + "jbe", + "vfmadd132pd", + "int1", + "vfmadd231pd", + "movsldup", + "vcvtss2usi", + "psubq", + "setg", + "vpunpcklwd", + "repe", + "std", + "vpmullq", + "scasb", + "setne", + "maxps", + "pminsw", + "cmovnp", + "bndstx", + "vpmovsqw", + "fyl2x", + "adox", + "jnb", + "pmaxud", + "punpckhqdq", + "cwde", + "ibvpermilps", + "jnbe", + "cvtsd2ss", + "vfnmsub231ps", + "adcx", + "btc", + "vphaddd", + "sfence", + "movntq", + "jb", + "vpsllq", + "popfq", + "vptestnmq", + "vpmovb2m", + "vrsqrt14pd", + "vfmaddsub213ps", + "vdivps", + "andnpd", + "vcvtpd2ps", + "vfmaddsub132ps", + "vcvtne2ps2bf16", + "movdir64b", + "vpandnq", + "sqrtps", + "pcmpeqq", + "vpshrdvd", + "cmovpo", + "vpmovzxdq", + "v4fmaddss", + "cmovs", + "vpmovusqw", + "vmaxss", + "vcompresspd", + "vgetexpss", + "rsm", + "sal", + "knotw", + "kandnw", + "vminsd", + "syscall", + "vpsrld", + "vmovhlps", + "vptestmd", + "cmovnle", + "pause", + "xgetbv", + "movhpd", + "sqrtss", + "cmovng", + "vaddsd", + "cmovnl", + "vphsubsw", + "vptestnmw", + "jnl", + "vmovntps", + "andn", + "vfnmadd231ps", + "vcomiss", + "cmovp", + "xchg", + "iretd", + "stosd", + "pmovzxwd", + "vpmuldq", + "vpexpandb", + "vfmaddsub231ps", + "aesenc", + "clts", + "vpunpckhqdq", + "ucomiss", + "vpshldvw", + "minsd", + "vfnmadd213sd", + "vfmadd231sd", + "fstcw", + "kshiftlb", + "vsubsd", + "kaddb", + "vmovdqa32", + "phaddw", + "movhps", + "vcvttps2dq", + "pabsw", + "fst", + "maxss", + "orps", + "xlat", + "addsd", + "punpcklbw", + "vphsubd", + "setng", + "vmaxps", + "vrsqrt28pd", + "vpsrlq", + "vpbroadcastmb2q", + "addsubps", + "phsubsw", + "cmova", + "out", + "stosq", + "unpckhps", + "vpmovsdb", + "andpd", + "vpopcntd", + "vp4dpwssd", + "cmovg", + "vcvtqq2pd", + "vgatherdps", + "jnp", + "kmovw", + "ptest", + "ud01", + "cmovnb", + "loopne", + "fldlg2", + "jna", + "cmovnz", + "divps", + "hsubps", + "jmp", + "ucomisd", + "vcvtneps2bf16", + "vcvtudq2ps", + "vcvtusi2sd", + "vcvttps2udq", + "vpmaxub", + "vpermt2ps", + "vfmsub132sd", + "fxch", + "divss", + "vpgatherdd", + "vcvttss2si", + "mulsd", + "vpopcntq", + "vpmovzxwd", + "subsd", + "sarx", + "setnc", + "vgf2p8mulb", + "lddqu", + "jae", + "cmc", + "vpaddsw", + "vpcmpeqb", + "movaps", + "vmovntdq", + "vpxorq", + "setnae", + "vfnmsub231sd", + "fucom", + "vpblendmw", + "vpmultishiftqb", + "repne", + "vbroadcasti32x4", + "vpermi2pd", + "bsf", + "stc", + "vfmsub132ss", + "psllq", + "cmp", + "vpunpckhbw", + "vcvttpd2uqq", + "vpmovw2m", + "vfmadd132sd", + "vfnmsub132ss", + "jle", + "vpmovmskb", + "vmovdqu", + "vpsrlw", + "push", + "vmovapd", + "ficomp", + "kandw", + "vpmovdw", + "vpmulld", + "kaddw", + "fld1", + "verr", + "haddpd", + "pshufb", + "kxorw", + "verw", + "jg", + "korw", + "insd", + "vfmsub231sd", + "vgetexppd", + "str", + "kxnorw", + "vpminsq", + "vpmovsxbw", + "psrld", + "cdqe", + "setl", + "vpor", + "psubsb", + "vcvtuqq2pd", + "bndldx", + "vdpbf16ps", + "vfmsub231pd", + "vcvtpd2dq", + "fcmovnbe", + "movd", + "v4fnmaddss", + "unpcklps", + "shld", + "cmovnae", + "shrd", + "fistp", + "kunpckbw", + "setc", + "vmaskmovpd", + "vsqrtpd", + "vpsubb", + "vpermt2b", + "phminposuw", + "fldz", + "kandnd", + "cmovbe", + "fcomi", + "punpcklwd", + "jge", + "punpckhbw", + "vfnmsub132ps", + "vpmaddubsw", + "vpshrdvw", + "jpo", + "vmaskmovdqu", + "vaddss", + "movss", + "vsqrtps", + "movq", + "lfs", + "vpmaxsd", + "rep", + "fcmovnu", + "vrangesd", + "ud1", + "fmulp", + "fdivp", + "movdqu", + "vpmovm2b", + "vpmovqb", + "vpmovqd", + "vfnmadd213pd", + "xadd", + "vpmaskmovd", + "popa", + "movhlps", + "vmovq", + "movq2dq", + "vfnmsub231ss", + "shl", + "vpmovzxbq", + "insb", + "prefetcht2", + "ktestd", + "movbe", + "vpermi2b", + "aesenclast", + "vcvtsd2ss", + "vcvtpd2qq", + "lss", + "vcvtps2qq", + "setna", + "vmovlhps", + "vpsrad", + "leave", + "rdtscp", + "vcvtps2dq", + "seto", + "psubusb", + "loope", + "fcompp", + "movsb", + "pmovzxwq", + "vpmaxud", + "vucomisd", + "vmovsldup", + "vfmaddsub231pd", + "pandn", + "pmulhw", + "call", + "lock", + "korq", + "paddusb", + "rsqrtps", + "vaesdeclast", + "vpminuw", + "neg", + "vpackusdw", + "vgatherdpd", + "cmovne", + "fadd", + "vprolvq", + "fstsw", + "packssdw", + "sysret", + "popad", + "vpsubsw", + "lea", + "cvtss2sd", + "pushfd", + "vminpd", + "vbroadcasti32x2", + "kandq", + "das", + "stosb", + "add", + "vpand", + "vpshufb", + "vrcp14ss", + "jns", + "fcmovu", + "cmovz", + "and", + "bt", + "vpaddb", + "vpmovsqd", + "vrcp14sd", + "pushfq", + "int3", + "cvttpd2pi", + "fnstsw1", + "maskmovq", + "pminsd", + "fnstcw1", + "vprorvd", + "fcmovne", + "setno", + "vpermb", + ]), + types: BTreeSet::from(["ptr", "byte", "word", "dword", "qword"]), + special: BTreeSet::from([ + "RAX", "RBX", "RCX", "RDX", "RSI", "RDI", "RBP", "RSP", "R8", "R9", "R10", "R11", + "R12", "R13", "R14", "R15", // 64-bit registers + "EAX", "EBX", "ECX", "EDX", "ESI", "EDI", "EBP", "ESP", "R8D", "R9D", "R10D", + "R11D", "R12D", "R13D", "R14D", "R15D", // 32-bit registers + "AX", "BX", "CX", "DX", "SI", "DI", "BP", "SP", "R8W", "R9W", "R10W", "R11W", + "R12W", "R13W", "R14W", "R15W", // 16-bit registers + "AH", "BH", "CH", "DH", "AL", "BL", "CL", "DL", "SIL", "DIL", "BPL", "SPL", "R8B", + "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B", + // 8-bit registers + "XMM0", "XMM1", "XMM2", "XMM3", "XMM4", "XMM5", "XMM6", "XMM7", "XMM8", "XMM9", + "XMM10", "XMM11", "XMM12", "XMM13", "XMM14", "XMM15", // XMM + "YMM0", "YMM1", "YMM2", "YMM3", "YMM4", "YMM5", "YMM6", "YMM7", "YMM8", "YMM9", + "YMM10", "YMM11", "YMM12", "YMM13", "YMM14", "YMM15", // YMM + "ZMM0", "ZMM1", "ZMM2", "ZMM3", "ZMM4", "ZMM5", "ZMM6", "ZMM7", "ZMM8", "ZMM9", + "ZMM10", "ZMM11", "ZMM12", "ZMM13", "ZMM14", "ZMM15", + // ZMM + ]), + } + } +} diff --git a/src/calcifer/code_editor/syntax/lua.rs b/src/calcifer/code_editor/syntax/lua.rs new file mode 100644 index 0000000..1555ca7 --- /dev/null +++ b/src/calcifer/code_editor/syntax/lua.rs @@ -0,0 +1,21 @@ +use super::Syntax; +use std::collections::BTreeSet; + +impl Syntax { + pub fn lua() -> Syntax { + Syntax { + language: "Lua", + case_sensitive: true, + comment: "--", + comment_multiline: ["--[[", "]]"], + keywords: BTreeSet::from([ + "and", "break", "do", "else", "elseif", "end", "for", "function", "if", "in", + "local", "not", "or", "repeat", "return", "then", "until", "while", + ]), + types: BTreeSet::from([ + "boolean", "number", "string", "function", "userdata", "thread", "table", + ]), + special: BTreeSet::from(["false", "nil", "true"]), + } + } +} diff --git a/src/calcifer/code_editor/syntax/mod.rs b/src/calcifer/code_editor/syntax/mod.rs new file mode 100644 index 0000000..c67ef88 --- /dev/null +++ b/src/calcifer/code_editor/syntax/mod.rs @@ -0,0 +1,196 @@ +#![allow(dead_code)] +pub mod asm; +pub mod lua; +pub mod python; +pub mod rust; +pub mod shell; +pub mod sql; + +use std::collections::BTreeSet; +use std::hash::{Hash, Hasher}; + +pub const SEPARATORS: [char; 1] = ['_']; +pub const QUOTES: [char; 3] = ['\'', '"', '`']; + +type MultiLine = bool; +type Float = bool; + +#[derive(Default, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum TokenType { + Comment(MultiLine), + Function, + Keyword, + Literal, + Numeric(Float), + Punctuation(char), + Special, + Str(char), + Type, + Whitespace(char), + #[default] + Unknown, +} +impl std::fmt::Debug for TokenType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut name = String::new(); + match &self { + TokenType::Comment(multiline) => { + name.push_str("Comment"); + { + if *multiline { + name.push_str(" MultiLine"); + } else { + name.push_str(" SingleLine"); + } + } + } + TokenType::Function => name.push_str("Function"), + TokenType::Keyword => name.push_str("Keyword"), + TokenType::Literal => name.push_str("Literal"), + TokenType::Numeric(float) => { + name.push_str("Numeric"); + if *float { + name.push_str(" Float"); + } else { + name.push_str(" Integer"); + } + } + TokenType::Punctuation(_) => name.push_str("Punctuation"), + TokenType::Special => name.push_str("Special"), + TokenType::Str(quote) => { + name.push_str("Str "); + name.push(*quote); + } + TokenType::Type => name.push_str("Type"), + TokenType::Whitespace(c) => { + name.push_str("Whitespace"); + match c { + ' ' => name.push_str(" Space"), + '\t' => name.push_str(" Tab"), + '\n' => name.push_str(" New Line"), + _ => (), + }; + } + TokenType::Unknown => name.push_str("Unknown"), + }; + write!(f, "{name}") + } +} +impl From for TokenType { + fn from(c: char) -> Self { + match c { + c if c.is_whitespace() => TokenType::Whitespace(c), + c if QUOTES.contains(&c) => TokenType::Str(c), + c if c.is_numeric() => TokenType::Numeric(false), + c if c.is_alphabetic() || SEPARATORS.contains(&c) => TokenType::Literal, + c if c.is_ascii_punctuation() => TokenType::Punctuation(c), + _ => TokenType::Unknown, + } + } +} + +#[derive(Clone, Debug, PartialEq)] +/// Rules for highlighting. +pub struct Syntax { + pub language: &'static str, + pub case_sensitive: bool, + pub comment: &'static str, + pub comment_multiline: [&'static str; 2], + pub keywords: BTreeSet<&'static str>, + pub types: BTreeSet<&'static str>, + pub special: BTreeSet<&'static str>, +} +impl Default for Syntax { + fn default() -> Self { + Syntax::rust() + } +} +impl Hash for Syntax { + fn hash(&self, state: &mut H) { + self.language.hash(state); + } +} +impl Syntax { + pub fn new(language: &'static str) -> Self { + Syntax { + language, + ..Default::default() + } + } + pub fn with_case_sensitive(self, case_sensitive: bool) -> Self { + Syntax { + case_sensitive, + ..self + } + } + pub fn with_comment(self, comment: &'static str) -> Self { + Syntax { comment, ..self } + } + pub fn with_comment_multiline(self, comment_multiline: [&'static str; 2]) -> Self { + Syntax { + comment_multiline, + ..self + } + } + pub fn with_keywords>>(self, keywords: T) -> Self { + Syntax { + keywords: keywords.into(), + ..self + } + } + pub fn with_types>>(self, types: T) -> Self { + Syntax { + types: types.into(), + ..self + } + } + pub fn with_special>>(self, special: T) -> Self { + Syntax { + special: special.into(), + ..self + } + } + + pub fn language(&self) -> &str { + self.language + } + pub fn comment(&self) -> &str { + self.comment + } + pub fn is_keyword(&self, word: &str) -> bool { + if self.case_sensitive { + self.keywords.contains(&word) + } else { + self.keywords.contains(word.to_ascii_uppercase().as_str()) + } + } + pub fn is_type(&self, word: &str) -> bool { + if self.case_sensitive { + self.types.contains(&word) + } else { + self.types.contains(word.to_ascii_uppercase().as_str()) + } + } + pub fn is_special(&self, word: &str) -> bool { + if self.case_sensitive { + self.special.contains(&word) + } else { + self.special.contains(word.to_ascii_uppercase().as_str()) + } + } +} + +impl Syntax { + pub fn simple(comment: &'static str) -> Self { + Syntax { + language: "", + case_sensitive: false, + comment, + comment_multiline: [comment; 2], + keywords: BTreeSet::new(), + types: BTreeSet::new(), + special: BTreeSet::new(), + } + } +} diff --git a/src/calcifer/code_editor/syntax/python.rs b/src/calcifer/code_editor/syntax/python.rs new file mode 100644 index 0000000..48dacec --- /dev/null +++ b/src/calcifer/code_editor/syntax/python.rs @@ -0,0 +1,36 @@ +use super::Syntax; +use std::collections::BTreeSet; + +impl Syntax { + pub fn python() -> Syntax { + Syntax { + language: "Python", + case_sensitive: true, + comment: "#", + comment_multiline: [r#"'''"#, r#"'''"#], + keywords: BTreeSet::from([ + "and", "as", "assert", "break", "class", "continue", "def", "del", "elif", "else", + "except", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", + "nonlocal", "not", "or", "pass", "raise", "return", "try", "while", "with", + "yield", + ]), + types: BTreeSet::from([ + "bool", + "int", + "float", + "complex", + "str", + "list", + "tuple", + "range", + "bytes", + "bytearray", + "memoryview", + "dict", + "set", + "frozenset", + ]), + special: BTreeSet::from(["False", "None", "True"]), + } + } +} diff --git a/src/calcifer/code_editor/syntax/rust.rs b/src/calcifer/code_editor/syntax/rust.rs new file mode 100644 index 0000000..94f6f64 --- /dev/null +++ b/src/calcifer/code_editor/syntax/rust.rs @@ -0,0 +1,87 @@ +use super::Syntax; +use std::collections::BTreeSet; + +impl Syntax { + pub fn rust() -> Self { + Syntax { + language: "Rust", + case_sensitive: true, + comment: "//", + comment_multiline: ["/*", "*/"], + keywords: BTreeSet::from([ + "as", "break", "const", "continue", "crate", "else", "enum", "extern", "fn", "for", + "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", + "return", "self", "struct", "super", "trait", "type", "use", "where", "while", + "async", "await", "abstract", "become", "box", "do", "final", "macro", "override", + "priv", "typeof", "unsized", "virtual", "yield", "try", "unsafe", "dyn", + ]), + types: BTreeSet::from([ + "Option", + "Result", + "Error", + "Box", + "Cow", + // Primitives + "bool", + "i8", + "u8", + "i16", + "u16", + "i32", + "u32", + "i64", + "u64", + "i128", + "u128", + "isize", + "usize", + "f32", + "f64", + "char", + "str", + "String", + // STD Collections + "Vec", + "BTreeMap", + "BTreeSet", + "BTreeMap", + "BTreeSet", + "VecDeque", + "BinaryHeap", + "LinkedList", + // RC + "Rc", + "Weak", + "LazyCell", + "SyncUnsafeCell", + "BorrowErrorl", + "BorrowMutErrorl", + "Celll", + "OnceCelll", + "Refl", + "RefCelll", + "RefMutl", + "UnsafeCell", + "Exclusive", + "LazyLock", + // ARC + "Arc", + "Barrier", + "BarrierWaitResult", + "Condvar", + "Mutex", + "MutexGuard", + "Once", + "OnceLock", + "OnceState", + "PoisonError", + "RwLock", + "RwLockReadGuard", + "RwLockWriteGuard", + "WaitTimeoutResult", + "Weak", + ]), + special: BTreeSet::from(["Self", "static", "true", "false"]), + } + } +} diff --git a/src/calcifer/code_editor/syntax/shell.rs b/src/calcifer/code_editor/syntax/shell.rs new file mode 100644 index 0000000..9834c49 --- /dev/null +++ b/src/calcifer/code_editor/syntax/shell.rs @@ -0,0 +1,40 @@ +use super::Syntax; +use std::collections::BTreeSet; + +impl Syntax { + pub fn shell() -> Self { + Syntax { + language: "Shell", + case_sensitive: true, + comment: "#", + keywords: BTreeSet::from([ + "echo", "read", "set", "unset", "readonly", "shift", "export", "if", "fi", "else", + "while", "do", "done", "for", "until", "case", "esac", "break", "continue", "exit", + "return", "trap", "wait", "eval", "exec", "ulimit", "umask", + ]), + comment_multiline: [": '", "'"], + types: BTreeSet::from([ + "ENV", + "HOME", + "IFS", + "LANG", + "LC_ALL", + "LC_COLLATE", + "LC_CTYPE", + "LC_MESSAGES", + "LINENO", + "NLSPATH", + "PATH", + "PPID", + "PS1", + "PS2", + "PS4", + "PWD", + ]), + special: BTreeSet::from([ + "alias", "bg", "cd", "command", "false", "fc", "fg", "getopts", "jobs", "kill", + "newgrp", "pwd", "read", "true", "umask", "unalias", "wait", + ]), + } + } +} diff --git a/src/calcifer/code_editor/syntax/sql.rs b/src/calcifer/code_editor/syntax/sql.rs new file mode 100644 index 0000000..b942313 --- /dev/null +++ b/src/calcifer/code_editor/syntax/sql.rs @@ -0,0 +1,137 @@ +use super::Syntax; +use std::collections::BTreeSet; + +impl Syntax { + pub fn sql() -> Self { + Syntax { + language: "SQL", + case_sensitive: false, + comment: "--", + comment_multiline: ["/*", "*/"], + keywords: BTreeSet::from([ + "ADD", + "ALL", + "ALTER", + "AND", + "ANY", + "AS", + "ASC", + "BACKUP", + "BETWEEN", + "CASE", + "CHECK", + "COLUMN", + "CONSTRAINT", + "CREATE", + "INDEX", + "OR", + "REPLACE", + "VIEW", + "PROCEDURE", + "UNIQUE", + "DEFAULT", + "DELETE", + "DESC", + "DISTINCT", + "DROP", + "PRIMARY", + "FOREIGN", + "EXEC", + "EXISTS", + "FROM", + "FULL", + "OUTER", + "JOIN", + "GROUP", + "BY", + "HAVING", + "IN", + "INNER", + "INSERT", + "INTO", + "SELECT", + "IS", + "KEY", + "NOT", + "NULL", + "LEFT", + "LIKE", + "LIMIT", + "ORDER", + "A", + "RIGHT", + "ROWNUM", + "TOP", + "TOPDOWN", //FIXME + "TRUNCATE", + "UNION", + "UPDATE", + "VALUES", + "WHERE", + "WITH", + ]), + types: BTreeSet::from([ + "BOOL", + "INTEGER", + "SMALLINT", + "BIGINT", + "REAL", + "DOUBLEPRECISION", + "VARCHAR", + "NUMBER", + "CHAR", + "TEXT", + "DATE", + "TIMESTAMP", + "UUID", + "BYTEA", + "LOB", + "BLOB", + "CLOB", + "BIGINT", + "NUMERIC", + "BIT", + "SMALLINT", + "DECIMAL", + "SMALLMONEY", + "INT", + "INT4", + "INT8", + "INT16", + "INT32", + "INT64", + "INT128", + "TINYINT", + "MONEY", + "FLOAT", + "REAL", + "DATE", + "DATETIMEOFFSET", + "DATETIME2", + "SMALLDATETIME", + "DATETIME", + "TIME", + "CHAR", + "VARCHAR", + "VARCHAR2", + "TEXT", + "NCHAR", + "NVARCHAR", + "NTEXT", + "BINARY", + "VARBINARY", + "IMAGE", + "ROWVERSION", + "HIERARCHYID", + "UNIQUEIDENTIFIER", + "SQL_VARIANT", + "XML", + "XMLTYPE", + "TABLE", + "SET", + "DATABASE", + ]), + special: BTreeSet::from(["PUBLIC"]), + } + } +} diff --git a/src/calcifer/code_editor/tests.rs b/src/calcifer/code_editor/tests.rs new file mode 100644 index 0000000..fa35dc7 --- /dev/null +++ b/src/calcifer/code_editor/tests.rs @@ -0,0 +1,65 @@ +use super::*; + +#[test] +fn numeric_float() { + assert_eq!( + Token::default().tokens(&Syntax::default(), "3.14"), + [Token::new(TokenType::Numeric(true), "3.14")] + ); +} + +#[test] +fn numeric_float_desription() { + assert_eq!( + Token::default().tokens(&Syntax::default(), "3.14_f32"), + [ + Token::new(TokenType::Numeric(true), "3.14"), + Token::new(TokenType::Numeric(true), "_"), + Token::new(TokenType::Numeric(true), "f32") + ] + ); +} + +#[test] +fn numeric_float_second_dot() { + assert_eq!( + Token::default().tokens(&Syntax::default(), "3.14.032"), + [ + Token::new(TokenType::Numeric(true), "3.14"), + Token::new(TokenType::Punctuation('.'), "."), + Token::new(TokenType::Numeric(false), "032") + ] + ); +} + +#[test] +fn simple_rust() { + let syntax = Syntax::rust(); + let input = vec![ + Token::new(TokenType::Keyword, "fn"), + Token::new(TokenType::Whitespace(' '), " "), + Token::new(TokenType::Function, "function"), + Token::new(TokenType::Punctuation('('), "("), + Token::new(TokenType::Str('\"'), "\"String\""), + Token::new(TokenType::Punctuation(')'), ")"), + Token::new(TokenType::Punctuation('{'), "{"), + Token::new(TokenType::Whitespace('\n'), "\n"), + Token::new(TokenType::Whitespace('\t'), "\t"), + Token::new(TokenType::Keyword, "let"), + Token::new(TokenType::Whitespace(' '), " "), + Token::new(TokenType::Literal, "x_0"), + Token::new(TokenType::Punctuation(':'), ":"), + Token::new(TokenType::Whitespace(' '), " "), + Token::new(TokenType::Type, "f32"), + Token::new(TokenType::Whitespace(' '), " "), + Token::new(TokenType::Punctuation('='), "="), + Token::new(TokenType::Numeric(true), "13.34"), + Token::new(TokenType::Punctuation(';'), ";"), + Token::new(TokenType::Whitespace('\n'), "\n"), + Token::new(TokenType::Punctuation('}'), "}"), + ]; + let str = input.iter().map(|h| h.buffer()).collect::(); + let output = Token::default().tokens(&syntax, &str); + println!("{str}"); + assert_eq!(input, output); +} diff --git a/src/calcifer/code_editor/themes/ayu.rs b/src/calcifer/code_editor/themes/ayu.rs new file mode 100644 index 0000000..3c60f21 --- /dev/null +++ b/src/calcifer/code_editor/themes/ayu.rs @@ -0,0 +1,57 @@ +use super::ColorTheme; + +impl ColorTheme { + /// Author: André Sá + /// + /// Based on the AYU theme colors from + pub const AYU: ColorTheme = ColorTheme { + name: "Ayu", + dark: false, + bg: "#fafafa", + cursor: "#5c6166", // foreground + selection: "#fa8d3e", // orange + comments: "#828c9a", // gray + functions: "#ffaa33", // yellow + keywords: "#fa8d3e", // orange + literals: "#5c6166", // foreground + numerics: "#a37acc", // magenta + punctuation: "#5c6166", // foreground + strs: "#86b300", // green + types: "#399ee6", // blue + special: "#f07171", // red + }; + + pub const AYU_MIRAGE: ColorTheme = ColorTheme { + name: "Ayu Mirage", + dark: true, + bg: "#1f2430", + cursor: "#cccac2", // foreground + selection: "#ffad66", // orange + comments: "#565b66", // gray + functions: "#ffcc77", // yellow + keywords: "#ffad66", // orange + literals: "#cccac2", // foreground + numerics: "#dfbfff", // magenta + punctuation: "#cccac2", // foreground + strs: "#d5ff80", // green + types: "#73d0ff", // blue + special: "#f28779", // red + }; + + pub const AYU_DARK: ColorTheme = ColorTheme { + name: "Ayu Dark", + dark: true, + bg: "#0f1419", + cursor: "#bfbdb6", // foreground + selection: "#ffad66", // orange + comments: "#5c6773", // gray + functions: "#e6b450", // yellow + keywords: "#ffad66", // orange + literals: "#bfbdb6", // foreground + numerics: "#dfbfff", // magenta + punctuation: "#bfbdb6", // foreground + strs: "#aad94c", // green + types: "#59c2ff", // blue + special: "#f28779", // red + }; +} diff --git a/src/calcifer/code_editor/themes/fantasy.rs b/src/calcifer/code_editor/themes/fantasy.rs new file mode 100644 index 0000000..9e073cd --- /dev/null +++ b/src/calcifer/code_editor/themes/fantasy.rs @@ -0,0 +1,39 @@ +use super::ColorTheme; + +impl ColorTheme { + /// Original Author: sainnhe + /// Modified by p4ymak + pub const FIRE: ColorTheme = ColorTheme { + name: "Fire", + dark: true, + bg: "#242424", + cursor: "#dadada", // foreground + selection: "#444852", // dunno + comments: "#656565", // dark_gray + functions: "#ffad69", // light orange + keywords: "#48b1a7", // mid green + literals: "#d2d2d3", // + numerics: "#ff7b4f", // orange + punctuation: "#989898", // gray + strs: "#cbd5a1", // light_green + types: "#038e83", // dark_green + special: "#48b1a7", // mid green + }; + + pub const ASH: ColorTheme = ColorTheme { + name: "Ash", + dark: true, + bg: "#101010", + cursor: "#eaeaea", + selection: "#505050", + comments: "#656565", + functions: "#a0a0a0", + keywords: "#848484", + literals: "#d2d2d2", + numerics: "#d2d2d2", + punctuation: "#848484", + strs: "#a0a0a0", + types: "#c6c6c6", + special: "#848484", + }; +} diff --git a/src/calcifer/code_editor/themes/github.rs b/src/calcifer/code_editor/themes/github.rs new file mode 100644 index 0000000..f190b5a --- /dev/null +++ b/src/calcifer/code_editor/themes/github.rs @@ -0,0 +1,39 @@ +use super::ColorTheme; + +impl ColorTheme { + /// Author : OwOSwordsman + /// An unofficial GitHub theme, generated using colors from: + pub const GITHUB_DARK: ColorTheme = ColorTheme { + name: "Github Dark", + dark: true, + bg: "#0d1117", // default + cursor: "#d29922", // attention.fg + selection: "#0c2d6b", // scale.blue.8 + comments: "#8b949e", // fg.muted + functions: "#d2a8ff", // scale.purple.2 + keywords: "#ff7b72", // scale.red.3 + literals: "#c9d1d9", // fg.default + numerics: "#79c0ff", // scale.blue.2 + punctuation: "#c9d1d9", // fg.default + strs: "#a5d6ff", // scale.blue.1 + types: "#ffa657", // scale.orange.2 + special: "#a5d6ff", // scale.blue.1 + }; + + pub const GITHUB_LIGHT: ColorTheme = ColorTheme { + name: "Github Light", + dark: false, + bg: "#ffffff", // default + cursor: "#000000", // invert + selection: "#0550ae", // scale.blue.6 + comments: "#57606a", // fg.muted + functions: "#8250df", // done.fg + keywords: "#cf222e", // scale.red.5 + literals: "#24292f", // fg.default + numerics: "#0550ae", // scale.blue.6 + punctuation: "#24292f", // fg.default + strs: "#0a3069", // scale.blue.8 + types: "#953800", // scale.orange.6 + special: "#a475f9", // scale.purple.4 + }; +} diff --git a/src/calcifer/code_editor/themes/gruvbox.rs b/src/calcifer/code_editor/themes/gruvbox.rs new file mode 100644 index 0000000..0366f84 --- /dev/null +++ b/src/calcifer/code_editor/themes/gruvbox.rs @@ -0,0 +1,41 @@ +use super::ColorTheme; + +impl ColorTheme { + /// Author : Jakub Bartodziej + /// Theme uses the gruvbox dark palette with standard contrast + pub const GRUVBOX: ColorTheme = ColorTheme { + name: "Gruvbox", + dark: true, + bg: "#282828", + cursor: "#a89984", // fg4 + selection: "#504945", // bg2 + comments: "#928374", // gray1 + functions: "#b8bb26", // green1 + keywords: "#fb4934", // red1 + literals: "#ebdbb2", // fg1 + numerics: "#d3869b", // purple1 + punctuation: "#fe8019", // orange1 + strs: "#8ec07c", // aqua1 + types: "#fabd2f", // yellow1 + special: "#83a598", // blue1 + }; + + pub const GRUVBOX_DARK: ColorTheme = ColorTheme::GRUVBOX; + + pub const GRUVBOX_LIGHT: ColorTheme = ColorTheme { + name: "Gruvbox Light", + dark: false, + bg: "#fbf1c7", + cursor: "#7c6f64", // fg4 + selection: "#b57614", // yellow1 + comments: "#7c6f64", // gray1 + functions: "#79740e", // green1 + keywords: "#9d0006", // red1 + literals: "#282828", // fg1 + numerics: "#8f3f71", // purple1 + punctuation: "#af3a03", // orange1 + strs: "#427b58", // aqua1 + types: "#b57614", // yellow1 + special: "#af3a03", // orange1 + }; +} diff --git a/src/calcifer/code_editor/themes/mod.rs b/src/calcifer/code_editor/themes/mod.rs new file mode 100644 index 0000000..aeee5db --- /dev/null +++ b/src/calcifer/code_editor/themes/mod.rs @@ -0,0 +1,148 @@ +#![allow(dead_code)] +pub mod ayu; +pub mod github; +pub mod gruvbox; +pub mod sonokai; +pub mod fantasy; + +use super::syntax::TokenType; + +use eframe::egui; +use egui::Color32; + +pub const ERROR_COLOR: Color32 = Color32::from_rgb(255, 0, 255); + +/// Array of default themes. +pub const DEFAULT_THEMES: [ColorTheme; 7] = [ + ColorTheme::AYU_MIRAGE, + ColorTheme::AYU_DARK, + ColorTheme::GITHUB_DARK, + ColorTheme::GRUVBOX, + ColorTheme::SONOKAI, + ColorTheme::FIRE, + ColorTheme::ASH, +]; + +fn color_from_hex(hex: &str) -> Option { + if hex == "none" { + return Some(Color32::from_rgba_premultiplied(255, 0, 255, 0)); + } + let rgb = (1..hex.len()) + .step_by(2) + .filter_map(|i| u8::from_str_radix(&hex[i..i + 2], 16).ok()) + .collect::>(); + let color = Color32::from_rgb(*rgb.first()?, *rgb.get(1)?, *rgb.get(2)?); + Some(color) +} + +#[derive(Hash, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +/// Colors in hexadecimal notation as used in HTML and CSS. +pub struct ColorTheme { + pub name: &'static str, + pub dark: bool, + pub bg: &'static str, + pub cursor: &'static str, + pub selection: &'static str, + pub comments: &'static str, + pub functions: &'static str, + pub keywords: &'static str, + pub literals: &'static str, + pub numerics: &'static str, + pub punctuation: &'static str, + pub strs: &'static str, + pub types: &'static str, + pub special: &'static str, +} +impl Default for ColorTheme { + fn default() -> Self { + ColorTheme::GRUVBOX + } +} +impl ColorTheme { + pub fn name(&self) -> &str { + self.name + } + + pub fn is_dark(&self) -> bool { + self.dark + } + + pub fn bg(&self) -> Color32 { + color_from_hex(self.bg).unwrap_or(ERROR_COLOR) + } + + pub fn cursor(&self) -> Color32 { + color_from_hex(self.cursor).unwrap_or(ERROR_COLOR) + } + + pub fn selection(&self) -> Color32 { + color_from_hex(self.selection).unwrap_or(ERROR_COLOR) + } + + pub fn modify_style(&self, ui: &mut egui::Ui, fontsize: f32) { + let style = ui.style_mut(); + style.visuals.widgets.noninteractive.bg_fill = self.bg(); + style.visuals.window_fill = self.bg(); + style.visuals.selection.stroke.color = self.cursor(); + style.visuals.selection.bg_fill = self.selection(); + style.visuals.extreme_bg_color = self.bg(); + style.override_font_id = Some(egui::FontId::monospace(fontsize)); + style.visuals.text_cursor.width = fontsize * 0.1; + } + + pub const fn type_color_str(&self, ty: TokenType) -> &'static str { + match ty { + TokenType::Comment(_) => self.comments, + TokenType::Function => self.functions, + TokenType::Keyword => self.keywords, + TokenType::Literal => self.literals, + TokenType::Numeric(_) => self.numerics, + TokenType::Punctuation(_) => self.punctuation, + TokenType::Special => self.special, + TokenType::Str(_) => self.strs, + TokenType::Type => self.types, + TokenType::Whitespace(_) | TokenType::Unknown => self.comments, + } + } + + pub fn type_color(&self, ty: TokenType) -> Color32 { + match ty { + TokenType::Comment(_) => color_from_hex(self.comments), + TokenType::Function => color_from_hex(self.functions), + TokenType::Keyword => color_from_hex(self.keywords), + TokenType::Literal => color_from_hex(self.literals), + TokenType::Numeric(_) => color_from_hex(self.numerics), + TokenType::Punctuation(_) => color_from_hex(self.punctuation), + TokenType::Special => color_from_hex(self.special), + TokenType::Str(_) => color_from_hex(self.strs), + TokenType::Type => color_from_hex(self.types), + TokenType::Whitespace(_) | TokenType::Unknown => color_from_hex(self.comments), + } + .unwrap_or(ERROR_COLOR) + } + + pub fn monocolor( + dark: bool, + bg: &'static str, + fg: &'static str, + cursor: &'static str, + selection: &'static str, + ) -> Self { + ColorTheme { + name: "monocolor", + dark, + bg, + cursor, + selection, + literals: fg, + numerics: fg, + keywords: fg, + functions: fg, + punctuation: fg, + types: fg, + strs: fg, + comments: fg, + special: fg, + } + } +} diff --git a/src/calcifer/code_editor/themes/sonokai.rs b/src/calcifer/code_editor/themes/sonokai.rs new file mode 100644 index 0000000..646e904 --- /dev/null +++ b/src/calcifer/code_editor/themes/sonokai.rs @@ -0,0 +1,22 @@ +use super::ColorTheme; + +impl ColorTheme { + /// Original Author: sainnhe + /// Modified by p4ymak + pub const SONOKAI: ColorTheme = ColorTheme { + name: "Sonokai", + dark: true, + bg: "#2c2e34", // bg0 + cursor: "#76cce0", // blue + selection: "#444852", // bg5 + comments: "#7f8490", // gray + functions: "#9ed072", // green + keywords: "#fc5d7c", // red + literals: "#e2e2e3", // foreground + numerics: "#b39df3", // purple + punctuation: "#7f8490", // gray + strs: "#e7c664", // yellow + types: "#399ee6", // blue + special: "#f39660", // orange + }; +} diff --git a/src/main.rs b/src/main.rs index 346d57b..d3b1a34 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ - mod tools; mod calcifer; use eframe::egui; -use egui_code_editor::ColorTheme; +use calcifer::code_editor::ColorTheme; use std::{path::Path, sync::Arc}; use tools::Demo; +use calcifer::code_editor::themes::DEFAULT_THEMES; const TERMINAL_HEIGHT : f32 = 200.0; const RED : egui::Color32 = egui::Color32::from_rgb(235, 108, 99); @@ -68,7 +68,7 @@ impl Default for Calcifer { command: String::new(), command_history: Vec::new(), - theme: tools::themes::CustomColorTheme::fire(), + theme: DEFAULT_THEMES[0], search: tools::search::SearchWindow::default(), searching: false, diff --git a/src/tools/mod.rs b/src/tools/mod.rs index 5ca8958..82441d4 100644 --- a/src/tools/mod.rs +++ b/src/tools/mod.rs @@ -1,9 +1,9 @@ use std::{process::Command, cmp::Ordering, env, path::PathBuf, fs::read_to_string, fs::write}; -use egui_code_editor::Syntax; +use crate::calcifer::code_editor::Syntax; use eframe::egui; use serde::{Serialize, Deserialize}; -pub mod themes; +//pub mod themes; pub mod search; @@ -77,6 +77,7 @@ pub struct Tab { pub language : String, pub saved : bool, pub history : Vec, + pub scroll_offset : f32, } impl Default for Tab { @@ -87,6 +88,7 @@ impl Default for Tab { language: "rs".into(), saved: false, history: vec![], + scroll_offset: 0.0, } } } diff --git a/src/tools/themes.rs b/src/tools/themes.rs deleted file mode 100644 index 1659c24..0000000 --- a/src/tools/themes.rs +++ /dev/null @@ -1,77 +0,0 @@ -use egui_code_editor::ColorTheme; - -pub struct CustomColorTheme; - -impl CustomColorTheme { - pub fn fire() -> ColorTheme { - let mut theme = ColorTheme::GRUVBOX; // Or any other theme you want to modify - - theme.name = "Fire"; - theme.dark = true; - theme.bg = "#242424"; - theme.cursor = "#dadada"; // foreground - theme.selection = "#444852"; // dunno - theme.comments = "#656565"; // dark_gray - theme.functions = "#ffad69"; // light orange - theme.keywords = "#48b1a7"; // mid green - theme.literals = "#d2d2d3"; // - theme.numerics = "#ff7b4f"; // orange - theme.punctuation = "#989898"; // gray - theme.strs = "#cbd5a1"; // light_green - theme.types = "#038e83"; // dark_green - theme.special = "#48b1a7"; // mid green - - theme - } - - pub fn ash() -> ColorTheme { - let mut theme = ColorTheme::GRUVBOX; // Or any other theme you want to modify - - theme.name = "Ash"; - theme.dark = true; - theme.bg = "#101010"; - theme.cursor = "#eaeaea"; // foreground - theme.selection = "#505050"; // bg5 - theme.comments = "#656565"; // gray - theme.functions = "#a0a0a0"; // green - theme.keywords = "#848484"; // orange - theme.literals = "#d2d2d2"; // foreground - theme.numerics = "#d2d2d2"; // magenta - theme.punctuation = "#848484"; // foreground - theme.strs = "#a0a0a0"; // green - theme.types = "#c6c6c6"; - theme.special = "#848484"; - - theme - } - - pub fn from_index(n : usize) -> ColorTheme { - match n { - 0 => ColorTheme::SONOKAI, - 1 => ColorTheme::GRUVBOX, - 2 => ColorTheme::GITHUB_DARK, - 3 => ColorTheme::AYU_MIRAGE, - 4 => ColorTheme::AYU_DARK, - 5 => CustomColorTheme::ash(), - 6 => CustomColorTheme::fire(), - _ => CustomColorTheme::ash(), - } - } - - pub fn max() -> usize { - 7 - } - - pub fn to_index(theme : ColorTheme) -> usize { - match theme.name { - "Sonokai" => 0, - "Gruvbox" => 1, - "Github Dark" => 2, - "Ayu Mirage" => 3, - "Ayu Dark" => 4, - "Ash" => 5, - "Fire" => 6, - _ => 0, - } - } -}