Skip to content

Commit 2d2404e

Browse files
committed
Refactor search filter logic
1 parent 6e57279 commit 2d2404e

File tree

1 file changed

+68
-18
lines changed

1 file changed

+68
-18
lines changed

src/providers/FileSystemProvider/TextSearchProvider.ts

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export class TextSearchProvider implements vscode.TextSearchProvider {
5252
let projectList: string[];
5353
let searchPromise: Promise<SearchResult[]>;
5454
const params = new URLSearchParams(options.folder.query);
55+
const csp = params.has("csp") && ["", "1"].includes(params.get("csp"));
5556
if (params.has("project") && params.get("project").length) {
5657
project = params.get("project");
5758
projectList = await api
@@ -109,34 +110,58 @@ export class TextSearchProvider implements vscode.TextSearchProvider {
109110

110111
if (!params.get("filter")) {
111112
// Unless isfs spec already includes a non-empty filter (which it rarely does), apply includes and excludes at the server side.
112-
// If include or exclude field is set to, say, A1B2M*.int there will be two consecutive options.[in|ex]cludes elements:
113-
// **/A1B2M*.int/**
114-
// **/A1B2M*.int
113+
// Convert **/ separators and /** suffix into multiple *-patterns that simulate these elements of glob syntax.
115114
//
116-
// Ignore first, and strip **/ prefix from second.
117115
// When 'Use Exclude Settings and Ignore Files' is enabled (which is typical) options.excludes will also contain entries from files.exclude and search.exclude settings.
118116
// This will result in additional server-side filtering which is superfluous but harmless other than perhaps incurring a small(?) performance cost.
119-
const tidyFilters = (filters: string[]): string[] => {
120-
return filters
121-
.map((value, index, array) =>
122-
value.endsWith("/**") && index < array.length - 1 && array[index + 1] + "/**" === value
123-
? ""
124-
: value.startsWith("**/")
125-
? value.slice(3)
126-
: value
127-
)
128-
.filter((value) => value !== "");
117+
118+
// Function to convert glob-style filters into ones the server understands
119+
const convertFilters = (filters: string[]): string[] => {
120+
// Use map to prevent duplicates in final result
121+
const filterMap = new Map<string, void>();
122+
123+
// The recursive function we use
124+
const recurse = (value: string): void => {
125+
const parts = value.split("**/");
126+
if (parts.length < 2) {
127+
// No more recursion
128+
if (value.endsWith("/**")) {
129+
filterMap.set(value.slice(0, -1));
130+
filterMap.set(value.slice(0, -3));
131+
} else {
132+
filterMap.set(value);
133+
}
134+
} else {
135+
const first = parts[0];
136+
const rest = parts.slice(1);
137+
recurse(first + "*/" + rest.join("**/"));
138+
recurse(first + rest.join("**/"));
139+
}
140+
};
141+
142+
// Invoke our recursive function
143+
filters.forEach((value) => {
144+
recurse(value);
145+
});
146+
147+
// Convert map to array and return it
148+
const results: string[] = [];
149+
filterMap.forEach((_v, key) => {
150+
results.push(key);
151+
});
152+
return results;
129153
};
130-
const filterExclude = tidyFilters(options.excludes).join(",'");
154+
155+
const filterExclude = convertFilters(options.excludes).join(",'");
131156
const filterInclude =
132157
options.includes.length > 0
133-
? tidyFilters(options.includes).join(",")
158+
? convertFilters(options.includes).join(",")
134159
: filterExclude
135-
? fileSpecFromURI(uri) // Excludes were specified but no includes, so start with the default includes (this makes type=cls|rtn work)
160+
? fileSpecFromURI(uri) // Excludes were specified but no includes, so start with the default includes (this step makes type=cls|rtn effective)
136161
: "";
137162
const filter = filterInclude + (!filterExclude ? "" : ",'" + filterExclude);
138163
if (filter) {
139-
const csp = params.has("csp") && ["", "1"].includes(params.get("csp"));
164+
// Unless isfs is serving CSP files, slash separators in filters must be converted to dot ones before sending to server
140165
params.append("filter", csp ? filter : filter.replace(/\//g, "."));
141166
uri = options.folder.with({ query: params.toString() });
142167
}
@@ -177,6 +202,31 @@ export class TextSearchProvider implements vscode.TextSearchProvider {
177202
return;
178203
}
179204
}
205+
206+
// Don't report matches in filetypes we don't want or don't handle
207+
const fileType = file.doc.split(".").pop().toLowerCase();
208+
if (!csp) {
209+
switch (params.get("type")) {
210+
case "cls":
211+
if (fileType !== "cls") {
212+
return;
213+
}
214+
break;
215+
216+
case "rtn":
217+
if (!["inc", "int", "mac"].includes(fileType)) {
218+
return;
219+
}
220+
break;
221+
222+
default:
223+
if (!["cls", "inc", "int", "mac"].includes(fileType)) {
224+
return;
225+
}
226+
break;
227+
}
228+
}
229+
180230
const uri = DocumentContentProvider.getUri(file.doc, "", "", true, options.folder);
181231
const content = decoder.decode(await vscode.workspace.fs.readFile(uri)).split("\n");
182232
// Find all lines that we have matches on

0 commit comments

Comments
 (0)