summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-core/src/syntax.rs93
-rw-r--r--helix-term/src/ui/editor.rs32
-rw-r--r--helix-term/src/ui/menu.rs3
3 files changed, 71 insertions, 57 deletions
diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs
index 6e26d2f6..376d143d 100644
--- a/helix-core/src/syntax.rs
+++ b/helix-core/src/syntax.rs
@@ -2,11 +2,12 @@ use crate::{Change, Rope, RopeSlice, Transaction};
pub use helix_syntax::Lang;
pub use helix_syntax::{get_language, get_language_name};
+use std::cell::RefCell;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;
-use once_cell::sync::OnceCell;
+use once_cell::sync::{Lazy, OnceCell};
// largely based on tree-sitter/cli/src/loader.rs
pub struct LanguageConfiguration {
@@ -65,8 +66,6 @@ impl LanguageConfiguration {
}
}
-use once_cell::sync::Lazy;
-
pub static LOADER: Lazy<Loader> = Lazy::new(Loader::init);
pub struct Loader {
@@ -145,13 +144,20 @@ impl Loader {
}
}
-//
-
-pub struct Syntax {
- // grammar: Grammar,
- parser: Parser,
+pub struct TSParser {
+ parser: tree_sitter::Parser,
cursors: Vec<QueryCursor>,
+}
+// could also just use a pool, or a single instance?
+thread_local! {
+ pub static PARSER: RefCell<TSParser> = RefCell::new(TSParser {
+ parser: Parser::new(),
+ cursors: Vec::new(),
+ })
+}
+
+pub struct Syntax {
config: Arc<HighlightConfiguration>,
pub(crate) root_layer: LanguageLayer,
@@ -163,10 +169,6 @@ impl Syntax {
/*language: Lang,*/ source: &Rope,
config: Arc<HighlightConfiguration>,
) -> Self {
- // fetch grammar for parser based on language string
- // let grammar = get_language(&language);
- let parser = Parser::new();
-
let root_layer = LanguageLayer { tree: None };
// track markers of injections
@@ -174,25 +176,25 @@ impl Syntax {
let mut syntax = Self {
// grammar,
- parser,
- cursors: Vec::new(),
config,
root_layer,
};
// update root layer
- syntax.root_layer.parse(
- &mut syntax.parser,
- &syntax.config,
- source,
- 0,
- vec![Range {
- start_byte: 0,
- end_byte: usize::MAX,
- start_point: Point::new(0, 0),
- end_point: Point::new(usize::MAX, usize::MAX),
- }],
- );
+ PARSER.with(|ts_parser| {
+ syntax.root_layer.parse(
+ &mut ts_parser.borrow_mut(),
+ &syntax.config,
+ source,
+ 0,
+ vec![Range {
+ start_byte: 0,
+ end_byte: usize::MAX,
+ start_point: Point::new(0, 0),
+ end_point: Point::new(usize::MAX, usize::MAX),
+ }],
+ );
+ });
syntax
}
@@ -202,13 +204,15 @@ impl Syntax {
source: &Rope,
changeset: &ChangeSet,
) -> Result<(), Error> {
- self.root_layer.update(
- &mut self.parser,
- &self.config,
- old_source,
- source,
- changeset,
- )
+ PARSER.with(|ts_parser| {
+ self.root_layer.update(
+ &mut ts_parser.borrow_mut(),
+ &self.config,
+ old_source,
+ source,
+ changeset,
+ )
+ })
// TODO: deal with injections and update them too
}
@@ -229,7 +233,8 @@ impl Syntax {
/// Iterate over the highlighted regions for a given slice of source code.
pub fn highlight_iter<'a>(
- &'a mut self,
+ &self,
+ ts_parser: &'a mut TSParser,
source: &'a [u8],
range: Option<std::ops::Range<usize>>,
cancellation_flag: Option<&'a AtomicUsize>,
@@ -283,7 +288,7 @@ impl Syntax {
byte_offset: range.map(|r| r.start).unwrap_or(0), // TODO: simplify
injection_callback,
cancellation_flag,
- highlighter: self,
+ highlighter: ts_parser,
iter_count: 0,
layers: vec![layer],
next_event: None,
@@ -336,19 +341,21 @@ impl LanguageLayer {
fn parse(
&mut self,
- parser: &mut Parser,
+ ts_parser: &mut TSParser,
config: &HighlightConfiguration,
source: &Rope,
mut depth: usize,
mut ranges: Vec<Range>,
) -> Result<(), Error> {
- if parser.set_included_ranges(&ranges).is_ok() {
- parser
+ if ts_parser.parser.set_included_ranges(&ranges).is_ok() {
+ ts_parser
+ .parser
.set_language(config.language)
.map_err(|_| Error::InvalidLanguage)?;
// unsafe { syntax.parser.set_cancellation_flag(cancellation_flag) };
- let tree = parser
+ let tree = ts_parser
+ .parser
.parse_with(
&mut |byte, _| {
if byte <= source.len_bytes() {
@@ -517,7 +524,7 @@ impl LanguageLayer {
fn update(
&mut self,
- parser: &mut Parser,
+ ts_parser: &mut TSParser,
config: &HighlightConfiguration,
old_source: &Rope,
source: &Rope,
@@ -535,7 +542,7 @@ impl LanguageLayer {
}
self.parse(
- parser,
+ ts_parser,
config,
source,
0,
@@ -652,7 +659,7 @@ where
{
source: &'a [u8],
byte_offset: usize,
- highlighter: &'a mut Syntax,
+ highlighter: &'a mut TSParser,
injection_callback: F,
cancellation_flag: Option<&'a AtomicUsize>,
layers: Vec<HighlightIterLayer<'a>>,
@@ -839,7 +846,7 @@ impl<'a> HighlightIterLayer<'a> {
/// added to the returned vector.
fn new<F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a>(
source: &'a [u8],
- highlighter: &mut Syntax,
+ highlighter: &mut TSParser,
cancellation_flag: Option<&'a AtomicUsize>,
injection_callback: &mut F,
mut config: &'a HighlightConfiguration,
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index ae48950f..a9aa6fec 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -3,7 +3,11 @@ use crate::compositor::{Component, Compositor, Context, EventResult};
use crate::keymap::{self, Keymaps};
use crate::ui::text_color;
-use helix_core::{indent::TAB_WIDTH, syntax::HighlightEvent, Position, Range, State};
+use helix_core::{
+ indent::TAB_WIDTH,
+ syntax::{self, HighlightEvent},
+ Position, Range, State,
+};
use helix_view::{document::Mode, Document, Editor, Theme, View};
use std::borrow::Cow;
@@ -34,7 +38,7 @@ impl EditorView {
}
pub fn render_view(
&self,
- view: &mut View,
+ view: &View,
viewport: Rect,
surface: &mut Surface,
theme: &Theme,
@@ -61,10 +65,9 @@ impl EditorView {
self.render_statusline(&view.doc, area, surface, theme, is_focused);
}
- // TODO: ideally not &mut View but highlights require it because of cursor cache
pub fn render_buffer(
&self,
- view: &mut View,
+ view: &View,
viewport: Rect,
surface: &mut Surface,
theme: &Theme,
@@ -79,7 +82,7 @@ impl EditorView {
let range = {
// calculate viewport byte ranges
let start = text.line_to_byte(view.first_line);
- let end = text.line_to_byte(last_line + 1); // TODO: double check
+ let end = text.line_to_byte(last_line + 1);
start..end
};
@@ -87,12 +90,20 @@ impl EditorView {
// TODO: range doesn't actually restrict source, just highlight range
// TODO: cache highlight results
// TODO: only recalculate when state.doc is actually modified
- let highlights: Vec<_> = match view.doc.syntax.as_mut() {
+ let highlights: Vec<_> = match &view.doc.syntax {
Some(syntax) => {
- syntax
- .highlight_iter(source_code.as_bytes(), Some(range), None, |_| None)
- .unwrap()
- .collect() // TODO: we collect here to avoid double borrow, fix later
+ syntax::PARSER.with(|ts_parser| {
+ syntax
+ .highlight_iter(
+ &mut ts_parser.borrow_mut(),
+ source_code.as_bytes(),
+ Some(range),
+ None,
+ |_| None,
+ )
+ .unwrap()
+ .collect() // TODO: we collect here to avoid holding the lock, fix later
+ })
}
None => vec![Ok(HighlightEvent::Source {
start: range.start,
@@ -102,7 +113,6 @@ impl EditorView {
let mut spans = Vec::new();
let mut visual_x = 0;
let mut line = 0u16;
- let text = view.doc.text();
'outer: for event in highlights {
match event.unwrap() {
diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs
index 7cfeb811..0fdf085f 100644
--- a/helix-term/src/ui/menu.rs
+++ b/helix-term/src/ui/menu.rs
@@ -12,9 +12,6 @@ use std::borrow::Cow;
use helix_core::Position;
use helix_view::Editor;
-// TODO: factor out a popup component that we can reuse for displaying docs on autocomplete,
-// diagnostics popups, etc.
-
pub struct Menu<T> {
options: Vec<T>,