|
2 | 2 |
|
3 | 3 | import * as vscode from "vscode";
|
4 | 4 | import {YaraCompletionItemProvider} from "./completionProvider";
|
| 5 | +import {YaraDefinitionProvider} from "./definitionProvider"; |
| 6 | +import {YaraReferenceProvider} from "./referenceProvider"; |
5 | 7 |
|
6 | 8 |
|
7 |
| -// variables have a few possible first characters - use these to identify vars vs. rules |
8 |
| -const varFirstChar: Set<string> = new Set(["$", "#", "@", "!"]); |
9 |
| - |
10 |
| -/* |
11 |
| - Get the start and end boundaries for the current YARA rule based on a symbol's position |
12 |
| -*/ |
13 |
| -function GetRuleRange(lines: string[], symbol: vscode.Position) { |
14 |
| - let begin: vscode.Position | null = null; |
15 |
| - let end: vscode.Position | null = null; |
16 |
| - const startRuleRegexp = RegExp("^rule "); |
17 |
| - const endRuleRegexp = RegExp("^\}"); |
18 |
| - // find the nearest reference to "rule" by traversing the lines in reverse order |
19 |
| - for (let lineNo = symbol.line; lineNo >= 0; lineNo--) { |
20 |
| - if (startRuleRegexp.test(lines[lineNo])) { |
21 |
| - begin = new vscode.Position(lineNo, 0); |
22 |
| - break; |
23 |
| - } |
24 |
| - } |
25 |
| - // start up this loop again using the beginning of the rule |
26 |
| - // and find the line with just a curly brace to identify the end of a rule |
27 |
| - for (let lineNo = begin.line; lineNo < lines.length; lineNo++) { |
28 |
| - if (endRuleRegexp.test(lines[lineNo])) { |
29 |
| - end = new vscode.Position(lineNo, 0); |
30 |
| - break; |
31 |
| - } |
32 |
| - } |
33 |
| - return new vscode.Range(begin, end); |
34 |
| -} |
35 |
| - |
36 |
| -export class YaraDefinitionProvider implements vscode.DefinitionProvider { |
37 |
| - public provideDefinition(doc: vscode.TextDocument, pos: vscode.Position, token: vscode.CancellationToken): Thenable<vscode.Location> { |
38 |
| - return new Promise((resolve, reject) => { |
39 |
| - let definition: vscode.Location | null = null; |
40 |
| - const fileUri: vscode.Uri = vscode.Uri.file(doc.fileName); |
41 |
| - const range: vscode.Range = doc.getWordRangeAtPosition(pos); |
42 |
| - const symbol: string = doc.getText(range); |
43 |
| - // console.log(`Providing definition for symbol '${symbol}'`); |
44 |
| - let possibleVarStart: vscode.Position = new vscode.Position(range.start.line, range.start.character - 1); |
45 |
| - let possibleVarRange: vscode.Range = new vscode.Range(possibleVarStart, range.end); |
46 |
| - let possibleVar: string = doc.getText(possibleVarRange); |
47 |
| - const lines: string[] = doc.getText().split("\n"); |
48 |
| - if (varFirstChar.has(possibleVar.charAt(0))) { |
49 |
| - // console.log(`Variable detected: ${possibleVar}`); |
50 |
| - let currentRuleRange: vscode.Range = GetRuleRange(lines, pos); |
51 |
| - // console.log(`Curr rule range: ${currentRuleRange.start.line+1} -> ${currentRuleRange.end.line+1}`); |
52 |
| - for (let lineNo = currentRuleRange.start.line; lineNo < currentRuleRange.end.line; lineNo++) { |
53 |
| - let character: number = lines[lineNo].indexOf(`$${symbol} =`); |
54 |
| - if (character != -1) { |
55 |
| - // console.log(`Found defintion of '${possibleVar}' on line ${lineNo + 1} at character ${character + 1}`); |
56 |
| - // gotta add one because VSCode won't recognize the '$' as part of the symbol |
57 |
| - let defPosition: vscode.Position = new vscode.Position(lineNo, character + 1); |
58 |
| - definition = new vscode.Location(fileUri, defPosition); |
59 |
| - break; |
60 |
| - } |
61 |
| - } |
62 |
| - } |
63 |
| - else { |
64 |
| - for (let lineNo = 0; lineNo < pos.line; lineNo++) { |
65 |
| - let character: number = lines[lineNo].indexOf(symbol); |
66 |
| - if (character != -1 && lines[lineNo].startsWith("rule")) { |
67 |
| - // console.log(`Found ${symbol} on line ${lineNo} at character ${character}`); |
68 |
| - let defPosition: vscode.Position = new vscode.Position(lineNo, character); |
69 |
| - definition = new vscode.Location(fileUri, defPosition); |
70 |
| - break; |
71 |
| - } |
72 |
| - } |
73 |
| - } |
74 |
| - if (definition != null) { |
75 |
| - resolve(definition); |
76 |
| - } |
77 |
| - else { |
78 |
| - reject(); |
79 |
| - } |
80 |
| - }); |
81 |
| - } |
82 |
| -} |
83 |
| - |
84 |
| -export class YaraReferenceProvider implements vscode.ReferenceProvider { |
85 |
| - public provideReferences(doc: vscode.TextDocument, pos: vscode.Position, options: { includeDeclaration: boolean }, token: vscode.CancellationToken): Thenable<vscode.Location[]> { |
86 |
| - return new Promise((resolve, reject) => { |
87 |
| - const fileUri: vscode.Uri = vscode.Uri.file(doc.fileName); |
88 |
| - const range: vscode.Range = doc.getWordRangeAtPosition(pos); |
89 |
| - let lines: string[] = doc.getText().split("\n"); |
90 |
| - let references: vscode.Location[] = new Array<vscode.Location>(); |
91 |
| - let symbol: string = doc.getText(range); |
92 |
| - // console.log(`Providing references for symbol '${symbol}'`); |
93 |
| - let possibleVarStart: vscode.Position = new vscode.Position(range.start.line, range.start.character - 1); |
94 |
| - let possibleVarRange: vscode.Range = new vscode.Range(possibleVarStart, range.end); |
95 |
| - let possibleVar: string = doc.getText(possibleVarRange); |
96 |
| - if (varFirstChar.has(possibleVar.charAt(0))) { |
97 |
| - let varRegexp: string; |
98 |
| - let startLine: number; |
99 |
| - let endLine: number; |
100 |
| - // console.log(`Identified symbol as a variable: ${symbol}`); |
101 |
| - let possibleWildcardEnd: vscode.Position = new vscode.Position(range.end.line, range.end.character + 1); |
102 |
| - let possibleWildcardRange: vscode.Range = new vscode.Range(possibleVarStart, possibleWildcardEnd); |
103 |
| - let possibleWildcard: string = doc.getText(possibleWildcardRange); |
104 |
| - if (possibleWildcard.slice(-1) == "*") { |
105 |
| - // treat like a wildcard and search only the local rule |
106 |
| - varRegexp = `[\$#@!]${symbol}[a-zA-Z0-9_]+`; |
107 |
| - let ruleRange = GetRuleRange(lines, pos); |
108 |
| - startLine = ruleRange.start.line; |
109 |
| - endLine = ruleRange.end.line; |
110 |
| - } |
111 |
| - else { |
112 |
| - // treat like a normal variable reference and search the whole document |
113 |
| - varRegexp = `[\$#@!]${symbol}[^a-zA-Z0-9_]`; |
114 |
| - startLine = 0; |
115 |
| - endLine = lines.length; |
116 |
| - } |
117 |
| - for (let lineNo = startLine; lineNo < endLine; lineNo++) { |
118 |
| - let character: number = lines[lineNo].search(varRegexp); |
119 |
| - if (character != -1) { |
120 |
| - // console.log(`Found ${symbol} on line ${lineNo} at character ${character}`); |
121 |
| - // have to readjust the character index |
122 |
| - let refPosition: vscode.Position = new vscode.Position(lineNo, character + 1); |
123 |
| - references.push(new vscode.Location(fileUri, refPosition)); |
124 |
| - } |
125 |
| - |
126 |
| - } |
127 |
| - } |
128 |
| - else { |
129 |
| - let lineNo = 0; |
130 |
| - lines.forEach(line => { |
131 |
| - let character: number = line.indexOf(symbol); |
132 |
| - if (character != -1) { |
133 |
| - // console.log(`Found ${symbol} on line ${lineNo} at character ${character}`); |
134 |
| - let refPosition: vscode.Position = new vscode.Position(lineNo, character); |
135 |
| - references.push(new vscode.Location(fileUri, refPosition)); |
136 |
| - } |
137 |
| - lineNo++; |
138 |
| - }); |
139 |
| - } |
140 |
| - if (references != null) { |
141 |
| - resolve(references); |
142 |
| - } |
143 |
| - else { |
144 |
| - reject(); |
145 |
| - } |
146 |
| - }); |
147 |
| - } |
148 |
| -} |
149 |
| - |
150 | 9 | export function activate(context: vscode.ExtensionContext) {
|
151 | 10 | // console.log("Activating Yara extension");
|
152 | 11 | let YARA: vscode.DocumentSelector = { language: "yara", scheme: "file" };
|
|
0 commit comments