|
1 | 1 | import * as vscode from 'vscode'; |
2 | | -import { getTrees, toPoint, toRange } from "../TreeSitter"; |
3 | | - |
| 2 | +import { getTrees, queryNode, toPoint, toRange, trees } from "../TreeSitter"; |
| 3 | +import { Point } from 'web-tree-sitter'; |
4 | 4 |
|
5 | 5 | export const HoverProvider: vscode.HoverProvider = { |
6 | 6 | provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.Hover { |
7 | 7 | // vscode.window.showInformationMessage(JSON.stringify("Hover")); |
8 | 8 | const trees = getTrees(document); |
9 | | - const jsonTree = trees.jsonTree; |
10 | 9 | const point = toPoint(position); |
11 | | - const node = jsonTree.rootNode.descendantForPosition(point); |
12 | | - // const node = jsonTree.rootNode.namedDescendantForPosition(point); |
13 | | - if (node == null) { |
14 | | - return; |
15 | | - } |
16 | 10 |
|
17 | | - if (node.type == 'regex') { |
18 | | - const regexTrees = getTrees(document).regexTrees; |
19 | | - const regexTree = regexTrees.get(node.id); |
20 | | - const regexNode = regexTree.rootNode.descendantForPosition(point); |
21 | | - const parentNode = regexNode.parent; |
22 | | - const markdownString = new vscode.MarkdownString(); |
23 | | - markdownString.appendText(parentNode.type + ' => ' + regexNode.type); |
24 | | - markdownString.appendCodeblock(parentNode.text, 'json-textmate-regex'); |
25 | | - markdownString.appendCodeblock(parentNode.toString(), 'scm'); |
26 | | - |
27 | | - const range = toRange(parentNode); |
28 | | - const hover = new vscode.Hover(markdownString, range); |
29 | | - // vscode.window.showInformationMessage(JSON.stringify(hover)); |
30 | | - return hover; |
| 11 | + // return debugTreeSitterHovers(trees, point); |
| 12 | + |
| 13 | + const rootNode = trees.jsonTree.rootNode; |
| 14 | + const hoverQuery = `;scm |
| 15 | + (match (key) @match) |
| 16 | + (begin (key) @begin) |
| 17 | + (end (key) @end) |
| 18 | + (while (key) @while) |
| 19 | + `; |
| 20 | + const hoverCapture = queryNode(rootNode, hoverQuery, point); |
| 21 | + const hoverNode = hoverCapture.node; |
| 22 | + |
| 23 | + const markdownString = new vscode.MarkdownString(); |
| 24 | + switch (hoverCapture.name) { |
| 25 | + case 'match': |
| 26 | + markdownString.appendMarkdown('Regular Expression to match, (capture) and apply `scopeNames` to text \n'); |
| 27 | + markdownString.appendMarkdown('TextMate uses the [Oniguruma](https://github.com/kkos/oniguruma/blob/master/doc/RE) regex dialect \n'); |
| 28 | + markdownString.appendCodeblock('Example: \\\\b(true|false)\\\\b', 'json-textmate-regex'); |
| 29 | + break; |
| 30 | + case 'begin': |
| 31 | + markdownString.appendMarkdown('Regular Expression just like `"match"` \n'); |
| 32 | + markdownString.appendMarkdown('Starts a region that _can_ span multiple lines. When used in conjunction with a `"end"`/`"while"` key \n'); |
| 33 | + markdownString.appendMarkdown('Rules can be nested inside the block with the `"patterns"` key \n'); |
| 34 | + markdownString.appendMarkdown('An anchor is placed after the `"begin"` rule; that you can then match with `\\\\G` \n'); |
| 35 | + markdownString.appendMarkdown('**\\*WARNING\\*** If `"begin"` matches the newline `\\n`. The `\\\\G` anchor is then placed at the beginning of the _next_ line \n'); |
| 36 | + markdownString.appendCodeblock('Example: (\\\\s*)(#*)(\\")', 'json-textmate-regex'); |
| 37 | + break; |
| 38 | + case 'end': |
| 39 | + markdownString.appendMarkdown('Regular Expression just like `"match"` \n'); |
| 40 | + markdownString.appendMarkdown('Ends the block started by `"begin"` \n'); |
| 41 | + markdownString.appendMarkdown('`"end"` has priority over rules inside the `"patterns"` array \n'); |
| 42 | + markdownString.appendMarkdown('**\\*WARNING\\*** Rules inside `"patterns"` can \'overmatch\' the `"end"` rule. Effectively \'pushing\' it out \n'); |
| 43 | + markdownString.appendMarkdown('(Captures) inside the `"begin"` key can be referenced here with regex back-references `\\\\1` \n'); |
| 44 | + markdownString.appendCodeblock('Example: (\\")(\\\\2)', 'json-textmate-regex'); |
| 45 | + break; |
| 46 | + case 'while': |
| 47 | + markdownString.appendMarkdown('Regular Expression just like `"match"` \n'); |
| 48 | + markdownString.appendMarkdown('Continues the block started by `"begin"` \n'); |
| 49 | + markdownString.appendMarkdown('**\\*WARNING\\*** [VSCode\'s TextMate Engine](https://github.com/microsoft/vscode-textmate) implements `"while"` slightly [differently](https://github.com/microsoft/vscode-textmate/issues/241) to how [Apple\'s TextMate 2.0 Application](https://macromates.com/) has \n'); |
| 50 | + markdownString.appendMarkdown('Unlike `"end"`, `"while"` is line-based, not character-based. It is only checked once per line (starting on the line after the `"begin"`) \n'); |
| 51 | + markdownString.appendMarkdown('If it matches then the _rest_ of the line is now part of the block (same also applies to the `"begin"` rule) \n'); |
| 52 | + markdownString.appendMarkdown('Rules can be nested inside the block with the `"patterns"` key \n'); |
| 53 | + markdownString.appendMarkdown('VSCode: `"while"` is always tested first, before any inner `"patterns"`. \n'); |
| 54 | + markdownString.appendMarkdown('VSCode: When `"while"` doesn\'t match, all unfinished/unclosed patterns are terminated and the `"begin"`/`"while"` block is then finished/closed \n'); |
| 55 | + markdownString.appendMarkdown('Apple: `"begin"`&`"end"` rules \'push\' the `"while"` rule to the next line \n'); |
| 56 | + markdownString.appendMarkdown('An anchor is placed after the `"begin"` rule; that you can then match with `\\\\G` \n'); |
| 57 | + markdownString.appendMarkdown('Apple: A `\\\G` anchor is also placed at the beginning of the _next_ line \n'); |
| 58 | + markdownString.appendMarkdown('(Captures) inside the `"begin"` key can be referenced here with regex back-references `\\\\1` \n'); |
| 59 | + markdownString.appendCodeblock('Example: ^\\\\1(?!\\\\s*\\")', 'json-textmate-regex'); |
| 60 | + break; |
31 | 61 | } |
32 | | - else { |
33 | | - const markdownString = new vscode.MarkdownString(); |
34 | | - markdownString.appendCodeblock(node.text, 'json-textmate'); |
35 | | - // const fieldName = node.walk().currentFieldName(); |
36 | | - // if (fieldName) |
37 | | - // markdownString.appendText(fieldName + ':'); |
38 | | - if (node.parent) |
39 | | - markdownString.appendText(node.parent.type + ' => '); |
40 | | - markdownString.appendText(node.type); |
41 | | - markdownString.appendCodeblock(node.toString(), 'scm'); |
42 | | - |
43 | | - const range = toRange(node); |
44 | | - const hover = new vscode.Hover(markdownString, range); |
45 | | - // vscode.window.showInformationMessage(JSON.stringify(hover)); |
46 | | - return hover; |
| 62 | + |
| 63 | + const range = toRange(hoverNode); |
| 64 | + const hover = new vscode.Hover(markdownString, range); |
| 65 | + // vscode.window.showInformationMessage(`hover\n${JSON.stringify(hover)}`); |
| 66 | + return hover; |
| 67 | + } |
| 68 | +}; |
| 69 | + |
| 70 | +function debugTreeSitterHovers(trees: trees, point: Point): vscode.Hover { |
| 71 | + const node = trees.jsonTree.rootNode.descendantForPosition(point); |
| 72 | + // const node = jsonTree.rootNode.namedDescendantForPosition(point); |
| 73 | + |
| 74 | + if (node == null) { |
| 75 | + return; |
| 76 | + } |
| 77 | + |
| 78 | + if (node.type == 'regex') { |
| 79 | + const regexTrees = trees.regexTrees; |
| 80 | + const regexTree = regexTrees.get(node.id); |
| 81 | + const regexNode = regexTree.rootNode.descendantForPosition(point); |
| 82 | + const parentNode = regexNode.parent; |
| 83 | + const markdownString = new vscode.MarkdownString(); |
| 84 | + markdownString.appendText(parentNode.type + ' => ' + regexNode.type); |
| 85 | + markdownString.appendCodeblock(parentNode.text, 'json-textmate-regex'); |
| 86 | + markdownString.appendCodeblock(parentNode.toString(), 'scm'); |
| 87 | + |
| 88 | + const range = toRange(parentNode); |
| 89 | + const hover = new vscode.Hover(markdownString, range); |
| 90 | + // vscode.window.showInformationMessage(`debugRegexHover\n${JSON.stringify(hover)}`); |
| 91 | + return hover; |
| 92 | + } |
| 93 | + else { |
| 94 | + const markdownString = new vscode.MarkdownString(); |
| 95 | + markdownString.appendCodeblock(node.text, 'json-textmate'); |
| 96 | + // const fieldName = node.walk().currentFieldName(); |
| 97 | + // if (fieldName) { |
| 98 | + // markdownString.appendText(`${fieldName}:`); |
| 99 | + // } |
| 100 | + if (node.parent) { |
| 101 | + markdownString.appendText(node.parent.type + ' => '); |
47 | 102 | } |
| 103 | + markdownString.appendText(node.type); |
| 104 | + markdownString.appendCodeblock(node.toString(), 'scm'); |
| 105 | + |
| 106 | + const range = toRange(node); |
| 107 | + const hover = new vscode.Hover(markdownString, range); |
| 108 | + // vscode.window.showInformationMessage(`debugHover\n${JSON.stringify(hover)}`); |
| 109 | + return hover; |
48 | 110 | } |
49 | 111 | } |
0 commit comments