Improved highlighting

This commit is contained in:
Joshua Barretto 2025-09-24 11:06:11 +01:00
parent d45deb2685
commit ad27219f4c
5 changed files with 41 additions and 12 deletions

15
Cargo.lock generated
View file

@ -91,10 +91,11 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "cc"
version = "1.2.27"
version = "1.2.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9"
dependencies = [
"find-msvc-tools",
"shlex",
]
@ -217,6 +218,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "find-msvc-tools"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959"
[[package]]
name = "foldhash"
version = "0.1.5"
@ -225,9 +232,9 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "hashbrown"
version = "0.15.4"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"allocator-api2",
"equivalent",

View file

@ -32,6 +32,8 @@ pub enum TokenKind {
Special,
/// A program constant or other statically-known name
Constant,
/// A function call or some other active operation
Function,
}
#[derive(Default)]
@ -146,8 +148,9 @@ pub enum Regex {
Group(Vec<Self>),
// (at_least, at_most, _)
Many(usize, usize, Box<Self>),
// (delimiter, x) - delimit x with `delimiter` on either side (used for raw strings)
// (delimiter, x) - parse a pattern, then refer to the substring later in x with `~`
Delim(Box<Self>, Box<Self>),
Rewind(Box<Self>),
}
struct State<'a> {
@ -163,7 +166,6 @@ impl State<'_> {
fn prev(&self) -> Option<char> {
self.s[..self.pos].last().copied()
// self.s.get(self.pos.saturating_sub(1)).copied()
}
fn skip_if(&mut self, f: impl FnOnce(char) -> bool) -> Option<()> {
@ -242,6 +244,14 @@ impl State<'_> {
self.delim = old_delim;
res
}
Regex::Rewind(r) => {
let old_pos = self.pos;
let res = self.go(r);
if res.is_some() {
self.pos = old_pos;
}
res
}
}
}
}
@ -265,7 +275,7 @@ use chumsky::{
impl Regex {
fn parser<'a>() -> impl Parser<'a, &'a str, Self, extra::Err<Rich<'a, char>>> {
recursive(|regex| {
let metachars = r"{}[]()^$.|*+-?\/@~";
let metachars = r"{}[]()^$.|*+-?\/@~%";
let char_ = choice((
none_of(metachars),
// Escaped meta characters
@ -307,6 +317,7 @@ impl Regex {
postfix(1, just('*'), |r, _, _| Self::Many(0, !0, Box::new(r))),
postfix(1, just('+'), |r, _, _| Self::Many(1, !0, Box::new(r))),
postfix(1, just('?'), |r, _, _| Self::Many(0, 1, Box::new(r))),
postfix(1, just('%'), |r, _, _| Self::Rewind(Box::new(r))),
// Non-standard: `x@y` parses `x` and then `y`. `y` can use `~` to refer to the extra string that was
// parsed by `x`. This supports nesting and is intended for context-sensitive patterns like Rust raw
// strings.

View file

@ -102,8 +102,10 @@ impl Highlighter {
)
.with(
TokenKind::Operator,
r"[(&(mut)?)(\?)(\+=?)(\-=?)(\*=?)(\/=?)(%=?)(!=?)(==?)(&&?=?)(\|\|?=?)(<<?=?)(>>?=?)(\.\.[\.=]?)\\\~\^:;,\@(=>?)]",
r"[(&(mut)?)(\?)(\+=?)(\-=?)(\*=?)(\/=?)(\%=?)(!=?)(==?)(&&?=?)(\|\|?=?)(<<?=?)(>>?=?)(\.\.[\.=]?)\\\~\^:;,\@(=>?)]",
)
// Function/method call
.with(TokenKind::Function, r"(\.)?\b[a-z_][A-Za-z0-9_]*\b[\(<]%")
// Fields and methods: a.foo
.with(TokenKind::Property, r"\.[a-z_][A-Za-z0-9_]*")
// Paths: std::foo::bar
@ -145,8 +147,10 @@ impl Highlighter {
.with(TokenKind::String, r#"b?'[(\\[nrt\\0(x[0-7A-Za-z][0-7A-Za-z])])[^']]*'"#)
.with(
TokenKind::Operator,
r"[(&)(\?)(\+\+)(\-\-)(\+=?)(\-=?)(\*=?)(\/=?)(%=?)(!=?)(==?)(&&?=?)(\|\|?=?)(<<?=?)(>>?=?)(\.\.[\.=]?)\\\~\^:;,\@(=>?)]",
r"[(&)(\?)(\+\+)(\-\-)(\+=?)(\-=?)(\*=?)(\/=?)(\%=?)(!=?)(==?)(&&?=?)(\|\|?=?)(<<?=?)(>>?=?)(\.\.[\.=]?)\\\~\^:;,\@(=>?)]",
)
// Function/method call
.with(TokenKind::Function, r"(\.)?\b[a-z_][A-Za-z0-9_]*\b[\(<]%")
// Fields and methods: a.foo
.with(TokenKind::Property, r"\.[a-z_][A-Za-z0-9_]*")
// Paths: std::foo::bar
@ -159,7 +163,7 @@ impl Highlighter {
pub fn generic_clike(self) -> Self {
self
// Keywords
.with(TokenKind::Keyword, r"\b[(var)(enum)(let)(this)(fn)(struct)(class)(import)(if)(while)(for)(in)(loop)(else)(break)(continue)(const)(static)(type)(extern)(return)(async)(throw)(catch)(union)(auto)(namespace)(public)(private)(function)(func)]\b")
.with(TokenKind::Keyword, r"\b[(var)(enum)(let)(this)(fn)(struct)(class)(import)(if)(while)(for)(in)(loop)(else)(break)(continue)(const)(static)(type)(extern)(return)(async)(throw)(catch)(union)(auto)(namespace)(public)(private)(function)(func)(goto)]\b")
// Primitives
.with(TokenKind::Type, r"\b[(([(unsigned)(signed)][[:space:]])*u?int[0-9]*(_t)?)(float)(double)(bool)(char)(size_t)(void)]\b")
.clike_comments()

View file

@ -63,6 +63,7 @@ pub struct Theme {
pub hl_token_string: Color,
pub hl_token_special: Color,
pub hl_token_constant: Color,
pub hl_token_function: Color,
}
impl Default for Theme {
@ -101,6 +102,7 @@ impl Default for Theme {
hl_token_string: Color::AnsiValue(179),
hl_token_special: Color::AnsiValue(160),
hl_token_constant: Color::AnsiValue(81),
hl_token_function: Color::AnsiValue(122),
}
}
}
@ -123,6 +125,7 @@ impl Theme {
TokenKind::String => self.hl_token_string,
TokenKind::Special => self.hl_token_special,
TokenKind::Constant => self.hl_token_constant,
TokenKind::Function => self.hl_token_function,
}
}
}

View file

@ -112,11 +112,15 @@ impl Element<()> for Root {
}
Action::Cancel => {
let unsaved = state.buffers.values().filter(|b| b.unsaved).count();
if unsaved == 0 {
if state.buffers.is_empty() {
return Ok(Resp::end(None));
} else {
self.tasks.push(Task::Confirm(Confirm {
label: Label(format!("Are you sure you wish to quit? (y/n). Note that {} files are unsaved!", unsaved)),
label: Label(if unsaved == 0 {
format!("Are you sure you wish to quit? (y/n). You have multiple documents open!")
} else {
format!("Are you sure you wish to quit? (y/n). Note that {} files are unsaved!", unsaved)
}),
action: Action::Quit,
}));
}