forked from mars/breed
1
0
Fork 0

Faster syntax highlighting with a style stack

This commit is contained in:
mars 2023-04-12 18:24:06 -04:00
parent 4f6f17d066
commit b351dbbcbb
1 changed files with 19 additions and 12 deletions

View File

@ -25,7 +25,7 @@ use crossterm::{cursor, ExecutableCommand, QueueableCommand};
use parking_lot::Mutex; use parking_lot::Mutex;
use ropey::Rope; use ropey::Rope;
use syntect::easy::ScopeRangeIterator; use syntect::easy::ScopeRangeIterator;
use syntect::parsing::{ParseState, Scope, ScopeStack, SyntaxSet}; use syntect::parsing::{BasicScopeStackOp, ParseState, Scope, ScopeStack, SyntaxSet};
use crate::theme::{Style, StyleStore}; use crate::theme::{Style, StyleStore};
use crate::{Cursor, Direction}; use crate::{Cursor, Direction};
@ -150,6 +150,8 @@ impl Buffer {
let mut parser = self.parser.clone(); let mut parser = self.parser.clone();
let mut line_buf = String::new(); let mut line_buf = String::new();
let mut stack = ScopeStack::new(); let mut stack = ScopeStack::new();
let mut style_stack = Vec::<Style>::new();
let mut styled_buf = Vec::new();
for line in self.text.lines() { for line in self.text.lines() {
// display line to a pre-allocated buffer for fast parsing // display line to a pre-allocated buffer for fast parsing
line_buf.clear(); line_buf.clear();
@ -161,26 +163,31 @@ impl Buffer {
let stack_ops = parser.parse_line(&line_buf, &self.syntax_set).unwrap(); let stack_ops = parser.parse_line(&line_buf, &self.syntax_set).unwrap();
// queue the operations on the stack // queue the operations on the stack
let mut line = Vec::new();
let range_iter = ScopeRangeIterator::new(&stack_ops, &line_buf); let range_iter = ScopeRangeIterator::new(&stack_ops, &line_buf);
styled_buf.clear();
for (range, op) in range_iter { for (range, op) in range_iter {
stack.apply(&op).unwrap(); stack
.apply_with_hook(&op, |op, _scopes| match op {
BasicScopeStackOp::Push(scope) => {
let scope = scope.build_string();
let style = styles.get_scope(&scope);
style_stack.push(style);
}
BasicScopeStackOp::Pop => {
style_stack.pop();
}
})
.unwrap();
if range.start == range.end { if range.start == range.end {
continue; continue;
} }
let mut style = Style::default(); let style = style_stack.last().cloned().unwrap_or_default();
for scope in stack.scopes.clone() { styled_buf.push((style, range));
// TODO docs say that build_string "shouldn't be done frequently"
let scope = scope.build_string();
style.apply(&styles.get_scope(&scope));
}
line.push((style, range));
} }
self.styled.push(line); self.styled.push(styled_buf.clone());
} }
self.style_dirty = false; self.style_dirty = false;