mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-23 01:46:18 +04:00
syntax: Reuse parser instances. highlight_iter() no longer needs &mut.
This commit is contained in:
parent
9dcfe25e4a
commit
b7dd7310c4
@ -2,11 +2,12 @@
|
|||||||
pub use helix_syntax::Lang;
|
pub use helix_syntax::Lang;
|
||||||
pub use helix_syntax::{get_language, get_language_name};
|
pub use helix_syntax::{get_language, get_language_name};
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::{Lazy, OnceCell};
|
||||||
|
|
||||||
// largely based on tree-sitter/cli/src/loader.rs
|
// largely based on tree-sitter/cli/src/loader.rs
|
||||||
pub struct LanguageConfiguration {
|
pub struct LanguageConfiguration {
|
||||||
@ -65,8 +66,6 @@ pub fn scope(&self) -> &str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
|
|
||||||
pub static LOADER: Lazy<Loader> = Lazy::new(Loader::init);
|
pub static LOADER: Lazy<Loader> = Lazy::new(Loader::init);
|
||||||
|
|
||||||
pub struct Loader {
|
pub struct Loader {
|
||||||
@ -145,13 +144,20 @@ pub fn language_config_for_scope(&self, scope: &str) -> Option<Arc<LanguageConfi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
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 {
|
pub struct Syntax {
|
||||||
// grammar: Grammar,
|
|
||||||
parser: Parser,
|
|
||||||
cursors: Vec<QueryCursor>,
|
|
||||||
|
|
||||||
config: Arc<HighlightConfiguration>,
|
config: Arc<HighlightConfiguration>,
|
||||||
|
|
||||||
pub(crate) root_layer: LanguageLayer,
|
pub(crate) root_layer: LanguageLayer,
|
||||||
@ -163,10 +169,6 @@ pub fn new(
|
|||||||
/*language: Lang,*/ source: &Rope,
|
/*language: Lang,*/ source: &Rope,
|
||||||
config: Arc<HighlightConfiguration>,
|
config: Arc<HighlightConfiguration>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// fetch grammar for parser based on language string
|
|
||||||
// let grammar = get_language(&language);
|
|
||||||
let parser = Parser::new();
|
|
||||||
|
|
||||||
let root_layer = LanguageLayer { tree: None };
|
let root_layer = LanguageLayer { tree: None };
|
||||||
|
|
||||||
// track markers of injections
|
// track markers of injections
|
||||||
@ -174,25 +176,25 @@ pub fn new(
|
|||||||
|
|
||||||
let mut syntax = Self {
|
let mut syntax = Self {
|
||||||
// grammar,
|
// grammar,
|
||||||
parser,
|
|
||||||
cursors: Vec::new(),
|
|
||||||
config,
|
config,
|
||||||
root_layer,
|
root_layer,
|
||||||
};
|
};
|
||||||
|
|
||||||
// update root layer
|
// update root layer
|
||||||
syntax.root_layer.parse(
|
PARSER.with(|ts_parser| {
|
||||||
&mut syntax.parser,
|
syntax.root_layer.parse(
|
||||||
&syntax.config,
|
&mut ts_parser.borrow_mut(),
|
||||||
source,
|
&syntax.config,
|
||||||
0,
|
source,
|
||||||
vec![Range {
|
0,
|
||||||
start_byte: 0,
|
vec![Range {
|
||||||
end_byte: usize::MAX,
|
start_byte: 0,
|
||||||
start_point: Point::new(0, 0),
|
end_byte: usize::MAX,
|
||||||
end_point: Point::new(usize::MAX, usize::MAX),
|
start_point: Point::new(0, 0),
|
||||||
}],
|
end_point: Point::new(usize::MAX, usize::MAX),
|
||||||
);
|
}],
|
||||||
|
);
|
||||||
|
});
|
||||||
syntax
|
syntax
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,13 +204,15 @@ pub fn update(
|
|||||||
source: &Rope,
|
source: &Rope,
|
||||||
changeset: &ChangeSet,
|
changeset: &ChangeSet,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.root_layer.update(
|
PARSER.with(|ts_parser| {
|
||||||
&mut self.parser,
|
self.root_layer.update(
|
||||||
&self.config,
|
&mut ts_parser.borrow_mut(),
|
||||||
old_source,
|
&self.config,
|
||||||
source,
|
old_source,
|
||||||
changeset,
|
source,
|
||||||
)
|
changeset,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
// TODO: deal with injections and update them too
|
// TODO: deal with injections and update them too
|
||||||
}
|
}
|
||||||
@ -229,7 +233,8 @@ fn tree(&self) -> &Tree {
|
|||||||
|
|
||||||
/// Iterate over the highlighted regions for a given slice of source code.
|
/// Iterate over the highlighted regions for a given slice of source code.
|
||||||
pub fn highlight_iter<'a>(
|
pub fn highlight_iter<'a>(
|
||||||
&'a mut self,
|
&self,
|
||||||
|
ts_parser: &'a mut TSParser,
|
||||||
source: &'a [u8],
|
source: &'a [u8],
|
||||||
range: Option<std::ops::Range<usize>>,
|
range: Option<std::ops::Range<usize>>,
|
||||||
cancellation_flag: Option<&'a AtomicUsize>,
|
cancellation_flag: Option<&'a AtomicUsize>,
|
||||||
@ -283,7 +288,7 @@ pub fn highlight_iter<'a>(
|
|||||||
byte_offset: range.map(|r| r.start).unwrap_or(0), // TODO: simplify
|
byte_offset: range.map(|r| r.start).unwrap_or(0), // TODO: simplify
|
||||||
injection_callback,
|
injection_callback,
|
||||||
cancellation_flag,
|
cancellation_flag,
|
||||||
highlighter: self,
|
highlighter: ts_parser,
|
||||||
iter_count: 0,
|
iter_count: 0,
|
||||||
layers: vec![layer],
|
layers: vec![layer],
|
||||||
next_event: None,
|
next_event: None,
|
||||||
@ -336,19 +341,21 @@ fn tree(&self) -> &Tree {
|
|||||||
|
|
||||||
fn parse(
|
fn parse(
|
||||||
&mut self,
|
&mut self,
|
||||||
parser: &mut Parser,
|
ts_parser: &mut TSParser,
|
||||||
config: &HighlightConfiguration,
|
config: &HighlightConfiguration,
|
||||||
source: &Rope,
|
source: &Rope,
|
||||||
mut depth: usize,
|
mut depth: usize,
|
||||||
mut ranges: Vec<Range>,
|
mut ranges: Vec<Range>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if parser.set_included_ranges(&ranges).is_ok() {
|
if ts_parser.parser.set_included_ranges(&ranges).is_ok() {
|
||||||
parser
|
ts_parser
|
||||||
|
.parser
|
||||||
.set_language(config.language)
|
.set_language(config.language)
|
||||||
.map_err(|_| Error::InvalidLanguage)?;
|
.map_err(|_| Error::InvalidLanguage)?;
|
||||||
|
|
||||||
// unsafe { syntax.parser.set_cancellation_flag(cancellation_flag) };
|
// unsafe { syntax.parser.set_cancellation_flag(cancellation_flag) };
|
||||||
let tree = parser
|
let tree = ts_parser
|
||||||
|
.parser
|
||||||
.parse_with(
|
.parse_with(
|
||||||
&mut |byte, _| {
|
&mut |byte, _| {
|
||||||
if byte <= source.len_bytes() {
|
if byte <= source.len_bytes() {
|
||||||
@ -517,7 +524,7 @@ fn traverse(point: Point, text: &Tendril) -> Point {
|
|||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
parser: &mut Parser,
|
ts_parser: &mut TSParser,
|
||||||
config: &HighlightConfiguration,
|
config: &HighlightConfiguration,
|
||||||
old_source: &Rope,
|
old_source: &Rope,
|
||||||
source: &Rope,
|
source: &Rope,
|
||||||
@ -535,7 +542,7 @@ fn update(
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.parse(
|
self.parse(
|
||||||
parser,
|
ts_parser,
|
||||||
config,
|
config,
|
||||||
source,
|
source,
|
||||||
0,
|
0,
|
||||||
@ -652,7 +659,7 @@ struct HighlightIter<'a, F>
|
|||||||
{
|
{
|
||||||
source: &'a [u8],
|
source: &'a [u8],
|
||||||
byte_offset: usize,
|
byte_offset: usize,
|
||||||
highlighter: &'a mut Syntax,
|
highlighter: &'a mut TSParser,
|
||||||
injection_callback: F,
|
injection_callback: F,
|
||||||
cancellation_flag: Option<&'a AtomicUsize>,
|
cancellation_flag: Option<&'a AtomicUsize>,
|
||||||
layers: Vec<HighlightIterLayer<'a>>,
|
layers: Vec<HighlightIterLayer<'a>>,
|
||||||
@ -839,7 +846,7 @@ impl<'a> HighlightIterLayer<'a> {
|
|||||||
/// added to the returned vector.
|
/// added to the returned vector.
|
||||||
fn new<F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a>(
|
fn new<F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a>(
|
||||||
source: &'a [u8],
|
source: &'a [u8],
|
||||||
highlighter: &mut Syntax,
|
highlighter: &mut TSParser,
|
||||||
cancellation_flag: Option<&'a AtomicUsize>,
|
cancellation_flag: Option<&'a AtomicUsize>,
|
||||||
injection_callback: &mut F,
|
injection_callback: &mut F,
|
||||||
mut config: &'a HighlightConfiguration,
|
mut config: &'a HighlightConfiguration,
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
use crate::keymap::{self, Keymaps};
|
use crate::keymap::{self, Keymaps};
|
||||||
use crate::ui::text_color;
|
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 helix_view::{document::Mode, Document, Editor, Theme, View};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
@ -34,7 +38,7 @@ pub fn new() -> Self {
|
|||||||
}
|
}
|
||||||
pub fn render_view(
|
pub fn render_view(
|
||||||
&self,
|
&self,
|
||||||
view: &mut View,
|
view: &View,
|
||||||
viewport: Rect,
|
viewport: Rect,
|
||||||
surface: &mut Surface,
|
surface: &mut Surface,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
@ -61,10 +65,9 @@ pub fn render_view(
|
|||||||
self.render_statusline(&view.doc, area, surface, theme, is_focused);
|
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(
|
pub fn render_buffer(
|
||||||
&self,
|
&self,
|
||||||
view: &mut View,
|
view: &View,
|
||||||
viewport: Rect,
|
viewport: Rect,
|
||||||
surface: &mut Surface,
|
surface: &mut Surface,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
@ -79,7 +82,7 @@ pub fn render_buffer(
|
|||||||
let range = {
|
let range = {
|
||||||
// calculate viewport byte ranges
|
// calculate viewport byte ranges
|
||||||
let start = text.line_to_byte(view.first_line);
|
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
|
start..end
|
||||||
};
|
};
|
||||||
@ -87,12 +90,20 @@ pub fn render_buffer(
|
|||||||
// TODO: range doesn't actually restrict source, just highlight range
|
// TODO: range doesn't actually restrict source, just highlight range
|
||||||
// TODO: cache highlight results
|
// TODO: cache highlight results
|
||||||
// TODO: only recalculate when state.doc is actually modified
|
// 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) => {
|
Some(syntax) => {
|
||||||
syntax
|
syntax::PARSER.with(|ts_parser| {
|
||||||
.highlight_iter(source_code.as_bytes(), Some(range), None, |_| None)
|
syntax
|
||||||
.unwrap()
|
.highlight_iter(
|
||||||
.collect() // TODO: we collect here to avoid double borrow, fix later
|
&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 {
|
None => vec![Ok(HighlightEvent::Source {
|
||||||
start: range.start,
|
start: range.start,
|
||||||
@ -102,7 +113,6 @@ pub fn render_buffer(
|
|||||||
let mut spans = Vec::new();
|
let mut spans = Vec::new();
|
||||||
let mut visual_x = 0;
|
let mut visual_x = 0;
|
||||||
let mut line = 0u16;
|
let mut line = 0u16;
|
||||||
let text = view.doc.text();
|
|
||||||
|
|
||||||
'outer: for event in highlights {
|
'outer: for event in highlights {
|
||||||
match event.unwrap() {
|
match event.unwrap() {
|
||||||
|
@ -12,9 +12,6 @@
|
|||||||
use helix_core::Position;
|
use helix_core::Position;
|
||||||
use helix_view::Editor;
|
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> {
|
pub struct Menu<T> {
|
||||||
options: Vec<T>,
|
options: Vec<T>,
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user