js highlighting

This commit is contained in:
WanderingPenwing 2024-02-28 18:04:44 +01:00
parent b84cde8e2b
commit f95d44ec69
4 changed files with 217 additions and 189 deletions

View file

@ -399,6 +399,7 @@ fn to_syntax(language: &str) -> Syntax {
match language { match language {
"py" => Syntax::python(), "py" => Syntax::python(),
"rs" => Syntax::rust(), "rs" => Syntax::rust(),
"js" => Syntax::javascript(),
_ => Syntax::shell(), _ => Syntax::shell(),
} }
} }

View file

@ -0,0 +1,24 @@
use super::Syntax;
use std::collections::BTreeSet;
impl Syntax {
pub fn javascript() -> Syntax {
Syntax {
language: "Javascript",
case_sensitive: true,
comment: "//",
comment_multiline: ["/*", "*/"],
keywords: BTreeSet::from([
"&&", "||", "!", "let", "var", "abstract", "arguments", "await", "break", "case", "catch", "class", "const", "continue",
"debugger", "default", "delete", "do", "else", "enum", "eval", "export", "extends", "final", "finally", "for", "function",
"goto", "if", "implements", "import", "in", "instanceof", "interface", "let", "native", "new", "package", "private", "protected",
"public", "return", "static", "super", "switch", "synchronized", "this","throw", "throws", "transient", "try", "typeof",
"var", "volatile", "while", "with", "yield",
]),
types: BTreeSet::from([
"Boolean", "Number", "BigInt", "Undefined", "Null", "String", "Symbol", "byte", "char", "float", "int", "long", "short", "void",
]),
special: BTreeSet::from(["false", "null", "true"]),
}
}
}

View file

