3
3
import * as vscode from "vscode" ;
4
4
5
5
6
+ // variables have a few possible first characters - use these to identify vars vs. rules
7
+ const varFirstChar = new Set ( [ "$" , "#" , "@" , "!" ] ) ;
8
+
9
+ /*
10
+ Get the start and end boundaries for the current YARA rule based on a symbol's position
11
+ */
12
+ function GetRuleRange ( lines : string [ ] , symbol : vscode . Position ) {
13
+ let begin : vscode . Position = null ;
14
+ let end : vscode . Position = null ;
15
+ const startRuleRegexp = RegExp ( "^rule " ) ;
16
+ const endRuleRegexp = RegExp ( "^\}" ) ;
17
+ // only go up to the symbol's line because the rule must be defined before the symbol
18
+ for ( let lineNo = 0 ; lineNo < symbol . line ; lineNo ++ ) {
19
+ if ( startRuleRegexp . test ( lines [ lineNo ] ) ) {
20
+ begin = new vscode . Position ( lineNo , 0 ) ;
21
+ }
22
+ }
23
+ // start up this loop again using the beginning of the rule
24
+ // and find the line with just a curly brace to identify the end of a rule
25
+ for ( let lineNo = begin . line ; lineNo < lines . length ; lineNo ++ ) {
26
+ if ( endRuleRegexp . test ( lines [ lineNo ] ) ) {
27
+ end = new vscode . Position ( lineNo , 0 ) ;
28
+ break ;
29
+ }
30
+ }
31
+ return new vscode . Range ( begin , end ) ;
32
+ }
33
+
6
34
export class YaraDefinitionProvider implements vscode . DefinitionProvider {
7
35
public provideDefinition ( doc : vscode . TextDocument , pos : vscode . Position , token : vscode . CancellationToken ) : Thenable < vscode . Location > {
8
36
return new Promise ( ( resolve , reject ) => {
@@ -11,21 +39,36 @@ export class YaraDefinitionProvider implements vscode.DefinitionProvider {
11
39
const range : vscode . Range = doc . getWordRangeAtPosition ( pos ) ;
12
40
const symbol : string = doc . getText ( range ) ;
13
41
// console.log(`Providing definition for symbol '${symbol}'`);
14
- let lines : string [ ] = doc . getText ( ) . split ( "\n" ) ;
15
- let lineNo = 0 ;
16
- lines . forEach ( line => {
17
- let character : number = line . indexOf ( symbol ) ;
18
- // line numbers are offset by one in output - need to adjust
19
- // only supporting definitions for rules
20
- if ( character != - 1 && ( lineNo + 1 ) != pos . line && line . startsWith ( "rule" ) ) {
21
- // console.log(`Found ${symbol} on line ${lineNo} at character ${character}`);
22
- let defPosition : vscode . Position = new vscode . Position ( lineNo , character ) ;
23
- definition = new vscode . Location ( fileUri , defPosition ) ;
24
- // Definition found. Break out of forEach
25
- return ;
42
+ let possibleVarStart : vscode . Position = new vscode . Position ( range . start . line , range . start . character - 1 ) ;
43
+ let possibleVarRange : vscode . Range = new vscode . Range ( possibleVarStart , range . end ) ;
44
+ let possibleVar : string = doc . getText ( possibleVarRange ) ;
45
+ const lines : string [ ] = doc . getText ( ) . split ( "\n" ) ;
46
+ if ( varFirstChar . has ( possibleVar . charAt ( 0 ) ) ) {
47
+ // console.log(`Variable detected: ${possibleVar}`);
48
+ let currentRuleRange : vscode . Range = GetRuleRange ( lines , pos ) ;
49
+ // console.log(`Curr rule range: ${currentRuleRange.start.line+1} -> ${currentRuleRange.end.line+1}`);
50
+ for ( let lineNo = currentRuleRange . start . line ; lineNo < currentRuleRange . end . line ; lineNo ++ ) {
51
+ let character : number = lines [ lineNo ] . indexOf ( `$${ symbol } =` ) ;
52
+ if ( character != - 1 ) {
53
+ // console.log(`Found defintion of '${possibleVar}' on line ${lineNo + 1} at character ${character + 1}`);
54
+ // gotta add one because VSCode won't recognize the '$' as part of the symbol
55
+ let defPosition : vscode . Position = new vscode . Position ( lineNo , character + 1 ) ;
56
+ definition = new vscode . Location ( fileUri , defPosition ) ;
57
+ break ;
58
+ }
59
+ }
60
+ }
61
+ else {
62
+ for ( let lineNo = 0 ; lineNo < pos . line ; lineNo ++ ) {
63
+ let character : number = lines [ lineNo ] . indexOf ( symbol ) ;
64
+ if ( character != - 1 && lines [ lineNo ] . startsWith ( "rule" ) ) {
65
+ // console.log(`Found ${symbol} on line ${lineNo} at character ${character}`);
66
+ let defPosition : vscode . Position = new vscode . Position ( lineNo , character ) ;
67
+ definition = new vscode . Location ( fileUri , defPosition ) ;
68
+ break ;
69
+ }
26
70
}
27
- lineNo ++ ;
28
- } ) ;
71
+ }
29
72
if ( definition != null ) {
30
73
resolve ( definition ) ;
31
74
}
@@ -39,14 +82,13 @@ export class YaraDefinitionProvider implements vscode.DefinitionProvider {
39
82
export class YaraReferenceProvider implements vscode . ReferenceProvider {
40
83
public provideReferences ( doc : vscode . TextDocument , pos : vscode . Position , options : { includeDeclaration : boolean } , token : vscode . CancellationToken ) : Thenable < vscode . Location [ ] > {
41
84
return new Promise ( ( resolve , reject ) => {
42
- const varFirstChar = new Set ( [ "$" , "#" , "@" , "!" ] ) ;
43
85
const fileUri : vscode . Uri = vscode . Uri . file ( doc . fileName ) ;
44
86
const range : vscode . Range = doc . getWordRangeAtPosition ( pos ) ;
45
87
let lines : string [ ] = doc . getText ( ) . split ( "\n" ) ;
46
88
let references : vscode . Location [ ] = new Array < vscode . Location > ( ) ;
47
89
let symbol : string = doc . getText ( range ) ;
48
90
// console.log(`Providing references for symbol '${symbol}'`);
49
- let possibleVarStart : vscode . Position = new vscode . Position ( range . start . line , range . start . character - 1 ) ;
91
+ let possibleVarStart : vscode . Position = new vscode . Position ( range . start . line , range . start . character - 1 ) ;
50
92
let possibleVarRange : vscode . Range = new vscode . Range ( possibleVarStart , range . end ) ;
51
93
let possibleVar : string = doc . getText ( possibleVarRange ) ;
52
94
if ( varFirstChar . has ( possibleVar . charAt ( 0 ) ) ) {
@@ -57,7 +99,7 @@ export class YaraReferenceProvider implements vscode.ReferenceProvider {
57
99
if ( character != - 1 ) {
58
100
// console.log(`Found ${symbol} on line ${lineNo} at character ${character}`);
59
101
// have to readjust the character index
60
- let refPosition : vscode . Position = new vscode . Position ( lineNo , character + 1 ) ;
102
+ let refPosition : vscode . Position = new vscode . Position ( lineNo , character + 1 ) ;
61
103
references . push ( new vscode . Location ( fileUri , refPosition ) ) ;
62
104
}
63
105
lineNo ++ ;
@@ -87,7 +129,7 @@ export class YaraReferenceProvider implements vscode.ReferenceProvider {
87
129
88
130
export function activate ( context : vscode . ExtensionContext ) {
89
131
// console.log("Activating Yara extension");
90
- let YARA : vscode . DocumentSelector = { language : "yara" , scheme : "file" } ;
132
+ let YARA : vscode . DocumentSelector = { language : "yara" , scheme : "file" } ;
91
133
let definitionDisposable : vscode . Disposable = vscode . languages . registerDefinitionProvider ( YARA , new YaraDefinitionProvider ( ) ) ;
92
134
let referenceDisposable : vscode . Disposable = vscode . languages . registerReferenceProvider ( YARA , new YaraReferenceProvider ( ) ) ;
93
135
context . subscriptions . push ( definitionDisposable ) ;
0 commit comments