mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 02:46:43 +00:00
WIP: Add interactions query language feature
Sketch in interaction provider API Wire interaction data through buffer chunk APIs
This commit is contained in:
parent
166585a2a8
commit
ecf8533d28
9 changed files with 313 additions and 72 deletions
|
@ -38,8 +38,8 @@ use gpui::{
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use json::json;
|
use json::json;
|
||||||
use language::{
|
use language::{
|
||||||
language_settings::ShowWhitespaceSetting, Bias, CursorShape, DiagnosticSeverity, OffsetUtf16,
|
language_settings::ShowWhitespaceSetting, Bias, CursorShape, DiagnosticSeverity, InteractionId,
|
||||||
Selection,
|
OffsetUtf16, Selection,
|
||||||
};
|
};
|
||||||
use project::{
|
use project::{
|
||||||
project_settings::{GitGutterSetting, ProjectSettings},
|
project_settings::{GitGutterSetting, ProjectSettings},
|
||||||
|
@ -1659,6 +1659,7 @@ impl EditorElement {
|
||||||
chunk: chunk.text,
|
chunk: chunk.text,
|
||||||
style: highlight_style,
|
style: highlight_style,
|
||||||
is_tab: chunk.is_tab,
|
is_tab: chunk.is_tab,
|
||||||
|
interaction: chunk.interaction_id,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1900,6 +1901,7 @@ impl EditorElement {
|
||||||
struct HighlightedChunk<'a> {
|
struct HighlightedChunk<'a> {
|
||||||
chunk: &'a str,
|
chunk: &'a str,
|
||||||
style: Option<HighlightStyle>,
|
style: Option<HighlightStyle>,
|
||||||
|
interaction: Option<InteractionId>,
|
||||||
is_tab: bool,
|
is_tab: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1930,6 +1932,7 @@ impl LineWithInvisibles {
|
||||||
for highlighted_chunk in chunks.chain([HighlightedChunk {
|
for highlighted_chunk in chunks.chain([HighlightedChunk {
|
||||||
chunk: "\n",
|
chunk: "\n",
|
||||||
style: None,
|
style: None,
|
||||||
|
interaction: None,
|
||||||
is_tab: false,
|
is_tab: false,
|
||||||
}]) {
|
}]) {
|
||||||
for (ix, mut line_chunk) in highlighted_chunk.chunk.split('\n').enumerate() {
|
for (ix, mut line_chunk) in highlighted_chunk.chunk.split('\n').enumerate() {
|
||||||
|
@ -1960,6 +1963,12 @@ impl LineWithInvisibles {
|
||||||
Cow::Borrowed(text_style)
|
Cow::Borrowed(text_style)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let interaction = if let Some(interaction) = highlighted_chunk.interaction {
|
||||||
|
Some(interaction)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
if line.len() + line_chunk.len() > max_line_len {
|
if line.len() + line_chunk.len() > max_line_len {
|
||||||
let mut chunk_len = max_line_len - line.len();
|
let mut chunk_len = max_line_len - line.len();
|
||||||
while !line_chunk.is_char_boundary(chunk_len) {
|
while !line_chunk.is_char_boundary(chunk_len) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ pub use crate::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
diagnostic_set::{DiagnosticEntry, DiagnosticGroup},
|
diagnostic_set::{DiagnosticEntry, DiagnosticGroup},
|
||||||
|
interaction_map::{InteractionId, InteractionMap},
|
||||||
language_settings::{language_settings, LanguageSettings},
|
language_settings::{language_settings, LanguageSettings},
|
||||||
outline::OutlineItem,
|
outline::OutlineItem,
|
||||||
syntax_map::{
|
syntax_map::{
|
||||||
|
@ -285,11 +286,74 @@ struct IndentSuggestion {
|
||||||
within_error: bool,
|
within_error: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BufferChunkHighlights<'a> {
|
pub(crate) trait QueryFeatureMap {
|
||||||
|
type Id: Copy + Clone + std::fmt::Debug;
|
||||||
|
|
||||||
|
fn get(&self, capture_id: u32) -> Self::Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
type BufferChunkHighlights<'a> = BufferChunkQuery<'a, HighlightMap>;
|
||||||
|
|
||||||
|
type BufferChunkInteractions<'a> = BufferChunkQuery<'a, InteractionMap>;
|
||||||
|
|
||||||
|
struct BufferChunkQuery<'a, T: QueryFeatureMap> {
|
||||||
captures: SyntaxMapCaptures<'a>,
|
captures: SyntaxMapCaptures<'a>,
|
||||||
next_capture: Option<SyntaxMapCapture<'a>>,
|
next_capture: Option<SyntaxMapCapture<'a>>,
|
||||||
stack: Vec<(usize, HighlightId)>,
|
maps: Vec<T>,
|
||||||
highlight_maps: Vec<HighlightMap>,
|
stack: Vec<(usize, T::Id)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: QueryFeatureMap> BufferChunkQuery<'a, T> {
|
||||||
|
fn seek(&mut self, offset: usize, byte_range: Range<usize>) {
|
||||||
|
self.stack.retain(|(end_offset, _)| *end_offset > offset);
|
||||||
|
if let Some(capture) = &self.next_capture {
|
||||||
|
if offset >= capture.node.start_byte() {
|
||||||
|
let next_capture_end = capture.node.end_byte();
|
||||||
|
if offset < next_capture_end {
|
||||||
|
self.stack.push((
|
||||||
|
next_capture_end,
|
||||||
|
self.maps[capture.grammar_index].get(capture.index),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
self.next_capture.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.captures.set_byte_range(byte_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_current_id(&self, chunk_end: &mut usize, id: &mut Option<T::Id>) {
|
||||||
|
if let Some((parent_capture_end, parent_id)) = self.stack.last() {
|
||||||
|
*chunk_end = (*chunk_end).min(*parent_capture_end);
|
||||||
|
*id = Some(parent_id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&mut self, range_start: usize, next_capture_start: &mut usize) {
|
||||||
|
while let Some((parent_capture_end, _)) = self.stack.last() {
|
||||||
|
if *parent_capture_end <= range_start {
|
||||||
|
self.stack.pop();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.next_capture.is_none() {
|
||||||
|
self.next_capture = self.captures.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(capture) = self.next_capture.as_ref() {
|
||||||
|
if range_start < capture.node.start_byte() {
|
||||||
|
if capture.node.start_byte() < *next_capture_start {
|
||||||
|
*next_capture_start = capture.node.start_byte();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
let highlight_id = self.maps[capture.grammar_index].get(capture.index);
|
||||||
|
self.stack.push((capture.node.end_byte(), highlight_id));
|
||||||
|
self.next_capture = self.captures.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BufferChunks<'a> {
|
pub struct BufferChunks<'a> {
|
||||||
|
@ -302,12 +366,14 @@ pub struct BufferChunks<'a> {
|
||||||
hint_depth: usize,
|
hint_depth: usize,
|
||||||
unnecessary_depth: usize,
|
unnecessary_depth: usize,
|
||||||
highlights: Option<BufferChunkHighlights<'a>>,
|
highlights: Option<BufferChunkHighlights<'a>>,
|
||||||
|
interactions: Option<BufferChunkInteractions<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct Chunk<'a> {
|
pub struct Chunk<'a> {
|
||||||
pub text: &'a str,
|
pub text: &'a str,
|
||||||
pub syntax_highlight_id: Option<HighlightId>,
|
pub syntax_highlight_id: Option<HighlightId>,
|
||||||
|
pub interaction_id: Option<InteractionId>,
|
||||||
pub highlight_style: Option<HighlightStyle>,
|
pub highlight_style: Option<HighlightStyle>,
|
||||||
pub diagnostic_severity: Option<DiagnosticSeverity>,
|
pub diagnostic_severity: Option<DiagnosticSeverity>,
|
||||||
pub is_unnecessary: bool,
|
pub is_unnecessary: bool,
|
||||||
|
@ -2089,17 +2155,27 @@ impl BufferSnapshot {
|
||||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||||
|
|
||||||
let mut syntax = None;
|
let mut syntax = None;
|
||||||
|
let mut interactions = None;
|
||||||
let mut diagnostic_endpoints = Vec::new();
|
let mut diagnostic_endpoints = Vec::new();
|
||||||
if language_aware {
|
if language_aware {
|
||||||
let captures = self.syntax.captures(range.clone(), &self.text, |grammar| {
|
let captures = self.syntax.captures(range.clone(), &self.text, |grammar| {
|
||||||
grammar.highlights_query.as_ref()
|
grammar.highlights_query.as_ref()
|
||||||
});
|
});
|
||||||
|
let interaction_captures = self.syntax.captures(range.clone(), &self.text, |grammar| {
|
||||||
|
grammar.interactions_query.as_ref()
|
||||||
|
});
|
||||||
let highlight_maps = captures
|
let highlight_maps = captures
|
||||||
.grammars()
|
.grammars()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|grammar| grammar.highlight_map())
|
.map(|grammar| grammar.highlight_map())
|
||||||
.collect();
|
.collect();
|
||||||
syntax = Some((captures, highlight_maps));
|
syntax = Some((captures, highlight_maps));
|
||||||
|
let interaction_maps = interaction_captures
|
||||||
|
.grammars()
|
||||||
|
.into_iter()
|
||||||
|
.map(|grammar| grammar.interaction_map())
|
||||||
|
.collect();
|
||||||
|
interactions = Some((interaction_captures, interaction_maps));
|
||||||
for entry in self.diagnostics_in_range::<_, usize>(range.clone(), false) {
|
for entry in self.diagnostics_in_range::<_, usize>(range.clone(), false) {
|
||||||
diagnostic_endpoints.push(DiagnosticEndpoint {
|
diagnostic_endpoints.push(DiagnosticEndpoint {
|
||||||
offset: entry.range.start,
|
offset: entry.range.start,
|
||||||
|
@ -2118,7 +2194,13 @@ impl BufferSnapshot {
|
||||||
.sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
|
.sort_unstable_by_key(|endpoint| (endpoint.offset, !endpoint.is_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferChunks::new(self.text.as_rope(), range, syntax, diagnostic_endpoints)
|
BufferChunks::new(
|
||||||
|
self.text.as_rope(),
|
||||||
|
range,
|
||||||
|
syntax,
|
||||||
|
interactions,
|
||||||
|
diagnostic_endpoints,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
|
pub fn for_each_line(&self, range: Range<Point>, mut callback: impl FnMut(u32, &str)) {
|
||||||
|
@ -2735,6 +2817,7 @@ impl<'a> BufferChunks<'a> {
|
||||||
text: &'a Rope,
|
text: &'a Rope,
|
||||||
range: Range<usize>,
|
range: Range<usize>,
|
||||||
syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
|
syntax: Option<(SyntaxMapCaptures<'a>, Vec<HighlightMap>)>,
|
||||||
|
interactions_syntax: Option<(SyntaxMapCaptures<'a>, Vec<InteractionMap>)>,
|
||||||
diagnostic_endpoints: Vec<DiagnosticEndpoint>,
|
diagnostic_endpoints: Vec<DiagnosticEndpoint>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut highlights = None;
|
let mut highlights = None;
|
||||||
|
@ -2743,7 +2826,17 @@ impl<'a> BufferChunks<'a> {
|
||||||
captures,
|
captures,
|
||||||
next_capture: None,
|
next_capture: None,
|
||||||
stack: Default::default(),
|
stack: Default::default(),
|
||||||
highlight_maps,
|
maps: highlight_maps,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut interactions = None;
|
||||||
|
if let Some((captures, interaction_maps)) = interactions_syntax {
|
||||||
|
interactions = Some(BufferChunkInteractions {
|
||||||
|
captures,
|
||||||
|
next_capture: None,
|
||||||
|
stack: Default::default(),
|
||||||
|
maps: interaction_maps,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2760,6 +2853,7 @@ impl<'a> BufferChunks<'a> {
|
||||||
hint_depth: 0,
|
hint_depth: 0,
|
||||||
unnecessary_depth: 0,
|
unnecessary_depth: 0,
|
||||||
highlights,
|
highlights,
|
||||||
|
interactions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2767,22 +2861,10 @@ impl<'a> BufferChunks<'a> {
|
||||||
self.range.start = offset;
|
self.range.start = offset;
|
||||||
self.chunks.seek(self.range.start);
|
self.chunks.seek(self.range.start);
|
||||||
if let Some(highlights) = self.highlights.as_mut() {
|
if let Some(highlights) = self.highlights.as_mut() {
|
||||||
highlights
|
highlights.seek(offset, self.range.clone());
|
||||||
.stack
|
}
|
||||||
.retain(|(end_offset, _)| *end_offset > offset);
|
if let Some(interactions) = self.interactions.as_mut() {
|
||||||
if let Some(capture) = &highlights.next_capture {
|
interactions.seek(offset, self.range.clone());
|
||||||
if offset >= capture.node.start_byte() {
|
|
||||||
let next_capture_end = capture.node.end_byte();
|
|
||||||
if offset < next_capture_end {
|
|
||||||
highlights.stack.push((
|
|
||||||
next_capture_end,
|
|
||||||
highlights.highlight_maps[capture.grammar_index].get(capture.index),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
highlights.next_capture.take();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
highlights.captures.set_byte_range(self.range.clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2840,31 +2922,10 @@ impl<'a> Iterator for BufferChunks<'a> {
|
||||||
let mut next_diagnostic_endpoint = usize::MAX;
|
let mut next_diagnostic_endpoint = usize::MAX;
|
||||||
|
|
||||||
if let Some(highlights) = self.highlights.as_mut() {
|
if let Some(highlights) = self.highlights.as_mut() {
|
||||||
while let Some((parent_capture_end, _)) = highlights.stack.last() {
|
highlights.next(self.range.start, &mut next_capture_start);
|
||||||
if *parent_capture_end <= self.range.start {
|
}
|
||||||
highlights.stack.pop();
|
if let Some(interactions) = self.interactions.as_mut() {
|
||||||
} else {
|
interactions.next(self.range.start, &mut next_capture_start);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if highlights.next_capture.is_none() {
|
|
||||||
highlights.next_capture = highlights.captures.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(capture) = highlights.next_capture.as_ref() {
|
|
||||||
if self.range.start < capture.node.start_byte() {
|
|
||||||
next_capture_start = capture.node.start_byte();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
let highlight_id =
|
|
||||||
highlights.highlight_maps[capture.grammar_index].get(capture.index);
|
|
||||||
highlights
|
|
||||||
.stack
|
|
||||||
.push((capture.node.end_byte(), highlight_id));
|
|
||||||
highlights.next_capture = highlights.captures.next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(endpoint) = self.diagnostic_endpoints.peek().copied() {
|
while let Some(endpoint) = self.diagnostic_endpoints.peek().copied() {
|
||||||
|
@ -2884,10 +2945,11 @@ impl<'a> Iterator for BufferChunks<'a> {
|
||||||
.min(next_diagnostic_endpoint);
|
.min(next_diagnostic_endpoint);
|
||||||
let mut highlight_id = None;
|
let mut highlight_id = None;
|
||||||
if let Some(highlights) = self.highlights.as_ref() {
|
if let Some(highlights) = self.highlights.as_ref() {
|
||||||
if let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last() {
|
highlights.select_current_id(&mut chunk_end, &mut highlight_id);
|
||||||
chunk_end = chunk_end.min(*parent_capture_end);
|
}
|
||||||
highlight_id = Some(*parent_highlight_id);
|
let mut interaction_id = None;
|
||||||
}
|
if let Some(interactions) = self.interactions.as_ref() {
|
||||||
|
interactions.select_current_id(&mut chunk_end, &mut interaction_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let slice =
|
let slice =
|
||||||
|
@ -2900,6 +2962,7 @@ impl<'a> Iterator for BufferChunks<'a> {
|
||||||
Some(Chunk {
|
Some(Chunk {
|
||||||
text: slice,
|
text: slice,
|
||||||
syntax_highlight_id: highlight_id,
|
syntax_highlight_id: highlight_id,
|
||||||
|
interaction_id,
|
||||||
diagnostic_severity: self.current_diagnostic_severity(),
|
diagnostic_severity: self.current_diagnostic_severity(),
|
||||||
is_unnecessary: self.current_code_is_unnecessary(),
|
is_unnecessary: self.current_code_is_unnecessary(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
@ -2,12 +2,25 @@ use gpui::fonts::HighlightStyle;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use theme::SyntaxTheme;
|
use theme::SyntaxTheme;
|
||||||
|
|
||||||
|
use crate::QueryFeatureMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct HighlightMap(Arc<[HighlightId]>);
|
pub struct HighlightMap(Arc<[HighlightId]>);
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct HighlightId(pub u32);
|
pub struct HighlightId(pub u32);
|
||||||
|
|
||||||
|
impl QueryFeatureMap for HighlightMap {
|
||||||
|
type Id = HighlightId;
|
||||||
|
|
||||||
|
fn get(&self, capture_id: u32) -> HighlightId {
|
||||||
|
self.0
|
||||||
|
.get(capture_id as usize)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(DEFAULT_SYNTAX_HIGHLIGHT_ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_SYNTAX_HIGHLIGHT_ID: HighlightId = HighlightId(u32::MAX);
|
const DEFAULT_SYNTAX_HIGHLIGHT_ID: HighlightId = HighlightId(u32::MAX);
|
||||||
|
|
||||||
impl HighlightMap {
|
impl HighlightMap {
|
||||||
|
@ -41,13 +54,6 @@ impl HighlightMap {
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, capture_id: u32) -> HighlightId {
|
|
||||||
self.0
|
|
||||||
.get(capture_id as usize)
|
|
||||||
.copied()
|
|
||||||
.unwrap_or(DEFAULT_SYNTAX_HIGHLIGHT_ID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HighlightId {
|
impl HighlightId {
|
||||||
|
|
59
crates/language/src/interaction_map.rs
Normal file
59
crates/language/src/interaction_map.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct InteractionMap(Arc<[Option<InteractionType>]>);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct InteractionId {
|
||||||
|
event_type: InteractionType,
|
||||||
|
capture: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_INTERACTION_ID: InteractionId = InteractionId {
|
||||||
|
event_type: InteractionType::Click,
|
||||||
|
capture: u32::MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl super::buffer::QueryFeatureMap for InteractionMap {
|
||||||
|
type Id = InteractionId;
|
||||||
|
|
||||||
|
fn get(&self, capture_id: u32) -> Self::Id {
|
||||||
|
match self.0.get(capture_id as usize) {
|
||||||
|
Some(Some(event)) => InteractionId {
|
||||||
|
event_type: *event,
|
||||||
|
capture: capture_id,
|
||||||
|
},
|
||||||
|
_ => DEFAULT_INTERACTION_ID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
enum InteractionType {
|
||||||
|
Click,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractionMap {
|
||||||
|
pub fn new(capture_names: &[String]) -> Self {
|
||||||
|
InteractionMap(
|
||||||
|
capture_names
|
||||||
|
.iter()
|
||||||
|
.map(|capture_name| {
|
||||||
|
let mut capture_parts = capture_name.split(".").peekable();
|
||||||
|
if let Some(str) = capture_parts.next() {
|
||||||
|
if str == "click" && capture_parts.peek().is_some() {
|
||||||
|
return Some(InteractionType::Click);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InteractionMap {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(Arc::new([]))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod diagnostic_set;
|
mod diagnostic_set;
|
||||||
mod highlight_map;
|
mod highlight_map;
|
||||||
|
mod interaction_map;
|
||||||
pub mod language_settings;
|
pub mod language_settings;
|
||||||
mod outline;
|
mod outline;
|
||||||
pub mod proto;
|
pub mod proto;
|
||||||
|
@ -18,7 +19,7 @@ use futures::{
|
||||||
FutureExt, TryFutureExt as _,
|
FutureExt, TryFutureExt as _,
|
||||||
};
|
};
|
||||||
use gpui::{executor::Background, AppContext, AsyncAppContext, Task};
|
use gpui::{executor::Background, AppContext, AsyncAppContext, Task};
|
||||||
pub use highlight_map::HighlightMap;
|
use interaction_map::InteractionMap;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use lsp::{CodeActionKind, LanguageServerBinary};
|
use lsp::{CodeActionKind, LanguageServerBinary};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
|
@ -54,6 +55,8 @@ use futures::channel::mpsc;
|
||||||
pub use buffer::Operation;
|
pub use buffer::Operation;
|
||||||
pub use buffer::*;
|
pub use buffer::*;
|
||||||
pub use diagnostic_set::DiagnosticEntry;
|
pub use diagnostic_set::DiagnosticEntry;
|
||||||
|
pub use highlight_map::HighlightMap;
|
||||||
|
pub use interaction_map::InteractionId;
|
||||||
pub use lsp::LanguageServerId;
|
pub use lsp::LanguageServerId;
|
||||||
pub use outline::{Outline, OutlineItem};
|
pub use outline::{Outline, OutlineItem};
|
||||||
pub use syntax_map::{OwnedSyntaxLayerInfo, SyntaxLayerInfo};
|
pub use syntax_map::{OwnedSyntaxLayerInfo, SyntaxLayerInfo};
|
||||||
|
@ -315,6 +318,12 @@ pub trait LspAdapter: 'static + Send + Sync {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait InteractionProvider: 'static + Send + Sync {
|
||||||
|
fn on_click(&self, _capture: &str, _text: &str) -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct CodeLabel {
|
pub struct CodeLabel {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
@ -358,6 +367,7 @@ pub struct LanguageQueries {
|
||||||
pub embedding: Option<Cow<'static, str>>,
|
pub embedding: Option<Cow<'static, str>>,
|
||||||
pub injections: Option<Cow<'static, str>>,
|
pub injections: Option<Cow<'static, str>>,
|
||||||
pub overrides: Option<Cow<'static, str>>,
|
pub overrides: Option<Cow<'static, str>>,
|
||||||
|
pub interactions: Option<Cow<'static, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -488,6 +498,7 @@ pub struct Language {
|
||||||
pub(crate) config: LanguageConfig,
|
pub(crate) config: LanguageConfig,
|
||||||
pub(crate) grammar: Option<Arc<Grammar>>,
|
pub(crate) grammar: Option<Arc<Grammar>>,
|
||||||
pub(crate) adapters: Vec<Arc<CachedLspAdapter>>,
|
pub(crate) adapters: Vec<Arc<CachedLspAdapter>>,
|
||||||
|
pub(crate) interaction_provider: Option<Arc<dyn InteractionProvider>>,
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
fake_adapter: Option<(
|
fake_adapter: Option<(
|
||||||
|
@ -501,6 +512,7 @@ pub struct Grammar {
|
||||||
pub ts_language: tree_sitter::Language,
|
pub ts_language: tree_sitter::Language,
|
||||||
pub(crate) error_query: Query,
|
pub(crate) error_query: Query,
|
||||||
pub(crate) highlights_query: Option<Query>,
|
pub(crate) highlights_query: Option<Query>,
|
||||||
|
pub(crate) interactions_query: Option<Query>,
|
||||||
pub(crate) brackets_config: Option<BracketConfig>,
|
pub(crate) brackets_config: Option<BracketConfig>,
|
||||||
pub(crate) indents_config: Option<IndentConfig>,
|
pub(crate) indents_config: Option<IndentConfig>,
|
||||||
pub outline_config: Option<OutlineConfig>,
|
pub outline_config: Option<OutlineConfig>,
|
||||||
|
@ -508,6 +520,7 @@ pub struct Grammar {
|
||||||
pub(crate) injection_config: Option<InjectionConfig>,
|
pub(crate) injection_config: Option<InjectionConfig>,
|
||||||
pub(crate) override_config: Option<OverrideConfig>,
|
pub(crate) override_config: Option<OverrideConfig>,
|
||||||
pub(crate) highlight_map: Mutex<HighlightMap>,
|
pub(crate) highlight_map: Mutex<HighlightMap>,
|
||||||
|
pub(crate) interaction_map: Mutex<InteractionMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IndentConfig {
|
struct IndentConfig {
|
||||||
|
@ -578,6 +591,7 @@ struct AvailableLanguage {
|
||||||
config: LanguageConfig,
|
config: LanguageConfig,
|
||||||
grammar: tree_sitter::Language,
|
grammar: tree_sitter::Language,
|
||||||
lsp_adapters: Vec<Arc<dyn LspAdapter>>,
|
lsp_adapters: Vec<Arc<dyn LspAdapter>>,
|
||||||
|
interaction_provider: Option<Arc<dyn InteractionProvider>>,
|
||||||
get_queries: fn(&str) -> LanguageQueries,
|
get_queries: fn(&str) -> LanguageQueries,
|
||||||
loaded: bool,
|
loaded: bool,
|
||||||
}
|
}
|
||||||
|
@ -660,6 +674,7 @@ impl LanguageRegistry {
|
||||||
config: LanguageConfig,
|
config: LanguageConfig,
|
||||||
grammar: tree_sitter::Language,
|
grammar: tree_sitter::Language,
|
||||||
lsp_adapters: Vec<Arc<dyn LspAdapter>>,
|
lsp_adapters: Vec<Arc<dyn LspAdapter>>,
|
||||||
|
interaction_provider: Option<Arc<dyn InteractionProvider>>,
|
||||||
get_queries: fn(&str) -> LanguageQueries,
|
get_queries: fn(&str) -> LanguageQueries,
|
||||||
) {
|
) {
|
||||||
let state = &mut *self.state.write();
|
let state = &mut *self.state.write();
|
||||||
|
@ -670,6 +685,7 @@ impl LanguageRegistry {
|
||||||
grammar,
|
grammar,
|
||||||
lsp_adapters,
|
lsp_adapters,
|
||||||
get_queries,
|
get_queries,
|
||||||
|
interaction_provider,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -832,6 +848,7 @@ impl LanguageRegistry {
|
||||||
let queries = (language.get_queries)(&language.path);
|
let queries = (language.get_queries)(&language.path);
|
||||||
let language =
|
let language =
|
||||||
Language::new(language.config, Some(language.grammar))
|
Language::new(language.config, Some(language.grammar))
|
||||||
|
.with_interaction_provider(language.interaction_provider)
|
||||||
.with_lsp_adapters(language.lsp_adapters)
|
.with_lsp_adapters(language.lsp_adapters)
|
||||||
.await;
|
.await;
|
||||||
let name = language.name();
|
let name = language.name();
|
||||||
|
@ -1170,12 +1187,15 @@ impl Language {
|
||||||
indents_config: None,
|
indents_config: None,
|
||||||
injection_config: None,
|
injection_config: None,
|
||||||
override_config: None,
|
override_config: None,
|
||||||
|
interactions_query: None,
|
||||||
error_query: Query::new(ts_language, "(ERROR) @error").unwrap(),
|
error_query: Query::new(ts_language, "(ERROR) @error").unwrap(),
|
||||||
ts_language,
|
ts_language,
|
||||||
highlight_map: Default::default(),
|
highlight_map: Default::default(),
|
||||||
|
interaction_map: Default::default(),
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
adapters: Vec::new(),
|
adapters: Vec::new(),
|
||||||
|
interaction_provider: None,
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
fake_adapter: None,
|
fake_adapter: None,
|
||||||
|
@ -1226,6 +1246,19 @@ impl Language {
|
||||||
.with_override_query(query.as_ref())
|
.with_override_query(query.as_ref())
|
||||||
.context("Error loading override query")?;
|
.context("Error loading override query")?;
|
||||||
}
|
}
|
||||||
|
if let Some(query) = queries.interactions {
|
||||||
|
self = self
|
||||||
|
.with_interaction_query(query.as_ref())
|
||||||
|
.context("Error loading interaction query")?;
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_interaction_query(mut self, source: &str) -> Result<Self> {
|
||||||
|
let grammar = self.grammar_mut();
|
||||||
|
let query = Query::new(grammar.ts_language, source)?;
|
||||||
|
*grammar.interaction_map.lock() = InteractionMap::new(query.capture_names());
|
||||||
|
grammar.interactions_query = Some(query);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1457,6 +1490,15 @@ impl Language {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_interaction_provider(
|
||||||
|
mut self,
|
||||||
|
interaction_provider: Option<Arc<dyn InteractionProvider>>,
|
||||||
|
) -> Self {
|
||||||
|
self.interaction_provider = interaction_provider;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub async fn set_fake_lsp_adapter(
|
pub async fn set_fake_lsp_adapter(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1534,7 +1576,9 @@ impl Language {
|
||||||
});
|
});
|
||||||
let highlight_maps = vec![grammar.highlight_map()];
|
let highlight_maps = vec![grammar.highlight_map()];
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) {
|
for chunk in
|
||||||
|
BufferChunks::new(text, range, Some((captures, highlight_maps)), None, vec![])
|
||||||
|
{
|
||||||
let end_offset = offset + chunk.text.len();
|
let end_offset = offset + chunk.text.len();
|
||||||
if let Some(highlight_id) = chunk.syntax_highlight_id {
|
if let Some(highlight_id) = chunk.syntax_highlight_id {
|
||||||
if !highlight_id.is_default() {
|
if !highlight_id.is_default() {
|
||||||
|
@ -1680,6 +1724,10 @@ impl Grammar {
|
||||||
self.highlight_map.lock().clone()
|
self.highlight_map.lock().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn interaction_map(&self) -> InteractionMap {
|
||||||
|
self.interaction_map.lock().clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn highlight_id_for_name(&self, name: &str) -> Option<HighlightId> {
|
pub fn highlight_id_for_name(&self, name: &str) -> Option<HighlightId> {
|
||||||
let capture_id = self
|
let capture_id = self
|
||||||
.highlights_query
|
.highlights_query
|
||||||
|
@ -1824,6 +1872,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
tree_sitter_typescript::language_tsx(),
|
tree_sitter_typescript::language_tsx(),
|
||||||
vec![],
|
vec![],
|
||||||
|
None,
|
||||||
|_| Default::default(),
|
|_| Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1860,6 +1909,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
tree_sitter_json::language(),
|
tree_sitter_json::language(),
|
||||||
vec![],
|
vec![],
|
||||||
|
None,
|
||||||
|_| Default::default(),
|
|_| Default::default(),
|
||||||
);
|
);
|
||||||
languages.register(
|
languages.register(
|
||||||
|
@ -1871,6 +1921,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
tree_sitter_rust::language(),
|
tree_sitter_rust::language(),
|
||||||
vec![],
|
vec![],
|
||||||
|
None,
|
||||||
|_| Default::default(),
|
|_| Default::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -2601,6 +2601,7 @@ async fn test_save_as(cx: &mut gpui::TestAppContext) {
|
||||||
},
|
},
|
||||||
tree_sitter_rust::language(),
|
tree_sitter_rust::language(),
|
||||||
vec![],
|
vec![],
|
||||||
|
None,
|
||||||
|_| Default::default(),
|
|_| Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ mod json;
|
||||||
#[cfg(feature = "plugin_runtime")]
|
#[cfg(feature = "plugin_runtime")]
|
||||||
mod language_plugin;
|
mod language_plugin;
|
||||||
mod lua;
|
mod lua;
|
||||||
|
mod markdown;
|
||||||
mod php;
|
mod php;
|
||||||
mod python;
|
mod python;
|
||||||
mod ruby;
|
mod ruby;
|
||||||
|
@ -36,36 +37,48 @@ mod yaml;
|
||||||
struct LanguageDir;
|
struct LanguageDir;
|
||||||
|
|
||||||
pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
|
pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
|
||||||
let language = |name, grammar, adapters| {
|
let language = |name, grammar, adapters, interactions| {
|
||||||
languages.register(name, load_config(name), grammar, adapters, load_queries)
|
languages.register(
|
||||||
|
name,
|
||||||
|
load_config(name),
|
||||||
|
grammar,
|
||||||
|
adapters,
|
||||||
|
interactions,
|
||||||
|
load_queries,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
language("bash", tree_sitter_bash::language(), vec![]);
|
language("bash", tree_sitter_bash::language(), vec![], None);
|
||||||
language(
|
language(
|
||||||
"c",
|
"c",
|
||||||
tree_sitter_c::language(),
|
tree_sitter_c::language(),
|
||||||
vec![Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>],
|
vec![Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"cpp",
|
"cpp",
|
||||||
tree_sitter_cpp::language(),
|
tree_sitter_cpp::language(),
|
||||||
vec![Arc::new(c::CLspAdapter)],
|
vec![Arc::new(c::CLspAdapter)],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language("css", tree_sitter_css::language(), vec![]);
|
language("css", tree_sitter_css::language(), vec![], None);
|
||||||
language(
|
language(
|
||||||
"elixir",
|
"elixir",
|
||||||
tree_sitter_elixir::language(),
|
tree_sitter_elixir::language(),
|
||||||
vec![Arc::new(elixir::ElixirLspAdapter)],
|
vec![Arc::new(elixir::ElixirLspAdapter)],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"go",
|
"go",
|
||||||
tree_sitter_go::language(),
|
tree_sitter_go::language(),
|
||||||
vec![Arc::new(go::GoLspAdapter)],
|
vec![Arc::new(go::GoLspAdapter)],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"heex",
|
"heex",
|
||||||
tree_sitter_heex::language(),
|
tree_sitter_heex::language(),
|
||||||
vec![Arc::new(elixir::ElixirLspAdapter)],
|
vec![Arc::new(elixir::ElixirLspAdapter)],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"json",
|
"json",
|
||||||
|
@ -74,21 +87,29 @@ pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
|
||||||
node_runtime.clone(),
|
node_runtime.clone(),
|
||||||
languages.clone(),
|
languages.clone(),
|
||||||
))],
|
))],
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
language(
|
||||||
|
"markdown",
|
||||||
|
tree_sitter_markdown::language(),
|
||||||
|
vec![],
|
||||||
|
Some(Arc::new(MarkdownInteractions)),
|
||||||
);
|
);
|
||||||
language("markdown", tree_sitter_markdown::language(), vec![]);
|
|
||||||
language(
|
language(
|
||||||
"python",
|
"python",
|
||||||
tree_sitter_python::language(),
|
tree_sitter_python::language(),
|
||||||
vec![Arc::new(python::PythonLspAdapter::new(
|
vec![Arc::new(python::PythonLspAdapter::new(
|
||||||
node_runtime.clone(),
|
node_runtime.clone(),
|
||||||
))],
|
))],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"rust",
|
"rust",
|
||||||
tree_sitter_rust::language(),
|
tree_sitter_rust::language(),
|
||||||
vec![Arc::new(rust::RustLspAdapter)],
|
vec![Arc::new(rust::RustLspAdapter)],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language("toml", tree_sitter_toml::language(), vec![]);
|
language("toml", tree_sitter_toml::language(), vec![], None);
|
||||||
language(
|
language(
|
||||||
"tsx",
|
"tsx",
|
||||||
tree_sitter_typescript::language_tsx(),
|
tree_sitter_typescript::language_tsx(),
|
||||||
|
@ -96,6 +117,7 @@ pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
|
||||||
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
|
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
|
||||||
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
|
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
|
||||||
],
|
],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"typescript",
|
"typescript",
|
||||||
|
@ -104,6 +126,7 @@ pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
|
||||||
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
|
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
|
||||||
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
|
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
|
||||||
],
|
],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"javascript",
|
"javascript",
|
||||||
|
@ -112,33 +135,39 @@ pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
|
||||||
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
|
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
|
||||||
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
|
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
|
||||||
],
|
],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"html",
|
"html",
|
||||||
tree_sitter_html::language(),
|
tree_sitter_html::language(),
|
||||||
vec![Arc::new(html::HtmlLspAdapter::new(node_runtime.clone()))],
|
vec![Arc::new(html::HtmlLspAdapter::new(node_runtime.clone()))],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"ruby",
|
"ruby",
|
||||||
tree_sitter_ruby::language(),
|
tree_sitter_ruby::language(),
|
||||||
vec![Arc::new(ruby::RubyLanguageServer)],
|
vec![Arc::new(ruby::RubyLanguageServer)],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"erb",
|
"erb",
|
||||||
tree_sitter_embedded_template::language(),
|
tree_sitter_embedded_template::language(),
|
||||||
vec![Arc::new(ruby::RubyLanguageServer)],
|
vec![Arc::new(ruby::RubyLanguageServer)],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language("scheme", tree_sitter_scheme::language(), vec![]);
|
language("scheme", tree_sitter_scheme::language(), vec![], None);
|
||||||
language("racket", tree_sitter_racket::language(), vec![]);
|
language("racket", tree_sitter_racket::language(), vec![], None);
|
||||||
language(
|
language(
|
||||||
"lua",
|
"lua",
|
||||||
tree_sitter_lua::language(),
|
tree_sitter_lua::language(),
|
||||||
vec![Arc::new(lua::LuaLspAdapter)],
|
vec![Arc::new(lua::LuaLspAdapter)],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"yaml",
|
"yaml",
|
||||||
tree_sitter_yaml::language(),
|
tree_sitter_yaml::language(),
|
||||||
vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))],
|
vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"svelte",
|
"svelte",
|
||||||
|
@ -146,16 +175,18 @@ pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
|
||||||
vec![Arc::new(svelte::SvelteLspAdapter::new(
|
vec![Arc::new(svelte::SvelteLspAdapter::new(
|
||||||
node_runtime.clone(),
|
node_runtime.clone(),
|
||||||
))],
|
))],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
language(
|
language(
|
||||||
"php",
|
"php",
|
||||||
tree_sitter_php::language(),
|
tree_sitter_php::language(),
|
||||||
vec![Arc::new(php::IntelephenseLspAdapter::new(node_runtime))],
|
vec![Arc::new(php::IntelephenseLspAdapter::new(node_runtime))],
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
language("elm", tree_sitter_elm::language(), vec![]);
|
language("elm", tree_sitter_elm::language(), vec![], None);
|
||||||
language("glsl", tree_sitter_glsl::language(), vec![]);
|
language("glsl", tree_sitter_glsl::language(), vec![], None);
|
||||||
language("nix", tree_sitter_nix::language(), vec![]);
|
language("nix", tree_sitter_nix::language(), vec![], None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
@ -192,6 +223,7 @@ fn load_queries(name: &str) -> LanguageQueries {
|
||||||
embedding: load_query(name, "/embedding"),
|
embedding: load_query(name, "/embedding"),
|
||||||
injections: load_query(name, "/injections"),
|
injections: load_query(name, "/injections"),
|
||||||
overrides: load_query(name, "/overrides"),
|
overrides: load_query(name, "/overrides"),
|
||||||
|
interactions: load_query(name, "/interactions"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
crates/zed/src/languages/markdown.rs
Normal file
15
crates/zed/src/languages/markdown.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use language::InteractionProvider;
|
||||||
|
|
||||||
|
pub struct MarkdownInteractions;
|
||||||
|
|
||||||
|
impl InteractionProvider for MarkdownInteractions {
|
||||||
|
fn on_click(&self, text: &str) -> Option<String> {
|
||||||
|
if text == "[ ]" {
|
||||||
|
return Some("[x]".to_string());
|
||||||
|
} else if text == "[x]" {
|
||||||
|
return Some("[ ]".to_string());
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
crates/zed/src/languages/markdown/interactions.scm
Normal file
5
crates/zed/src/languages/markdown/interactions.scm
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
(
|
||||||
|
(list_item (paragraph (shortcut_link) @click.toggle_selected))
|
||||||
|
(#matches? @click.toggle_selected "^([ ]|[x])")
|
||||||
|
)
|
Loading…
Reference in a new issue