@ -1,5 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
pub mod asm; pub mod asm;
pub mod javascript;
pub mod lua; pub mod lua;
pub mod python; pub mod python;
pub mod rust; pub mod rust;
@ -18,179 +19,179 @@ type Float = bool;
#[derive(Default, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] #[derive(Default, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum TokenType { pub enum TokenType {
Comment(MultiLine), Comment(MultiLine),
Function, Function,
Keyword, Keyword,
Literal, Literal,
Numeric(Float), Numeric(Float),
Punctuation(char), Punctuation(char),
Special, Special,
Str(char), Str(char),
Type, Type,
Whitespace(char), Whitespace(char),
#[default] #[default]
Unknown, Unknown,
} }
impl std::fmt::Debug for TokenType { impl std::fmt::Debug for TokenType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut name = String::new(); let mut name = String::new();
match &self { match &self {
TokenType::Comment(multiline) => { TokenType::Comment(multiline) => {
name.push_str("Comment"); name.push_str("Comment");
{ {
if *multiline { if *multiline {
name.push_str(" MultiLine"); name.push_str(" MultiLine");
} else { } else {
name.push_str(" SingleLine"); name.push_str(" SingleLine");
} }
} }
} }
TokenType::Function => name.push_str("Function"), TokenType::Function => name.push_str("Function"),
TokenType::Keyword => name.push_str("Keyword"), TokenType::Keyword => name.push_str("Keyword"),
TokenType::Literal => name.push_str("Literal"), TokenType::Literal => name.push_str("Literal"),
TokenType::Numeric(float) => { TokenType::Numeric(float) => {
name.push_str("Numeric"); name.push_str("Numeric");
if *float { if *float {
name.push_str(" Float"); name.push_str(" Float");
} else { } else {
name.push_str(" Integer"); name.push_str(" Integer");
} }
} }
TokenType::Punctuation(_) => name.push_str("Punctuation"), TokenType::Punctuation(_) => name.push_str("Punctuation"),
TokenType::Special => name.push_str("Special"), TokenType::Special => name.push_str("Special"),
TokenType::Str(quote) => { TokenType::Str(quote) => {
name.push_str("Str "); name.push_str("Str ");
name.push(*quote); name.push(*quote);
} }
TokenType::Type => name.push_str("Type"), TokenType::Type => name.push_str("Type"),
TokenType::Whitespace(c) => { TokenType::Whitespace(c) => {
name.push_str("Whitespace"); name.push_str("Whitespace");
match c { match c {
' ' => name.push_str(" Space"), ' ' => name.push_str(" Space"),
'\t' => name.push_str(" Tab"), '\t' => name.push_str(" Tab"),
'\n' => name.push_str(" New Line"), '\n' => name.push_str(" New Line"),
_ => (), _ => (),
}; };
} }
TokenType::Unknown => name.push_str("Unknown"), TokenType::Unknown => name.push_str("Unknown"),
}; };
write!(f, "{name}") write!(f, "{name}")
} }
} }
impl From<char> for TokenType { impl From<char> for TokenType {
fn from(c: char) -> Self { fn from(c: char) -> Self {
match c { match c {
c if c.is_whitespace() => TokenType::Whitespace(c), c if c.is_whitespace() => TokenType::Whitespace(c),
c if QUOTES.contains(&c) => TokenType::Str(c), c if QUOTES.contains(&c) => TokenType::Str(c),
c if c.is_numeric() => TokenType::Numeric(false), c if c.is_numeric() => TokenType::Numeric(false),
c if c.is_alphabetic() || SEPARATORS.contains(&c) => TokenType::Literal, c if c.is_alphabetic() || SEPARATORS.contains(&c) => TokenType::Literal,
c if c.is_ascii_punctuation() => TokenType::Punctuation(c), c if c.is_ascii_punctuation() => TokenType::Punctuation(c),
_ => TokenType::Unknown, _ => TokenType::Unknown,
} }
} }
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
/// Rules for highlighting. /// Rules for highlighting.
pub struct Syntax { pub struct Syntax {
pub language: &'static str, pub language: &'static str,
pub case_sensitive: bool, pub case_sensitive: bool,
pub comment: &'static str, pub comment: &'static str,
pub comment_multiline: [&'static str; 2], pub comment_multiline: [&'static str; 2],
pub keywords: BTreeSet<&'static str>, pub keywords: BTreeSet<&'static str>,
pub types: BTreeSet<&'static str>, pub types: BTreeSet<&'static str>,
pub special: BTreeSet<&'static str>, pub special: BTreeSet<&'static str>,
} }
impl Default for Syntax { impl Default for Syntax {
fn default() -> Self { fn default() -> Self {
Syntax::rust() Syntax::rust()
} }
} }
impl Hash for Syntax { impl Hash for Syntax {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.language.hash(state); self.language.hash(state);
} }
} }
impl Syntax { impl Syntax {
pub fn new(language: &'static str) -> Self { pub fn new(language: &'static str) -> Self {
Syntax { Syntax {
language, language,
..Default::default() ..Default::default()
} }
} }
pub fn with_case_sensitive(self, case_sensitive: bool) -> Self { pub fn with_case_sensitive(self, case_sensitive: bool) -> Self {
Syntax { Syntax {
case_sensitive, case_sensitive,
..self ..self
} }
} }
pub fn with_comment(self, comment: &'static str) -> Self { pub fn with_comment(self, comment: &'static str) -> Self {
Syntax { comment, ..self } Syntax { comment, ..self }
} }
pub fn with_comment_multiline(self, comment_multiline: [&'static str; 2]) -> Self { pub fn with_comment_multiline(self, comment_multiline: [&'static str; 2]) -> Self {
Syntax { Syntax {
comment_multiline, comment_multiline,
..self ..self
} }
} }
pub fn with_keywords<T: Into<BTreeSet<&'static str>>>(self, keywords: T) -> Self { pub fn with_keywords<T: Into<BTreeSet<&'static str>>>(self, keywords: T) -> Self {
Syntax { Syntax {
keywords: keywords.into(), keywords: keywords.into(),
..self ..self
} }
} }
pub fn with_types<T: Into<BTreeSet<&'static str>>>(self, types: T) -> Self { pub fn with_types<T: Into<BTreeSet<&'static str>>>(self, types: T) -> Self {
Syntax { Syntax {
types: types.into(), types: types.into(),
..self ..self
} }
} }
pub fn with_special<T: Into<BTreeSet<&'static str>>>(self, special: T) -> Self { pub fn with_special<T: Into<BTreeSet<&'static str>>>(self, special: T) -> Self {
Syntax { Syntax {
special: special.into(), special: special.into(),
..self ..self
} }
} }
pub fn language(&self) -> &str { pub fn language(&self) -> &str {
self.language self.language
} }
pub fn comment(&self) -> &str { pub fn comment(&self) -> &str {
self.comment self.comment
} }
pub fn is_keyword(&self, word: &str) -> bool { pub fn is_keyword(&self, word: &str) -> bool {
if self.case_sensitive { if self.case_sensitive {
self.keywords.contains(&word) self.keywords.contains(&word)
} else { } else {
self.keywords.contains(word.to_ascii_uppercase().as_str()) self.keywords.contains(word.to_ascii_uppercase().as_str())
} }
} }
pub fn is_type(&self, word: &str) -> bool { pub fn is_type(&self, word: &str) -> bool {
if self.case_sensitive { if self.case_sensitive {
self.types.contains(&word) self.types.contains(&word)
} else { } else {
self.types.contains(word.to_ascii_uppercase().as_str()) self.types.contains(word.to_ascii_uppercase().as_str())
} }
} }
pub fn is_special(&self, word: &str) -> bool { pub fn is_special(&self, word: &str) -> bool {
if self.case_sensitive { if self.case_sensitive {
self.special.contains(&word) self.special.contains(&word)
} else { } else {
self.special.contains(word.to_ascii_uppercase().as_str()) self.special.contains(word.to_ascii_uppercase().as_str())
} }
} }
} }
impl Syntax { impl Syntax {
pub fn simple(comment: &'static str) -> Self { pub fn simple(comment: &'static str) -> Self {
Syntax { Syntax {
language: "", language: "",
case_sensitive: false, case_sensitive: false,
comment, comment,
comment_multiline: [comment; 2], comment_multiline: [comment; 2],
keywords: BTreeSet::new(), keywords: BTreeSet::new(),
types: BTreeSet::new(), types: BTreeSet::new(),
special: BTreeSet::new(), special: BTreeSet::new(),
} }
} }
} }

