@@ -3,6 +3,7 @@ import type {
3
3
ScopeType ,
4
4
SimpleScopeType ,
5
5
SimpleScopeTypeType ,
6
+ StringRecord ,
6
7
TreeSitter ,
7
8
} from "@cursorless/common" ;
8
9
import {
@@ -12,6 +13,7 @@ import {
12
13
type TextDocument ,
13
14
} from "@cursorless/common" ;
14
15
import { TreeSitterScopeHandler } from "../processTargets/modifiers/scopeHandlers" ;
16
+ import { LanguageDefinitionCache } from "./LanguageDefinitionCache" ;
15
17
import { TreeSitterQuery } from "./TreeSitterQuery" ;
16
18
import type { QueryCapture } from "./TreeSitterQuery/QueryCapture" ;
17
19
import { validateQueryCaptures } from "./TreeSitterQuery/validateQueryCaptures" ;
@@ -21,14 +23,18 @@ import { validateQueryCaptures } from "./TreeSitterQuery/validateQueryCaptures";
21
23
* tree-sitter query used to extract scopes for the given language
22
24
*/
23
25
export class LanguageDefinition {
26
+ private cache : LanguageDefinitionCache ;
27
+
24
28
private constructor (
25
29
/**
26
30
* The tree-sitter query used to extract scopes for the given language.
27
31
* Note that this query contains patterns for all scope types that the
28
32
* language supports using new-style tree-sitter queries
29
33
*/
30
34
private query : TreeSitterQuery ,
31
- ) { }
35
+ ) {
36
+ this . cache = new LanguageDefinitionCache ( ) ;
37
+ }
32
38
33
39
/**
34
40
* Construct a language definition for the given language id, if the language
@@ -93,10 +99,34 @@ export class LanguageDefinition {
93
99
document : TextDocument ,
94
100
captureName : SimpleScopeTypeType ,
95
101
) : QueryCapture [ ] {
96
- return this . query
97
- . matches ( document )
98
- . map ( ( match ) => match . captures . find ( ( { name } ) => name === captureName ) )
99
- . filter ( ( capture ) => capture != null ) ;
102
+ if ( ! this . cache . isValid ( document ) ) {
103
+ this . cache . update ( document , this . getCapturesMap ( document ) ) ;
104
+ }
105
+
106
+ return this . cache . get ( captureName ) ;
107
+ }
108
+
109
+ clearCache ( ) : void {
110
+ this . cache = new LanguageDefinitionCache ( ) ;
111
+ }
112
+
113
+ /**
114
+ * This is a low level function that returns a map of all captures in the document.
115
+ */
116
+ private getCapturesMap ( document : TextDocument ) : StringRecord < QueryCapture [ ] > {
117
+ const matches = this . query . matches ( document ) ;
118
+ const result : StringRecord < QueryCapture [ ] > = { } ;
119
+
120
+ for ( const match of matches ) {
121
+ for ( const capture of match . captures ) {
122
+ if ( result [ capture . name ] == null ) {
123
+ result [ capture . name ] = [ ] ;
124
+ }
125
+ result [ capture . name ] ! . push ( capture ) ;
126
+ }
127
+ }
128
+
129
+ return result ;
100
130
}
101
131
}
102
132
0 commit comments