Use SyntaxMap in Buffer

This commit is contained in:
Max Brunsfeld 2022-08-23 17:09:13 -07:00
parent 9113c94371
commit ced45cbb0a
6 changed files with 830 additions and 532 deletions

View file

@ -30,8 +30,12 @@ use std::{
ops::Range,
path::{Path, PathBuf},
str,
sync::Arc,
sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc,
},
};
use syntax_map::SyntaxSnapshot;
use theme::{SyntaxTheme, Theme};
use tree_sitter::{self, Query};
use util::ResultExt;
@ -50,6 +54,7 @@ thread_local! {
}
lazy_static! {
pub static ref NEXT_GRAMMAR_ID: AtomicUsize = Default::default();
pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
LanguageConfig {
name: "Plain Text".into(),
@ -286,15 +291,29 @@ pub struct Language {
}
pub struct Grammar {
id: usize,
pub(crate) ts_language: tree_sitter::Language,
pub(crate) highlights_query: Option<Query>,
pub(crate) brackets_query: Option<Query>,
pub(crate) indents_query: Option<Query>,
pub(crate) outline_query: Option<Query>,
pub(crate) brackets_config: Option<BracketConfig>,
pub(crate) indents_config: Option<IndentConfig>,
pub(crate) outline_config: Option<OutlineConfig>,
pub(crate) injection_config: Option<InjectionConfig>,
pub(crate) highlight_map: Mutex<HighlightMap>,
}
struct IndentConfig {
query: Query,
indent_capture_ix: u32,
end_capture_ix: Option<u32>,
}
struct OutlineConfig {
query: Query,
item_capture_ix: u32,
name_capture_ix: u32,
context_capture_ix: Option<u32>,
}
struct InjectionConfig {
query: Query,
content_capture_ix: u32,
@ -302,6 +321,12 @@ struct InjectionConfig {
languages_by_pattern_ix: Vec<Option<Box<str>>>,
}
struct BracketConfig {
query: Query,
open_capture_ix: u32,
close_capture_ix: u32,
}
#[derive(Clone)]
pub enum LanguageServerBinaryStatus {
CheckingForUpdate,
@ -499,6 +524,13 @@ impl LanguageRegistry {
}
}
#[cfg(any(test, feature = "test-support"))]
impl Default for LanguageRegistry {
fn default() -> Self {
Self::test()
}
}
async fn get_server_binary_path(
adapter: Arc<CachedLspAdapter>,
language: Arc<Language>,
@ -576,10 +608,11 @@ impl Language {
config,
grammar: ts_language.map(|ts_language| {
Arc::new(Grammar {
id: NEXT_GRAMMAR_ID.fetch_add(1, SeqCst),
highlights_query: None,
brackets_query: None,
indents_query: None,
outline_query: None,
brackets_config: None,
outline_config: None,
indents_config: None,
injection_config: None,
ts_language,
highlight_map: Default::default(),
@ -604,19 +637,70 @@ impl Language {
pub fn with_brackets_query(mut self, source: &str) -> Result<Self> {
let grammar = self.grammar_mut();
grammar.brackets_query = Some(Query::new(grammar.ts_language, source)?);
let query = Query::new(grammar.ts_language, source)?;
let mut open_capture_ix = None;
let mut close_capture_ix = None;
get_capture_indices(
&query,
&mut [
("open", &mut open_capture_ix),
("close", &mut close_capture_ix),
],
);
if let Some((open_capture_ix, close_capture_ix)) = open_capture_ix.zip(close_capture_ix) {
grammar.brackets_config = Some(BracketConfig {
query,
open_capture_ix,
close_capture_ix,
});
}
Ok(self)
}
pub fn with_indents_query(mut self, source: &str) -> Result<Self> {
let grammar = self.grammar_mut();
grammar.indents_query = Some(Query::new(grammar.ts_language, source)?);
let query = Query::new(grammar.ts_language, source)?;
let mut indent_capture_ix = None;
let mut end_capture_ix = None;
get_capture_indices(
&query,
&mut [
("indent", &mut indent_capture_ix),
("end", &mut end_capture_ix),
],
);
if let Some(indent_capture_ix) = indent_capture_ix {
grammar.indents_config = Some(IndentConfig {
query,
indent_capture_ix,
end_capture_ix,
});
}
Ok(self)
}
pub fn with_outline_query(mut self, source: &str) -> Result<Self> {
let grammar = self.grammar_mut();
grammar.outline_query = Some(Query::new(grammar.ts_language, source)?);
let query = Query::new(grammar.ts_language, source)?;
let mut item_capture_ix = None;
let mut name_capture_ix = None;
let mut context_capture_ix = None;
get_capture_indices(
&query,
&mut [
("item", &mut item_capture_ix),
("name", &mut name_capture_ix),
("context", &mut context_capture_ix),
],
);
if let Some((item_capture_ix, name_capture_ix)) = item_capture_ix.zip(name_capture_ix) {
grammar.outline_config = Some(OutlineConfig {
query,
item_capture_ix,
name_capture_ix,
context_capture_ix,
});
}
Ok(self)
}
@ -625,13 +709,13 @@ impl Language {
let query = Query::new(grammar.ts_language, source)?;
let mut language_capture_ix = None;
let mut content_capture_ix = None;
for (ix, name) in query.capture_names().iter().enumerate() {
*match name.as_str() {
"language" => &mut language_capture_ix,
"content" => &mut content_capture_ix,
_ => continue,
} = Some(ix as u32);
}
get_capture_indices(
&query,
&mut [
("language", &mut language_capture_ix),
("content", &mut content_capture_ix),
],
);
let languages_by_pattern_ix = (0..query.pattern_count())
.map(|ix| {
query.property_settings(ix).iter().find_map(|setting| {
@ -729,9 +813,16 @@ impl Language {
let mut result = Vec::new();
if let Some(grammar) = &self.grammar {
let tree = grammar.parse_text(text, None);
let captures = SyntaxSnapshot::single_tree_captures(
range.clone(),
text,
&tree,
grammar,
|grammar| grammar.highlights_query.as_ref(),
);
let highlight_maps = vec![grammar.highlight_map()];
let mut offset = 0;
for chunk in BufferChunks::new(text, range, Some(&tree), self.grammar.as_ref(), vec![])
{
for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) {
let end_offset = offset + chunk.text.len();
if let Some(highlight_id) = chunk.syntax_highlight_id {
if !highlight_id.is_default() {
@ -771,6 +862,10 @@ impl Language {
}
impl Grammar {
pub fn id(&self) -> usize {
self.id
}
fn parse_text(&self, text: &Rope, old_tree: Option<Tree>) -> Tree {
PARSER.with(|parser| {
let mut parser = parser.borrow_mut();
@ -870,6 +965,17 @@ impl LspAdapter for Arc<FakeLspAdapter> {
}
}
fn get_capture_indices(query: &Query, captures: &mut [(&str, &mut Option<u32>)]) {
for (ix, name) in query.capture_names().iter().enumerate() {
for (capture_name, index) in captures.iter_mut() {
if capture_name == name {
**index = Some(ix as u32);
break;
}
}
}
}
pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
lsp::Position::new(point.row, point.column)
}