on master help sign in
syntax: Reuse parser instances. highlight_iter() no longer needs &mut.
b7dd731Blaž Hrastnik
helix-core/src/syntax.rs+50−43
@@ -2,11 +2,12 @@ use crate::{Change, Rope, RopeSlice, Transaction};
2pub use helix_syntax::Lang;
2pub use helix_syntax::Lang;
3pub use helix_syntax::{get_language, get_language_name};
3pub use helix_syntax::{get_language, get_language_name};
4
4
5+use std::cell::RefCell;
5use std::collections::HashMap;
6use std::collections::HashMap;
6use std::path::{Path, PathBuf};
7use std::path::{Path, PathBuf};
7use std::sync::Arc;
8use std::sync::Arc;
8
9
9−use once_cell::sync::OnceCell;
10+use once_cell::sync::{Lazy, OnceCell};
10
11
11// largely based on tree-sitter/cli/src/loader.rs
12// largely based on tree-sitter/cli/src/loader.rs
12pub struct LanguageConfiguration {
13pub struct LanguageConfiguration {
@@ -65,8 +66,6 @@ impl LanguageConfiguration {
65 }
66 }
66}
67}
67
68
68−use once_cell::sync::Lazy;
69−
70pub static LOADER: Lazy<Loader> = Lazy::new(Loader::init);
69pub static LOADER: Lazy<Loader> = Lazy::new(Loader::init);
71
70
72pub struct Loader {
71pub struct Loader {
@@ -145,13 +144,20 @@ impl Loader {
145 }
144 }
146}
145}
147
146
148−//
149−
150−pub struct Syntax {
147+pub struct TSParser {
151− // grammar: Grammar,
152− parser: Parser,
148+ parser: tree_sitter::Parser,
153 cursors: Vec<QueryCursor>,
149 cursors: Vec<QueryCursor>,
150+}
154
151
152+// could also just use a pool, or a single instance?
153+thread_local! {
154+ pub static PARSER: RefCell<TSParser> = RefCell::new(TSParser {
155+ parser: Parser::new(),
156+ cursors: Vec::new(),
157+ })
158+}
159+
160+pub struct Syntax {
155 config: Arc<HighlightConfiguration>,
161 config: Arc<HighlightConfiguration>,
156
162
157 pub(crate) root_layer: LanguageLayer,
163 pub(crate) root_layer: LanguageLayer,
@@ -163,10 +169,6 @@ impl Syntax {
163 /*language: Lang,*/ source: &Rope,
169 /*language: Lang,*/ source: &Rope,
164 config: Arc<HighlightConfiguration>,
170 config: Arc<HighlightConfiguration>,
165 ) -> Self {
171 ) -> Self {
166− // fetch grammar for parser based on language string
167− // let grammar = get_language(&language);
168− let parser = Parser::new();
169−
170 let root_layer = LanguageLayer { tree: None };
172 let root_layer = LanguageLayer { tree: None };
171
173
172 // track markers of injections
174 // track markers of injections
@@ -174,25 +176,25 @@ impl Syntax {
174
176
175 let mut syntax = Self {
177 let mut syntax = Self {
176 // grammar,
178 // grammar,
177− parser,
178− cursors: Vec::new(),
179 config,
179 config,
180 root_layer,
180 root_layer,
181 };
181 };
182
182
183 // update root layer
183 // update root layer
184+ PARSER.with(|ts_parser| {
184− syntax.root_layer.parse(
185+ syntax.root_layer.parse(
185− &mut syntax.parser,
186+ &mut ts_parser.borrow_mut(),
186− &syntax.config,
187+ &syntax.config,
187− source,
188+ source,
188− 0,
189+ 0,
189− vec![Range {
190+ vec![Range {
190− start_byte: 0,
191+ start_byte: 0,
191− end_byte: usize::MAX,
192+ end_byte: usize::MAX,
192− start_point: Point::new(0, 0),
193+ start_point: Point::new(0, 0),
193− end_point: Point::new(usize::MAX, usize::MAX),
194+ end_point: Point::new(usize::MAX, usize::MAX),
194− }],
195+ }],
196+ );
195− );
197+ });
196 syntax
198 syntax
197 }
199 }
198
200
@@ -202,13 +204,15 @@ impl Syntax {
202 source: &Rope,
204 source: &Rope,
203 changeset: &ChangeSet,
205 changeset: &ChangeSet,
204 ) -> Result<(), Error> {
206 ) -> Result<(), Error> {
207+ PARSER.with(|ts_parser| {
205− self.root_layer.update(
208+ self.root_layer.update(
206− &mut self.parser,
209+ &mut ts_parser.borrow_mut(),
207− &self.config,
210+ &self.config,
208− old_source,
211+ old_source,
209− source,
212+ source,
210− changeset,
213+ changeset,
214+ )
211− )
215+ })
212
216
213 // TODO: deal with injections and update them too
217 // TODO: deal with injections and update them too
214 }
218 }
@@ -229,7 +233,8 @@ impl Syntax {
229
233
230 /// Iterate over the highlighted regions for a given slice of source code.
234 /// Iterate over the highlighted regions for a given slice of source code.
231 pub fn highlight_iter<'a>(
235 pub fn highlight_iter<'a>(
232− &'a mut self,
236+ &self,
237+ ts_parser: &'a mut TSParser,
233 source: &'a [u8],
238 source: &'a [u8],
234 range: Option<std::ops::Range<usize>>,
239 range: Option<std::ops::Range<usize>>,
235 cancellation_flag: Option<&'a AtomicUsize>,
240 cancellation_flag: Option<&'a AtomicUsize>,
@@ -283,7 +288,7 @@ impl Syntax {
283 byte_offset: range.map(|r| r.start).unwrap_or(0), // TODO: simplify
288 byte_offset: range.map(|r| r.start).unwrap_or(0), // TODO: simplify
284 injection_callback,
289 injection_callback,
285 cancellation_flag,
290 cancellation_flag,
286− highlighter: self,
291+ highlighter: ts_parser,
287 iter_count: 0,
292 iter_count: 0,
288 layers: vec![layer],
293 layers: vec![layer],
289 next_event: None,
294 next_event: None,
@@ -336,19 +341,21 @@ impl LanguageLayer {
336
341
337 fn parse(
342 fn parse(
338 &mut self,
343 &mut self,
339− parser: &mut Parser,
344+ ts_parser: &mut TSParser,
340 config: &HighlightConfiguration,
345 config: &HighlightConfiguration,
341 source: &Rope,
346 source: &Rope,
342 mut depth: usize,
347 mut depth: usize,
343 mut ranges: Vec<Range>,
348 mut ranges: Vec<Range>,
344 ) -> Result<(), Error> {
349 ) -> Result<(), Error> {
345− if parser.set_included_ranges(&ranges).is_ok() {
350+ if ts_parser.parser.set_included_ranges(&ranges).is_ok() {
351+ ts_parser
346− parser
352+ .parser
347 .set_language(config.language)
353 .set_language(config.language)
348 .map_err(|_| Error::InvalidLanguage)?;
354 .map_err(|_| Error::InvalidLanguage)?;
349
355
350 // unsafe { syntax.parser.set_cancellation_flag(cancellation_flag) };
356 // unsafe { syntax.parser.set_cancellation_flag(cancellation_flag) };
357+ let tree = ts_parser
351− let tree = parser
358+ .parser
352 .parse_with(
359 .parse_with(
353 &mut |byte, _| {
360 &mut |byte, _| {
354 if byte <= source.len_bytes() {
361 if byte <= source.len_bytes() {
@@ -517,7 +524,7 @@ impl LanguageLayer {
517
524
518 fn update(
525 fn update(
519 &mut self,
526 &mut self,
520− parser: &mut Parser,
527+ ts_parser: &mut TSParser,
521 config: &HighlightConfiguration,
528 config: &HighlightConfiguration,
522 old_source: &Rope,
529 old_source: &Rope,
523 source: &Rope,
530 source: &Rope,
@@ -535,7 +542,7 @@ impl LanguageLayer {
535 }
542 }
536
543
537 self.parse(
544 self.parse(
538− parser,
545+ ts_parser,
539 config,
546 config,
540 source,
547 source,
541 0,
548 0,
@@ -652,7 +659,7 @@ where
652{
659{
653 source: &'a [u8],
660 source: &'a [u8],
654 byte_offset: usize,
661 byte_offset: usize,
655− highlighter: &'a mut Syntax,
662+ highlighter: &'a mut TSParser,
656 injection_callback: F,
663 injection_callback: F,
657 cancellation_flag: Option<&'a AtomicUsize>,
664 cancellation_flag: Option<&'a AtomicUsize>,
658 layers: Vec<HighlightIterLayer<'a>>,
665 layers: Vec<HighlightIterLayer<'a>>,
@@ -839,7 +846,7 @@ impl<'a> HighlightIterLayer<'a> {
839 /// added to the returned vector.
846 /// added to the returned vector.
840 fn new<F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a>(
847 fn new<F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a>(
841 source: &'a [u8],
848 source: &'a [u8],
842− highlighter: &mut Syntax,
849+ highlighter: &mut TSParser,
843 cancellation_flag: Option<&'a AtomicUsize>,
850 cancellation_flag: Option<&'a AtomicUsize>,
844 injection_callback: &mut F,
851 injection_callback: &mut F,
845 mut config: &'a HighlightConfiguration,
852 mut config: &'a HighlightConfiguration,
helix-term/src/ui/editor.rs+21−11
@@ -3,7 +3,11 @@ use crate::compositor::{Component, Compositor, Context, EventResult};
3use crate::keymap::{self, Keymaps};
3use crate::keymap::{self, Keymaps};
4use crate::ui::text_color;
4use crate::ui::text_color;
5
5
6+use helix_core::{
7+ indent::TAB_WIDTH,
6−use helix_core::{indent::TAB_WIDTH, syntax::HighlightEvent, Position, Range, State};
8+ syntax::{self, HighlightEvent},
9+ Position, Range, State,
10+};
7use helix_view::{document::Mode, Document, Editor, Theme, View};
11use helix_view::{document::Mode, Document, Editor, Theme, View};
8use std::borrow::Cow;
12use std::borrow::Cow;
9
13
@@ -34,7 +38,7 @@ impl EditorView {
34 }
38 }
35 pub fn render_view(
39 pub fn render_view(
36 &self,
40 &self,
37− view: &mut View,
41+ view: &View,
38 viewport: Rect,
42 viewport: Rect,
39 surface: &mut Surface,
43 surface: &mut Surface,
40 theme: &Theme,
44 theme: &Theme,
@@ -61,10 +65,9 @@ impl EditorView {
61 self.render_statusline(&view.doc, area, surface, theme, is_focused);
65 self.render_statusline(&view.doc, area, surface, theme, is_focused);
62 }
66 }
63
67
64− // TODO: ideally not &mut View but highlights require it because of cursor cache
65 pub fn render_buffer(
68 pub fn render_buffer(
66 &self,
69 &self,
67− view: &mut View,
70+ view: &View,
68 viewport: Rect,
71 viewport: Rect,
69 surface: &mut Surface,
72 surface: &mut Surface,
70 theme: &Theme,
73 theme: &Theme,
@@ -79,7 +82,7 @@ impl EditorView {
79 let range = {
82 let range = {
80 // calculate viewport byte ranges
83 // calculate viewport byte ranges
81 let start = text.line_to_byte(view.first_line);
84 let start = text.line_to_byte(view.first_line);
82− let end = text.line_to_byte(last_line + 1); // TODO: double check
85+ let end = text.line_to_byte(last_line + 1);
83
86
84 start..end
87 start..end
85 };
88 };
@@ -87,12 +90,20 @@ impl EditorView {
87 // TODO: range doesn't actually restrict source, just highlight range
90 // TODO: range doesn't actually restrict source, just highlight range
88 // TODO: cache highlight results
91 // TODO: cache highlight results
89 // TODO: only recalculate when state.doc is actually modified
92 // TODO: only recalculate when state.doc is actually modified
90− let highlights: Vec<_> = match view.doc.syntax.as_mut() {
93+ let highlights: Vec<_> = match &view.doc.syntax {
91 Some(syntax) => {
94 Some(syntax) => {
92− syntax
95+ syntax::PARSER.with(|ts_parser| {
96+ syntax
97+ .highlight_iter(
98+ &mut ts_parser.borrow_mut(),
93− .highlight_iter(source_code.as_bytes(), Some(range), None, |_| None)
99+ source_code.as_bytes(),
100+ Some(range),
101+ None,
102+ |_| None,
103+ )
94− .unwrap()
104+ .unwrap()
95− .collect() // TODO: we collect here to avoid double borrow, fix later
105+ .collect() // TODO: we collect here to avoid holding the lock, fix later
106+ })
96 }
107 }
97 None => vec![Ok(HighlightEvent::Source {
108 None => vec![Ok(HighlightEvent::Source {
98 start: range.start,
109 start: range.start,
@@ -102,7 +113,6 @@ impl EditorView {
102 let mut spans = Vec::new();
113 let mut spans = Vec::new();
103 let mut visual_x = 0;
114 let mut visual_x = 0;
104 let mut line = 0u16;
115 let mut line = 0u16;
105− let text = view.doc.text();
106
116
107 'outer: for event in highlights {
117 'outer: for event in highlights {
108 match event.unwrap() {
118 match event.unwrap() {
helix-term/src/ui/menu.rs−3
@@ -12,9 +12,6 @@ use std::borrow::Cow;
12use helix_core::Position;
12use helix_core::Position;
13use helix_view::Editor;
13use helix_view::Editor;
14
14
15−// TODO: factor out a popup component that we can reuse for displaying docs on autocomplete,
16−// diagnostics popups, etc.
17−
18pub struct Menu<T> {
15pub struct Menu<T> {
19 options: Vec<T>,
16 options: Vec<T>,
20
17