View file

@ -1,42 +1,44 @@
use eframe::egui; use eframe::egui;
pub struct ShortcutsWindow { pub struct ShortcutsWindow {
pub visible: bool, pub visible: bool,
} }
impl ShortcutsWindow { impl ShortcutsWindow {
pub fn new() -> Self { pub fn new() -> Self {
Self { visible: false } Self { visible: false }
} }
pub fn show(&mut self, ctx: &egui::Context) { pub fn show(&mut self, ctx: &egui::Context) {
let mut visible = self.visible; let mut visible = self.visible;
egui::Window::new("Shortcuts") egui::Window::new("Shortcuts")
.open(&mut visible) .open(&mut visible)
.vscroll(true) .vscroll(true)
.hscroll(true) .hscroll(true)
.show(ctx, |ui| self.ui(ui)); .show(ctx, |ui| self.ui(ui));
self.visible = self.visible && visible; self.visible = self.visible && visible;
} }
fn ui(&mut self, ui: &mut egui::Ui) { fn ui(&mut self, ui: &mut egui::Ui) {
ui.set_min_width(250.0); ui.set_min_width(250.0);
ui.label("Ctrl+S : save file"); ui.label("Ctrl+S : save file");
ui.label("Ctrl+Shift+S : save file as"); ui.label("Ctrl+Shift+S : save file as");
ui.label("Ctrl+R : reload file"); ui.label("Ctrl+R : reload file");
ui.separator(); ui.separator();
ui.label("Ctrl+F : open search window"); ui.label("Ctrl+F : open search window");
ui.separator(); ui.separator();
ui.label("Ctrl+Z : undo"); ui.label("Ctrl+T : reload tree");
ui.label("Ctrl+Y : redo"); ui.separator();
ui.label("Tab on selection : add indent of selection"); ui.label("Ctrl+Z : undo");
ui.label("Shift+Tab on selection : remove indent of selection"); ui.label("Ctrl+Y : redo");
ui.label("Ctrl+E : comment selection"); ui.label("Tab on selection : add indent of selection");
ui.separator(); ui.label("Shift+Tab on selection : remove indent of selection");
ui.label("Alt+Arrows : move between tabs"); ui.label("Ctrl+E : comment selection");
ui.separator(); ui.separator();
ui.label("Enter (project_mode) : edit item"); ui.label("Alt+Arrows : move between tabs");
ui.label("Arrows (project_mode) : change selected item"); ui.separator();
ui.label("Shift+Arrows (project_mode) : move selected item"); ui.label("Enter (project_mode) : edit item");
} ui.label("Arrows (project_mode) : change selected item");
ui.label("Shift+Arrows (project_mode) : move selected item");
}
} }