chore(highlight): apply clippy fixes

This commit is contained in:
Amaan Qureshi 2024-02-04 02:00:42 -05:00
parent 28bb2a8c1c
commit f32fa784be
No known key found for this signature in database
GPG key ID: E67890ADC4227273
4 changed files with 89 additions and 72 deletions

View file

@ -5,9 +5,10 @@
[crates.io]: https://crates.io/crates/tree-sitter-highlight
[crates.io badge]: https://img.shields.io/crates/v/tree-sitter-highlight.svg?color=%23B48723
### Usage
## Usage
Add this crate, and the language-specific crates for whichever languages you want to parse, to your `Cargo.toml`:
Add this crate, and the language-specific crates for whichever languages you want
to parse, to your `Cargo.toml`:
```toml
[dependencies]
@ -40,7 +41,8 @@ let highlight_names = [
];
```
Create a highlighter. You need one of these for each thread that you're using for syntax highlighting:
Create a highlighter. You need one of these for each thread that you're using for
syntax highlighting:
```rust
use tree_sitter_highlight::Highlighter;
@ -57,9 +59,11 @@ let javascript_language = tree_sitter_javascript::language();
let mut javascript_config = HighlightConfiguration::new(
javascript_language,
"javascript",
tree_sitter_javascript::HIGHLIGHT_QUERY,
tree_sitter_javascript::INJECTION_QUERY,
tree_sitter_javascript::LOCALS_QUERY,
false,
).unwrap();
```
@ -96,4 +100,6 @@ for event in highlights {
}
```
The last parameter to `highlight` is a *language injection* callback. This allows other languages to be retrieved when Tree-sitter detects an embedded document (for example, a piece of JavaScript code inside of a `script` tag within HTML).
The last parameter to `highlight` is a _language injection_ callback. This allows
other languages to be retrieved when Tree-sitter detects an embedded document
(for example, a piece of JavaScript code inside a `script` tag within HTML).

View file

@ -105,20 +105,20 @@ pub unsafe extern "C" fn ts_highlighter_add_language(
};
let highlight_query =
slice::from_raw_parts(highlight_query as *const u8, highlight_query_len as usize);
slice::from_raw_parts(highlight_query.cast::<u8>(), highlight_query_len as usize);
let highlight_query = str::from_utf8(highlight_query).or(Err(ErrorCode::InvalidUtf8))?;
let injection_query = if injection_query_len > 0 {
let query =
slice::from_raw_parts(injection_query as *const u8, injection_query_len as usize);
slice::from_raw_parts(injection_query.cast::<u8>(), injection_query_len as usize);
str::from_utf8(query).or(Err(ErrorCode::InvalidUtf8))?
} else {
""
};
let locals_query = if locals_query_len > 0 {
let query = slice::from_raw_parts(locals_query as *const u8, locals_query_len as usize);
let query = slice::from_raw_parts(locals_query.cast::<u8>(), locals_query_len as usize);
str::from_utf8(query).or(Err(ErrorCode::InvalidUtf8))?
} else {
""
@ -167,7 +167,7 @@ pub extern "C" fn ts_highlight_buffer_new() -> *mut TSHighlightBuffer {
/// It cannot be used after this function is called.
#[no_mangle]
pub unsafe extern "C" fn ts_highlighter_delete(this: *mut TSHighlighter) {
drop(Box::from_raw(this))
drop(Box::from_raw(this));
}
/// Deletes a [`TSHighlightBuffer`] instance.
@ -180,7 +180,7 @@ pub unsafe extern "C" fn ts_highlighter_delete(this: *mut TSHighlighter) {
/// It cannot be used after this function is called.
#[no_mangle]
pub unsafe extern "C" fn ts_highlight_buffer_delete(this: *mut TSHighlightBuffer) {
drop(Box::from_raw(this))
drop(Box::from_raw(this));
}
/// Get the HTML content of a [`TSHighlightBuffer`] instance as a raw pointer.
@ -263,7 +263,7 @@ pub unsafe extern "C" fn ts_highlighter_highlight(
let this = unwrap_ptr(this);
let output = unwrap_mut_ptr(output);
let scope_name = unwrap(CStr::from_ptr(scope_name).to_str());
let source_code = slice::from_raw_parts(source_code as *const u8, source_code_len as usize);
let source_code = slice::from_raw_parts(source_code.cast::<u8>(), source_code_len as usize);
let cancellation_flag = cancellation_flag.as_ref();
this.highlight(source_code, scope_name, output, cancellation_flag)
}
@ -309,7 +309,7 @@ impl TSHighlighter {
.renderer
.render(highlights, source_code, &|s| self.attribute_strings[s.0]);
match result {
Err(Error::Cancelled) | Err(Error::Unknown) => ErrorCode::Timeout,
Err(Error::Cancelled | Error::Unknown) => ErrorCode::Timeout,
Err(Error::InvalidLanguage) => ErrorCode::InvalidLanguage,
Ok(()) => ErrorCode::Ok,
}
@ -335,7 +335,7 @@ unsafe fn unwrap_mut_ptr<'a, T>(result: *mut T) -> &'a mut T {
fn unwrap<T, E: fmt::Display>(result: Result<T, E>) -> T {
result.unwrap_or_else(|error| {
eprintln!("tree-sitter highlight error: {}", error);
eprintln!("tree-sitter highlight error: {error}");
abort();
})
}

View file

@ -1,7 +1,6 @@
#![doc = include_str!("../README.md")]
pub mod c_lib;
pub mod util;
pub use c_lib as c;
use lazy_static::lazy_static;
@ -180,9 +179,16 @@ struct HighlightIterLayer<'a> {
depth: usize,
}
impl Default for Highlighter {
fn default() -> Self {
Self::new()
}
}
impl Highlighter {
#[must_use]
pub fn new() -> Self {
Highlighter {
Self {
parser: Parser::new(),
cursors: Vec::new(),
}
@ -333,7 +339,7 @@ impl HighlightConfiguration {
}
let highlight_indices = vec![None; query.capture_names().len()];
Ok(HighlightConfiguration {
Ok(Self {
language,
language_name: name.into(),
query,
@ -353,7 +359,8 @@ impl HighlightConfiguration {
}
/// Get a slice containing all of the highlight names used in the configuration.
pub fn names(&self) -> &[&str] {
#[must_use]
pub const fn names(&self) -> &[&str] {
self.query.capture_names()
}
@ -377,7 +384,7 @@ impl HighlightConfiguration {
let mut best_index = None;
let mut best_match_len = 0;
for (i, recognized_name) in recognized_names.into_iter().enumerate() {
for (i, recognized_name) in recognized_names.iter().enumerate() {
let mut len = 0;
let mut matches = true;
for part in recognized_name.as_ref().split('.') {
@ -399,16 +406,17 @@ impl HighlightConfiguration {
// Return the list of this configuration's capture names that are neither present in the
// list of predefined 'canonical' names nor start with an underscore (denoting 'private' captures
// used as part of capture internals).
#[must_use]
pub fn nonconformant_capture_names(&self, capture_names: &HashSet<&str>) -> Vec<&str> {
let capture_names = if capture_names.is_empty() {
&*STANDARD_CAPTURE_NAMES
} else {
&capture_names
capture_names
};
self.names()
.iter()
.filter(|&n| !(n.starts_with('_') || capture_names.contains(n)))
.map(|n| *n)
.copied()
.collect()
}
}
@ -419,6 +427,7 @@ impl<'a> HighlightIterLayer<'a> {
/// In the even that the new layer contains "combined injections" (injections where multiple
/// disjoint ranges are parsed as one syntax tree), these will be eagerly processed and
/// added to the returned vector.
#[allow(clippy::too_many_arguments)]
fn new<F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a>(
source: &'a [u8],
parent_name: Option<&str>,
@ -444,7 +453,7 @@ impl<'a> HighlightIterLayer<'a> {
.parse(source, None)
.ok_or(Error::Cancelled)?;
unsafe { highlighter.parser.set_cancellation_flag(None) };
let mut cursor = highlighter.cursors.pop().unwrap_or(QueryCursor::new());
let mut cursor = highlighter.cursors.pop().unwrap_or_default();
// Process combined injections.
if let Some(combined_injections_query) = &config.combined_injections_query {
@ -514,12 +523,12 @@ impl<'a> HighlightIterLayer<'a> {
if queue.is_empty() {
break;
} else {
let (next_config, next_depth, next_ranges) = queue.remove(0);
config = next_config;
depth = next_depth;
ranges = next_ranges;
}
let (next_config, next_depth, next_ranges) = queue.remove(0);
config = next_config;
depth = next_depth;
ranges = next_ranges;
}
Ok(result)
@ -545,7 +554,7 @@ impl<'a> HighlightIterLayer<'a> {
let mut parent_range = parent_range_iter
.next()
.expect("Layers should only be constructed with non-empty ranges vectors");
for node in nodes.iter() {
for node in nodes {
let mut preceding_range = Range {
start_byte: 0,
start_point: Point::new(0, 0),
@ -568,7 +577,7 @@ impl<'a> HighlightIterLayer<'a> {
Some(child.range())
}
})
.chain([following_range].iter().cloned())
.chain(std::iter::once(following_range))
{
let mut range = Range {
start_byte: preceding_range.end_byte,
@ -628,7 +637,7 @@ impl<'a> HighlightIterLayer<'a> {
.captures
.peek()
.map(|(m, i)| m.captures[*i].node.start_byte());
let next_end = self.highlight_end_stack.last().cloned();
let next_end = self.highlight_end_stack.last().copied();
match (next_start, next_end) {
(Some(start), Some(end)) => {
if start < end {
@ -685,10 +694,9 @@ where
self.layers[0..(i + 1)].rotate_left(1);
}
break;
} else {
let layer = self.layers.remove(0);
self.highlighter.cursors.push(layer.cursor);
}
let layer = self.layers.remove(0);
self.highlighter.cursors.push(layer.cursor);
}
}
@ -760,7 +768,7 @@ where
// 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 let Some(end_byte) = layer.highlight_end_stack.last().copied() {
if end_byte <= range.start {
layer.highlight_end_stack.pop();
return self.emit_event(end_byte, Some(HighlightEvent::HighlightEnd));
@ -769,7 +777,7 @@ where
}
// 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() {
else if let Some(end_byte) = layer.highlight_end_stack.last().copied() {
layer.highlight_end_stack.pop();
return self.emit_event(end_byte, Some(HighlightEvent::HighlightEnd));
} else {
@ -848,12 +856,9 @@ where
local_defs: Vec::new(),
};
for prop in layer.config.query.property_settings(match_.pattern_index) {
match prop.key.as_ref() {
"local.scope-inherits" => {
scope.inherits =
prop.value.as_ref().map_or(true, |r| r.as_ref() == "true");
}
_ => {}
if prop.key.as_ref() == "local.scope-inherits" {
scope.inherits =
prop.value.as_ref().map_or(true, |r| r.as_ref() == "true");
}
}
layer.scope_stack.push(scope);
@ -884,26 +889,24 @@ where
}
// 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 {
if definition_highlight.is_none() {
definition_highlight = None;
if let Ok(name) = str::from_utf8(&self.source[range.clone()]) {
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;
else if Some(capture.index) == layer.config.local_ref_capture_index
&& definition_highlight.is_none()
{
definition_highlight = None;
if let Ok(name) = str::from_utf8(&self.source[range.clone()]) {
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;
}
}
}
@ -993,9 +996,16 @@ where
}
}
impl Default for HtmlRenderer {
fn default() -> Self {
Self::new()
}
}
impl HtmlRenderer {
#[must_use]
pub fn new() -> Self {
let mut result = HtmlRenderer {
let mut result = Self {
html: Vec::with_capacity(BUFFER_HTML_RESERVE_CAPACITY),
line_offsets: Vec::with_capacity(BUFFER_LINES_RESERVE_CAPACITY),
carriage_return_highlight: None,
@ -1095,10 +1105,21 @@ impl HtmlRenderer {
self.html.extend(b"</span>");
}
fn add_text<'a, F>(&mut self, src: &[u8], highlights: &Vec<Highlight>, attribute_callback: &F)
fn add_text<'a, F>(&mut self, src: &[u8], highlights: &[Highlight], attribute_callback: &F)
where
F: Fn(Highlight) -> &'a [u8],
{
pub const fn html_escape(c: u8) -> Option<&'static [u8]> {
match c as char {
'>' => Some(b"&gt;"),
'<' => Some(b"&lt;"),
'&' => Some(b"&amp;"),
'\'' => Some(b"&#39;"),
'"' => Some(b"&quot;"),
_ => None,
}
}
let mut last_char_was_cr = false;
for c in LossyUtf8::new(src).flat_map(|p| p.bytes()) {
// Don't render carriage return characters, but allow lone carriage returns (not
@ -1122,7 +1143,7 @@ impl HtmlRenderer {
highlights
.iter()
.for_each(|scope| self.start_highlight(*scope, attribute_callback));
} else if let Some(escape) = util::html_escape(c) {
} else if let Some(escape) = html_escape(c) {
self.html.extend_from_slice(escape);
} else {
self.html.push(c);
@ -1161,7 +1182,7 @@ fn injection_for_match<'a>(
// that sets the injection.language key.
"injection.language" => {
if language_name.is_none() {
language_name = prop.value.as_ref().map(|s| s.as_ref());
language_name = prop.value.as_ref().map(std::convert::AsRef::as_ref);
}
}

View file

@ -1,10 +0,0 @@
pub fn html_escape(c: u8) -> Option<&'static [u8]> {
match c as char {
'>' => Some(b"&gt;"),
'<' => Some(b"&lt;"),
'&' => Some(b"&amp;"),
'\'' => Some(b"&#39;"),
'"' => Some(b"&quot;"),
_ => None,
}
}