Skip to content

Commit e0311c0

Browse files
authored
Merge pull request #89 from sminez/issue-76
Fix: multiple tree-sitter highlighting bugs
2 parents af99247 + c0b94b3 commit e0311c0

File tree

15 files changed

+414
-109
lines changed

15 files changed

+414
-109
lines changed

Cargo.lock

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,5 @@ toml = "0.8.19"
5454
[dev-dependencies]
5555
simple_test_case = "1.2.0"
5656
criterion = "0.5"
57+
tree-sitter-python = "0.23.6"
58+
tree-sitter-rust = "0.23.2"

data/config.toml

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ function = { fg = "#957FB8" }
7272
keyword = { fg = "#Bf616A" }
7373
module = { fg = "#2D4F67" }
7474
number = { fg = "#D27E99" }
75+
operator = { fg = "#E6C384" }
7576
punctuation = { fg = "#9CABCA" }
7677
string = { fg = "#61DCA5" }
7778
type = { fg = "#7E9CD8" }

data/tree-sitter/queries/dart/highlights.scm

-1
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,3 @@
210210
"?."
211211
"?"
212212
] @punctuation.delimiter
213-

data/tree-sitter/queries/proto/highlights.scm

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757

5858
(comment) @comment
5959

60+
((comment) @comment.documentation
61+
(#match? @comment.documentation "^/[*][*][^*].*[*]/$"))
62+
6063
[
6164
"("
6265
")"

data/tree-sitter/queries/rust/highlights.scm

+60-38
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
(shebang) @keyword.directive
2+
13
(function_item (identifier) @function)
24
(function_signature_item (identifier) @function)
35
(macro_invocation
@@ -6,6 +8,10 @@
68

79
(identifier) @variable
810

11+
; Assume all-caps names are constants
12+
((identifier) @constant
13+
(#match? @constant "^[A-Z][A-Z%d_]*$"))
14+
915
(const_item
1016
name: (identifier) @constant)
1117
(type_identifier) @type
@@ -18,10 +24,19 @@
1824
name: (identifier) @module)
1925
(self) @keyword.builtin
2026

21-
"_" @character.special
27+
[
28+
(line_comment)
29+
(block_comment)
30+
(outer_doc_comment_marker)
31+
(inner_doc_comment_marker)
32+
] @comment @spell
33+
34+
(line_comment
35+
(doc_comment)) @comment.documentation
36+
37+
(block_comment
38+
(doc_comment)) @comment.documentation
2239

23-
(line_comment) @comment
24-
(block_comment) @comment
2540

2641
(boolean_literal) @boolean
2742
(integer_literal) @number
@@ -32,6 +47,14 @@
3247
(string_literal) @string
3348
(raw_string_literal) @string
3449

50+
(use_wildcard
51+
"*" @character.special)
52+
53+
(remaining_field_pattern
54+
".." @character.special)
55+
56+
"_" @character.special
57+
3558
; Keywords
3659
[
3760
"use"
@@ -111,30 +134,6 @@
111134
(closure_parameters
112135
"|" @punctuation.bracket)
113136

114-
(type_arguments
115-
[
116-
"<"
117-
">"
118-
] @punctuation.bracket)
119-
120-
(type_parameters
121-
[
122-
"<"
123-
">"
124-
] @punctuation.bracket)
125-
126-
(bracketed_type
127-
[
128-
"<"
129-
">"
130-
] @punctuation.bracket)
131-
132-
(for_lifetimes
133-
[
134-
"<"
135-
">"
136-
] @punctuation.bracket)
137-
138137
[
139138
","
140139
"."
@@ -185,17 +184,40 @@
185184
"||"
186185
] @operator
187186

188-
(use_wildcard
189-
"*" @character.special)
187+
(type_arguments
188+
[
189+
"<"
190+
">"
191+
] @punctuation.bracket)
190192

191-
(remaining_field_pattern
192-
".." @character.special)
193+
(type_parameters
194+
[
195+
"<"
196+
">"
197+
] @punctuation.bracket)
198+
199+
(bracketed_type
200+
[
201+
"<"
202+
">"
203+
] @punctuation.bracket)
204+
205+
(for_lifetimes
206+
[
207+
"<"
208+
">"
209+
] @punctuation.bracket)
210+
211+
212+
(attribute_item
213+
"#" @punctuation.special)
214+
215+
(inner_attribute_item
216+
[
217+
"!"
218+
"#"
219+
] @punctuation.special)
193220

194-
; (attribute_item
195-
; "#" @punctuation.special)
196221

197-
; (inner_attribute_item
198-
; [
199-
; "!"
200-
; "#"
201-
; ] @punctuation.special)
222+
((identifier) @constant.builtin
223+
(#any-of? @constant.builtin "Some" "None" "Ok" "Err"))

data/tree-sitter/queries/yaml/highlights.scm

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
(boolean_scalar) @boolean
2+
(null_scalar) @constant.builtin
3+
(double_quote_scalar) @string
4+
(single_quote_scalar) @string
5+
6+
((block_scalar) @string
7+
(#set! priority 99))
8+
9+
(string_scalar) @string
10+
(escape_sequence) @string.escape
11+
(integer_scalar) @number
12+
(float_scalar) @number
13+
(comment) @comment
14+
115
[
216
(anchor_name)
317
(alias_name)
@@ -59,18 +73,3 @@
5973
"---"
6074
"..."
6175
] @punctuation.special
62-
63-
(boolean_scalar) @boolean
64-
(null_scalar) @constant.builtin
65-
(double_quote_scalar) @string
66-
(single_quote_scalar) @string
67-
68-
((block_scalar) @string
69-
(#set! priority 99))
70-
71-
(string_scalar) @string
72-
(escape_sequence) @string.escape
73-
(integer_scalar) @number
74-
(float_scalar) @number
75-
(comment) @comment @spell
76-

docs/tree-sitter-queries.md

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Writing tree-sitter queries for ad
2+
3+
### Overview
4+
5+
`ad` currently supports a subset of the tree-sitter based syntax highlighting you may be familiar
6+
with from other text editors. The configuration options in your `config.toml` under the `tree_sitter`
7+
key will direct `ad` to search for scheme highlights files under a given directory for the languages
8+
that you configure. These query files can, for the most part, be copied from other editors but there
9+
are a couple of caveats that you should keep in mind.
10+
11+
1. Support for custom predicates (such as neovim's `#lua-match?` and `#contains?` is not provided.
12+
Queries using unsupported predicates will be rejected, resulting in tree-sitter not being enabled
13+
for the language in question.
14+
2. ad follows the same precedence approach as neovim for overlapping queries, with the _last_ match
15+
being used in place of previous matches. When writing your `highlights.scm` file you should place
16+
more specific rules towards the end of the file and more general rules towards the start.
17+
3. ad does not currently provide any support for indentation, injections, locals or folds. So the
18+
resulting highlights you obtain may not exactly match what you are used to from another editor if
19+
you are copying over existing queries.
20+
21+
22+
### Getting started
23+
24+
ad provides some support for tree-sitter parsers that I have been able to test and verify as part of my
25+
local setup. For the most part they are adapted from the ones found in [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter/tree/master/queries)
26+
with the the modigications outlined below. If you are testing your own queries it is often better to start
27+
with a subset of the `highlights.scm` file from another editor and incrementally add in more queries
28+
while verifying that the results in ad look the way that you expect.
29+
30+
Beyond that simple advice, the tree-sitter documentation on writing queries is the best place to start
31+
if you are looking to configure your own custom queries:
32+
https://tree-sitter.github.io/tree-sitter/using-parsers/queries/index.html
33+
34+
35+
### Troubleshooting
36+
37+
- **Where are my highlights that I configured?**
38+
- First make sure that you don't have any typos in your config (we all do it) and that the highlighting
39+
provided in the ad repo is working correctly.
40+
- If you are sure that you have things set up correctly then try running `:view-logs` to see if there
41+
are any warnings about the queries that you are using. You should see a log line asserting that the
42+
tree-sitter parser has been initialised, and if not there should be an error message explaining why
43+
setup failed.
44+
45+
- **What is this warning about unsupported predicates?**
46+
- A common feature of tree-sitter queries is the use of [predicates](https://tree-sitter.github.io/tree-sitter/using-parsers/queries/3-predicates-and-directives.html)
47+
to conditionally select nodes in the tree based on their content as well as their type. Tree-sitter
48+
supports providing and running custom predicates but it is up to the program running the query to
49+
provide the implementation of how custom predicates are applied. `neovim` and other editors tend to
50+
make extensive use of custom predicates that are not supported inside of ad. If a query you are
51+
using contains any unsupported predicates it will be rejected with warning logs listing the predicates
52+
that were found.
53+
- Typically, you can replace `#lua-match?` with the tree-sitter built-in `#match?` predicate and have
54+
it produce the expected result.
55+
- You can also replace `#contains?` with `#match? .. ".*$contained_string.*"`
56+
57+
- **Why are comments not rendering with the correct styling?**
58+
- Comment queries from neovim frequently have a secondary `@spell` tag associated with them that ad
59+
will end up using as the tag for the match (in place of, for example, `@comment`). If you remove
60+
the `@spell` tag from your query you should see your comments receive the correct highlighting.

src/buffer/internal.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ impl GapBuffer {
414414
}
415415

416416
/// Convert a byte index to a character index
417-
pub fn byte_to_char(&self, byte_idx: usize) -> usize {
417+
pub fn raw_byte_to_char(&self, byte_idx: usize) -> usize {
418418
self.chars_in_raw_range(0, byte_idx)
419419
}
420420

@@ -739,7 +739,7 @@ impl GapBuffer {
739739
}
740740

741741
#[inline]
742-
fn byte_to_raw_byte(&self, byte: usize) -> usize {
742+
pub fn byte_to_raw_byte(&self, byte: usize) -> usize {
743743
if byte > self.gap_start {
744744
byte + self.gap()
745745
} else {

src/buffer/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,10 @@ impl Buffer {
410410
s
411411
}
412412

413+
pub(crate) fn pretty_print_ts_tree(&self) -> Option<String> {
414+
self.ts_state.as_ref().map(|ts| ts.pretty_print_tree())
415+
}
416+
413417
pub(crate) fn string_lines(&self) -> Vec<String> {
414418
self.txt
415419
.iter_lines()

src/editor/actions.rs

+8
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ pub enum Action {
118118
ShellRun { cmd: String },
119119
ShellSend { cmd: String },
120120
ShowHelp,
121+
TsShowTree,
121122
Undo,
122123
UpdateConfig { input: String },
123124
ViewLogs,
@@ -495,6 +496,13 @@ where
495496
.open_virtual("+logs", self.log_buffer.content(), false)
496497
}
497498

499+
pub(super) fn show_active_ts_tree(&mut self) {
500+
match self.layout.active_buffer().pretty_print_ts_tree() {
501+
Some(s) => self.layout.open_virtual("+ts-tree", s, false),
502+
None => self.set_status_message("no tree-sitter tree for current buffer"),
503+
}
504+
}
505+
498506
pub(super) fn show_help(&mut self) {
499507
self.layout.open_virtual("+help", gen_help_docs(), false)
500508
}

src/editor/commands.rs

+2
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ fn parse_command(input: &str, active_buffer_id: usize, cwd: &Path) -> Result<Act
138138
input: input.to_string(),
139139
})),
140140

141+
"ts-show-tree" => Ok(Single(TsShowTree)),
142+
141143
"view-logs" => Ok(Single(ViewLogs)),
142144

143145
"w" | "write" => {

src/editor/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ where
492492
ShellReplace { cmd } => self.replace_dot_with_shell_cmd(&cmd),
493493
ShellRun { cmd } => self.run_shell_cmd(&cmd),
494494
ShowHelp => self.show_help(),
495+
TsShowTree => self.show_active_ts_tree(),
495496
UpdateConfig { input } => self.update_config(&input),
496497
ViewLogs => self.view_logs(),
497498
Yank => self.set_clipboard(self.layout.active_buffer().dot_contents()),

src/lsp/capabilities.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl PositionEncoding {
8686
Self::Utf8 => {
8787
let line_start = b.txt.line_to_char(pos.line as usize);
8888
let byte_idx = b.txt.char_to_byte(line_start + pos.character as usize);
89-
let col = b.txt.byte_to_char(byte_idx);
89+
let col = b.txt.raw_byte_to_char(byte_idx);
9090

9191
(pos.line as usize, col)
9292
}

0 commit comments

Comments
 (0)