Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-syntax/src/highlighter.rs')
| -rw-r--r-- | helix-syntax/src/highlighter.rs | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/helix-syntax/src/highlighter.rs b/helix-syntax/src/highlighter.rs new file mode 100644 index 00000000..8801b13f --- /dev/null +++ b/helix-syntax/src/highlighter.rs @@ -0,0 +1,438 @@ +pub use super::highlighter2::*; + +// use std::borrow::Cow; +// use std::cell::RefCell; +// use std::sync::atomic::{self, AtomicUsize}; +// use std::{fmt, iter, mem, ops}; + +// use ropey::RopeSlice; +// use tree_sitter::{QueryCaptures, QueryCursor, Tree}; + +// use crate::{byte_range_to_str, Error, HighlightConfiguration, Syntax, TREE_SITTER_MATCH_LIMIT}; + +// const CANCELLATION_CHECK_INTERVAL: usize = 100; + +// /// Indicates which highlight should be applied to a region of source code. +// #[derive(Copy, Clone, Debug, PartialEq, Eq)] +// pub struct Highlight(pub usize); + +// /// Represents a single step in rendering a syntax-highlighted document. +// #[derive(Copy, Clone, Debug)] +// pub enum HighlightEvent { +// Source { start: usize, end: usize }, +// HighlightStart(Highlight), +// HighlightEnd, +// } + +// #[derive(Debug)] +// struct LocalDef<'a> { +// name: Cow<'a, str>, +// value_range: ops::Range<usize>, +// highlight: Option<Highlight>, +// } + +// #[derive(Debug)] +// struct LocalScope<'a> { +// inherits: bool, +// range: ops::Range<usize>, +// local_defs: Vec<LocalDef<'a>>, +// } + +// #[derive(Debug)] +// struct HighlightIter<'a> { +// source: RopeSlice<'a>, +// byte_offset: usize, +// cancellation_flag: Option<&'a AtomicUsize>, +// layers: Vec<HighlightIterLayer<'a>>, +// iter_count: usize, +// next_event: Option<HighlightEvent>, +// last_highlight_range: Option<(usize, usize, u32)>, +// } + +// struct HighlightIterLayer<'a> { +// _tree: Option<Tree>, +// cursor: QueryCursor, +// captures: RefCell<iter::Peekable<QueryCaptures<'a, 'a, RopeProvider<'a>, &'a [u8]>>>, +// config: &'a HighlightConfiguration, +// highlight_end_stack: Vec<usize>, +// scope_stack: Vec<LocalScope<'a>>, +// depth: u32, +// } + +// impl<'a> fmt::Debug for HighlightIterLayer<'a> { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_struct("HighlightIterLayer").finish() +// } +// } + +// impl<'a> HighlightIterLayer<'a> { +// // First, sort scope boundaries by their byte offset in the document. At a +// // given position, emit scope endings before scope beginnings. Finally, emit +// // scope boundaries from deeper layers first. +// fn sort_key(&self) -> Option<(usize, bool, isize)> { +// let depth = -(self.depth as isize); +// let next_start = self +// .captures +// .borrow_mut() +// .peek() +// .map(|(m, i)| m.captures[*i].node.start_byte()); +// let next_end = self.highlight_end_stack.last().cloned(); +// match (next_start, next_end) { +// (Some(start), Some(end)) => { +// if start < end { +// Some((start, true, depth)) +// } else { +// Some((end, false, depth)) +// } +// } +// (Some(i), None) => Some((i, true, depth)), +// (None, Some(j)) => Some((j, false, depth)), +// _ => None, +// } +// } +// } + +// impl<'a> HighlightIter<'a> { +// fn emit_event( +// &mut self, +// offset: usize, +// event: Option<HighlightEvent>, +// ) -> Option<Result<HighlightEvent, Error>> { +// let result; +// if self.byte_offset < offset { +// result = Some(Ok(HighlightEvent::Source { +// start: self.byte_offset, +// end: offset, +// })); +// self.byte_offset = offset; +// self.next_event = event; +// } else { +// result = event.map(Ok); +// } +// self.sort_layers(); +// result +// } + +// fn sort_layers(&mut self) { +// while !self.layers.is_empty() { +// if let Some(sort_key) = self.layers[0].sort_key() { +// let mut i = 0; +// while i + 1 < self.layers.len() { +// if let Some(next_offset) = self.layers[i + 1].sort_key() { +// if next_offset < sort_key { +// i += 1; +// continue; +// } +// } else { +// let layer = self.layers.remove(i + 1); +// PARSER.with(|ts_parser| { +// let highlighter = &mut ts_parser.borrow_mut(); +// highlighter.cursors.push(layer.cursor); +// }); +// } +// break; +// } +// if i > 0 { +// self.layers[0..(i + 1)].rotate_left(1); +// } +// break; +// } else { +// let layer = self.layers.remove(0); +// PARSER.with(|ts_parser| { +// let highlighter = &mut ts_parser.borrow_mut(); +// highlighter.cursors.push(layer.cursor); +// }); +// } +// } +// } +// } + +// impl<'a> Iterator for HighlightIter<'a> { +// type Item = Result<HighlightEvent, Error>; + +// fn next(&mut self) -> Option<Self::Item> { +// 'main: loop { +// // If we've already determined the next highlight boundary, just return it. +// if let Some(e) = self.next_event.take() { +// return Some(Ok(e)); +// } + +// // Periodically check for cancellation, returning `Cancelled` error if the +// // cancellation flag was flipped. +// if let Some(cancellation_flag) = self.cancellation_flag { +// self.iter_count += 1; +// if self.iter_count >= CANCELLATION_CHECK_INTERVAL { +// self.iter_count = 0; +// if cancellation_flag.load(atomic::Ordering::Relaxed) != 0 { +// return Some(Err(Error::Cancelled)); +// } +// } +// } + +// // If none of the layers have any more highlight boundaries, terminate. +// if self.layers.is_empty() { +// let len = self.source.len_bytes(); +// return if self.byte_offset < len { +// let result = Some(Ok(HighlightEvent::Source { +// start: self.byte_offset, +// end: len, +// })); +// self.byte_offset = len; +// result +// } else { +// None +// }; +// } + +// // Get the next capture from whichever layer has the earliest highlight boundary. +// let range; +// let layer = &mut self.layers[0]; +// let captures = layer.captures.get_mut(); +// if let Some((next_match, capture_index)) = captures.peek() { +// let next_capture = next_match.captures[*capture_index]; +// range = next_capture.node.byte_range(); + +// // If any previous highlight ends before this node starts, then before +// // processing this capture, emit the source code up until the end of the +// // previous highlight, and an end event for that highlight. +// if let Some(end_byte) = layer.highlight_end_stack.last().cloned() { +// if end_byte <= range.start { +// layer.highlight_end_stack.pop(); +// return self.emit_event(end_byte, Some(HighlightEvent::HighlightEnd)); +// } +// } +// } +// // If there are no more captures, then emit any remaining highlight end events. +// // And if there are none of those, then just advance to the end of the document. +// else if let Some(end_byte) = layer.highlight_end_stack.last().cloned() { +// layer.highlight_end_stack.pop(); +// return self.emit_event(end_byte, Some(HighlightEvent::HighlightEnd)); +// } else { +// return self.emit_event(self.source.len_bytes(), None); +// }; + +// let (mut match_, capture_index) = captures.next().unwrap(); +// let mut capture = match_.captures[capture_index]; + +// // Remove from the local scope stack any local scopes that have already ended. +// while range.start > layer.scope_stack.last().unwrap().range.end { +// layer.scope_stack.pop(); +// } + +// // If this capture is for tracking local variables, then process the +// // local variable info. +// let mut reference_highlight = None; +// let mut definition_highlight = None; +// while match_.pattern_index < layer.config.highlights_pattern_index { +// // If the node represents a local scope, push a new local scope onto +// // the scope stack. +// if Some(capture.index) == layer.config.local_scope_capture_index { +// definition_highlight = None; +// let mut scope = LocalScope { +// inherits: true, +// range: range.clone(), +// local_defs: Vec::new(), +// }; +// for prop in layer.config.query.property_settings(match_.pattern_index) { +// if let "local.scope-inherits" = prop.key.as_ref() { +// scope.inherits = +// prop.value.as_ref().map_or(true, |r| r.as_ref() == "true"); +// } +// } +// layer.scope_stack.push(scope); +// } +// // If the node represents a definition, add a new definition to the +// // local scope at the top of the scope stack. +// else if Some(capture.index) == layer.config.local_def_capture_index { +// reference_highlight = None; +// let scope = layer.scope_stack.last_mut().unwrap(); + +// let mut value_range = 0..0; +// for capture in match_.captures { +// if Some(capture.index) == layer.config.local_def_value_capture_index { +// value_range = capture.node.byte_range(); +// } +// } + +// let name = byte_range_to_str(range.clone(), self.source); +// scope.local_defs.push(LocalDef { +// name, +// value_range, +// highlight: None, +// }); +// definition_highlight = scope.local_defs.last_mut().map(|s| &mut s.highlight); +// } +// // If the node represents a reference, then try to find the corresponding +// // definition in the scope stack. +// else if Some(capture.index) == layer.config.local_ref_capture_index +// && definition_highlight.is_none() +// { +// definition_highlight = None; +// let name = byte_range_to_str(range.clone(), self.source); +// for scope in layer.scope_stack.iter().rev() { +// if let Some(highlight) = scope.local_defs.iter().rev().find_map(|def| { +// if def.name == name && range.start >= def.value_range.end { +// Some(def.highlight) +// } else { +// None +// } +// }) { +// reference_highlight = highlight; +// break; +// } +// if !scope.inherits { +// break; +// } +// } +// } + +// // Continue processing any additional matches for the same node. +// if let Some((next_match, next_capture_index)) = captures.peek() { +// let next_capture = next_match.captures[*next_capture_index]; +// if next_capture.node == capture.node { +// capture = next_capture; +// match_ = captures.next().unwrap().0; +// continue; +// } +// } + +// self.sort_layers(); +// continue 'main; +// } + +// // Otherwise, this capture must represent a highlight. +// // If this exact range has already been highlighted by an earlier pattern, or by +// // a different layer, then skip over this one. +// if let Some((last_start, last_end, last_depth)) = self.last_highlight_range { +// if range.start == last_start && range.end == last_end && layer.depth < last_depth { +// self.sort_layers(); +// continue 'main; +// } +// } + +// // If the current node was found to be a local variable, then skip over any +// // highlighting patterns that are disabled for local variables. +// if definition_highlight.is_some() || reference_highlight.is_some() { +// while layer.config.non_local_variable_patterns[match_.pattern_index] { +// match_.remove(); +// if let Some((next_match, next_capture_index)) = captures.peek() { +// let next_capture = next_match.captures[*next_capture_index]; +// if next_capture.node == capture.node { +// capture = next_capture; +// match_ = captures.next().unwrap().0; +// continue; +// } +// } + +// self.sort_layers(); +// continue 'main; +// } +// } + +// // Once a highlighting pattern is found for the current node, skip over +// // any later highlighting patterns that also match this node. Captures +// // for a given node are ordered by pattern index, so these subsequent +// // captures are guaranteed to be for highlighting, not injections or +// // local variables. +// while let Some((next_match, next_capture_index)) = captures.peek() { +// let next_capture = next_match.captures[*next_capture_index]; +// if next_capture.node == capture.node { +// captures.next(); +// } else { +// break; +// } +// } + +// let current_highlight = layer.config.highlight_indices.load()[capture.index as usize]; + +// // If this node represents a local definition, then store the current +// // highlight value on the local scope entry representing this node. +// if let Some(definition_highlight) = definition_highlight { +// *definition_highlight = current_highlight; +// } + +// // Emit a scope start event and push the node's end position to the stack. +// if let Some(highlight) = reference_highlight.or(current_highlight) { +// self.last_highlight_range = Some((range.start, range.end, layer.depth)); +// layer.highlight_end_stack.push(range.end); +// return self +// .emit_event(range.start, Some(HighlightEvent::HighlightStart(highlight))); +// } + +// self.sort_layers(); +// } +// } +// } + +// impl Syntax { +// /// Iterate over the highlighted regions for a given slice of source code. +// pub fn highlight_iter<'a>( +// &'a self, +// source: RopeSlice<'a>, +// range: Option<std::ops::Range<usize>>, +// cancellation_flag: Option<&'a AtomicUsize>, +// ) -> impl Iterator<Item = Result<HighlightEvent, Error>> + 'a { +// let mut layers = self +// .layers +// .iter() +// .filter_map(|(_, layer)| { +// // TODO: if range doesn't overlap layer range, skip it + +// // Reuse a cursor from the pool if available. +// let mut cursor = PARSER.with(|ts_parser| { +// let highlighter = &mut ts_parser.borrow_mut(); +// highlighter.cursors.pop().unwrap_or_else(QueryCursor::new) +// }); + +// // The `captures` iterator borrows the `Tree` and the `QueryCursor`, which +// // prevents them from being moved. But both of these values are really just +// // pointers, so it's actually ok to move them. +// let cursor_ref = +// unsafe { mem::transmute::<_, &'static mut QueryCursor>(&mut cursor) }; + +// // if reusing cursors & no range this resets to whole range +// cursor_ref.set_byte_range(range.clone().unwrap_or(0..usize::MAX)); +// cursor_ref.set_match_limit(TREE_SITTER_MATCH_LIMIT); + +// let mut captures = cursor_ref +// .captures( +// &layer.config.query, +// layer.tree().root_node(), +// RopeProvider(source), +// ) +// .peekable(); + +// // If there's no captures, skip the layer +// captures.peek()?; + +// Some(HighlightIterLayer { +// highlight_end_stack: Vec::new(), +// scope_stack: vec![LocalScope { +// inherits: false, +// range: 0..usize::MAX, +// local_defs: Vec::new(), +// }], +// cursor, +// _tree: None, +// captures: RefCell::new(captures), +// config: layer.config.as_ref(), // TODO: just reuse `layer` +// depth: layer.depth, // TODO: just reuse `layer` +// }) +// }) +// .collect::<Vec<_>>(); + +// layers.sort_unstable_by_key(|layer| layer.sort_key()); + +// let mut result = HighlightIter { +// source, +// byte_offset: range.map_or(0, |r| r.start), +// cancellation_flag, +// iter_count: 0, +// layers, +// next_event: None, +// last_highlight_range: None, +// }; +// result.sort_layers(); +// result +// } +// } |