chore(highlight): apply clippy fixes
This commit is contained in:
parent
28bb2a8c1c
commit
f32fa784be
4 changed files with 89 additions and 72 deletions
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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">"),
|
||||
'<' => Some(b"<"),
|
||||
'&' => Some(b"&"),
|
||||
'\'' => Some(b"'"),
|
||||
'"' => Some(b"""),
|
||||
_ => 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
pub fn html_escape(c: u8) -> Option<&'static [u8]> {
|
||||
match c as char {
|
||||
'>' => Some(b">"),
|
||||
'<' => Some(b"<"),
|
||||
'&' => Some(b"&"),
|
||||
'\'' => Some(b"'"),
|
||||
'"' => Some(b"""),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue