@@ -52,6 +52,7 @@ export class TextSearchProvider implements vscode.TextSearchProvider {
52
52
let projectList : string [ ] ;
53
53
let searchPromise : Promise < SearchResult [ ] > ;
54
54
const params = new URLSearchParams ( options . folder . query ) ;
55
+ const csp = params . has ( "csp" ) && [ "" , "1" ] . includes ( params . get ( "csp" ) ) ;
55
56
if ( params . has ( "project" ) && params . get ( "project" ) . length ) {
56
57
project = params . get ( "project" ) ;
57
58
projectList = await api
@@ -104,13 +105,94 @@ export class TextSearchProvider implements vscode.TextSearchProvider {
104
105
} else {
105
106
const sysStr = params . has ( "system" ) && params . get ( "system" ) . length ? params . get ( "system" ) : "0" ;
106
107
const genStr = params . has ( "generated" ) && params . get ( "generated" ) . length ? params . get ( "generated" ) : "0" ;
108
+
109
+ let uri = options . folder ;
110
+
111
+ if ( ! params . get ( "filter" ) ) {
112
+ // Unless isfs spec already includes a non-empty filter (which it rarely does), apply includes and excludes at the server side.
113
+ // Convert **/ separators and /** suffix into multiple *-patterns that simulate these elements of glob syntax.
114
+
115
+ // Function to convert glob-style filters into ones that the server understands
116
+ const convertFilters = ( filters : string [ ] ) : string [ ] => {
117
+ // Use map to prevent duplicates in final result
118
+ const filterMap = new Map < string , void > ( ) ;
119
+
120
+ // The recursive function we use
121
+ const recurse = ( value : string ) : void => {
122
+ const parts = value . split ( "**/" ) ;
123
+ if ( parts . length < 2 ) {
124
+ // No more recursion
125
+ if ( value . endsWith ( "/**" ) ) {
126
+ filterMap . set ( value . slice ( 0 , - 1 ) ) ;
127
+ filterMap . set ( value . slice ( 0 , - 3 ) ) ;
128
+ } else {
129
+ filterMap . set ( value ) ;
130
+ }
131
+ } else {
132
+ const first = parts [ 0 ] ;
133
+ const rest = parts . slice ( 1 ) ;
134
+ recurse ( first + "*/" + rest . join ( "**/" ) ) ;
135
+ recurse ( first + rest . join ( "**/" ) ) ;
136
+ }
137
+ } ;
138
+
139
+ // Invoke our recursive function
140
+ filters
141
+ . filter ( ( value ) => csp || ! value . match ( / \. ( [ a - z ] + | \* ) \/ \* \* $ / ) ) // drop superfluous entries ending .xyz/** or .*/** when not handling CSP files
142
+ . forEach ( ( value ) => {
143
+ recurse ( value ) ;
144
+ } ) ;
145
+
146
+ // Convert map to array and return it
147
+ const results : string [ ] = [ ] ;
148
+ filterMap . forEach ( ( _v , key ) => {
149
+ results . push ( key ) ;
150
+ } ) ;
151
+ return results ;
152
+ } ;
153
+
154
+ // Function to get one of the two kinds of exclude settings as an array
155
+ const getConfigExcludes = ( key : string ) => {
156
+ return Object . entries ( vscode . workspace . getConfiguration ( key , options . folder ) . get ( "exclude" ) )
157
+ . filter ( ( value ) => value [ 1 ] === true )
158
+ . map ( ( value ) => value [ 0 ] ) ;
159
+ } ;
160
+
161
+ // Build an array containing the files.exclude settings followed by the search.exclude ones,
162
+ // then try to remove exactly those from the end of the ones passed to us when "Use Exclude Settings and Ignore Files" is on.
163
+ const configurationExcludes = getConfigExcludes ( "files" ) . concat ( getConfigExcludes ( "search" ) ) ;
164
+ const ourExcludes = options . excludes ;
165
+ while ( configurationExcludes . length > 0 ) {
166
+ if ( configurationExcludes . pop ( ) !== ourExcludes . pop ( ) ) {
167
+ break ;
168
+ }
169
+ }
170
+
171
+ // If we successfully removed them all, the ones that remain were explicitly entered in the "files to exclude" field of Search, so use them.
172
+ // If removal was unsuccessful use the whole set.
173
+ const filterExclude = convertFilters ( ! configurationExcludes . length ? ourExcludes : options . excludes ) . join ( ",'" ) ;
174
+
175
+ const filterInclude =
176
+ options . includes . length > 0
177
+ ? convertFilters ( options . includes ) . join ( "," )
178
+ : filterExclude
179
+ ? fileSpecFromURI ( uri ) // Excludes were specified but no includes, so start with the default includes (this step makes type=cls|rtn effective)
180
+ : "" ;
181
+ const filter = filterInclude + ( ! filterExclude ? "" : ",'" + filterExclude ) ;
182
+ if ( filter ) {
183
+ // Unless isfs is serving CSP files, slash separators in filters must be converted to dot ones before sending to server
184
+ params . append ( "filter" , csp ? filter : filter . replace ( / \/ / g, "." ) ) ;
185
+ uri = options . folder . with ( { query : params . toString ( ) } ) ;
186
+ }
187
+ }
188
+
107
189
searchPromise = api
108
190
. actionSearch ( {
109
191
query : query . pattern ,
110
192
regex : query . isRegExp ,
111
193
word : query . isWordMatch ,
112
194
case : query . isCaseSensitive ,
113
- files : fileSpecFromURI ( options . folder ) ,
195
+ files : fileSpecFromURI ( uri ) ,
114
196
sys : sysStr === "1" || ( sysStr === "0" && api . ns === "%SYS" ) ,
115
197
gen : genStr === "1" ,
116
198
// If options.maxResults is null the search is supposed to return an unlimited number of results
@@ -139,6 +221,31 @@ export class TextSearchProvider implements vscode.TextSearchProvider {
139
221
return ;
140
222
}
141
223
}
224
+
225
+ // Don't report matches in filetypes we don't want or don't handle
226
+ const fileType = file . doc . split ( "." ) . pop ( ) . toLowerCase ( ) ;
227
+ if ( ! csp ) {
228
+ switch ( params . get ( "type" ) ) {
229
+ case "cls" :
230
+ if ( fileType !== "cls" ) {
231
+ return ;
232
+ }
233
+ break ;
234
+
235
+ case "rtn" :
236
+ if ( ! [ "inc" , "int" , "mac" ] . includes ( fileType ) ) {
237
+ return ;
238
+ }
239
+ break ;
240
+
241
+ default :
242
+ if ( ! [ "cls" , "inc" , "int" , "mac" ] . includes ( fileType ) ) {
243
+ return ;
244
+ }
245
+ break ;
246
+ }
247
+ }
248
+
142
249
const uri = DocumentContentProvider . getUri ( file . doc , "" , "" , true , options . folder ) ;
143
250
const content = decoder . decode ( await vscode . workspace . fs . readFile ( uri ) ) . split ( "\n" ) ;
144
251
// Find all lines that we have matches on
0 commit comments