Improve FileSearchProvider (exclude grob support + no command)

feature/search
Kelvin Schoofs 6 years ago
parent 119f2bdc1e
commit 543c95c99a

14
package-lock.json generated

@ -25,6 +25,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
"dev": true
},
"@types/node": { "@types/node": {
"version": "8.10.43", "version": "8.10.43",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.43.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.43.tgz",
@ -483,8 +489,7 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
"dev": true
}, },
"base": { "base": {
"version": "0.11.2", "version": "0.11.2",
@ -589,7 +594,6 @@
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -987,8 +991,7 @@
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
"dev": true
}, },
"concat-stream": { "concat-stream": {
"version": "1.6.2", "version": "1.6.2",
@ -3083,7 +3086,6 @@
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }

@ -437,6 +437,7 @@
"postinstall": "node ./node_modules/vscode/bin/install" "postinstall": "node ./node_modules/vscode/bin/install"
}, },
"devDependencies": { "devDependencies": {
"@types/minimatch": "^3.0.3",
"@types/node": "^8.10.43", "@types/node": "^8.10.43",
"@types/request": "^2.48.1", "@types/request": "^2.48.1",
"@types/ssh2": "^0.5.35", "@types/ssh2": "^0.5.35",
@ -452,6 +453,7 @@
"dependencies": { "dependencies": {
"event-stream": "^3.3.4", "event-stream": "^3.3.4",
"jsonc-parser": "^2.0.0", "jsonc-parser": "^2.0.0",
"minimatch": "^3.0.4",
"socks": "^2.2.0", "socks": "^2.2.0",
"ssh2": "^0.8.2", "ssh2": "^0.8.2",
"winreg": "^1.2.4" "winreg": "^1.2.4"

@ -1,57 +1,56 @@
import * as minimatch from 'minimatch';
import { posix as path } from 'path'; import { posix as path } from 'path';
import { createInterface } from 'readline';
import { ClientChannel } from 'ssh2';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { Manager } from './manager'; import { Manager } from './manager';
import { toPromise } from './toPromise';
export class SearchProvider implements vscode.FileSearchProvider { export class SearchProvider implements vscode.FileSearchProvider {
protected cache: [vscode.CancellationToken, Promise<string[]>][] = []; protected cache: [vscode.CancellationToken, Promise<vscode.Uri[]>][] = [];
constructor(protected manager: Manager) { } constructor(protected manager: Manager) { }
public async provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Promise<vscode.Uri[]> { public async provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Promise<vscode.Uri[]> {
const { folder, session = token } = options; const { folder, session } = options;
let cached = this.cache.find(([t]) => session === t); let cached = this.cache.find(([t]) => session === t);
if (!cached) { if (!cached && session) {
cached = [session, this.buildTree(options, session)] as SearchProvider['cache'][0]; cached = [session, this.buildTree(options, session)] as SearchProvider['cache'][0];
this.cache.push(cached); this.cache.push(cached);
session.onCancellationRequested(() => { session.onCancellationRequested(() => {
this.cache.splice(this.cache.indexOf(cached!)); this.cache.splice(this.cache.indexOf(cached!));
}); });
} else if (!cached) {
cached = [token, this.buildTree(options, token)] as SearchProvider['cache'][0];
} }
const paths = await cached[1]; const paths = await cached[1];
console.log('Found', paths.length);
if (token.isCancellationRequested) return []; if (token.isCancellationRequested) return [];
const pattern = query.pattern.toLowerCase(); const pattern = query.pattern.toLowerCase();
return paths.map<vscode.Uri | null>((relative) => { return paths.map<vscode.Uri | null>((relative) => {
if (!relative.toLowerCase().includes(pattern)) return null; if (!relative.path.toLowerCase().includes(pattern)) return null;
return folder.with({ path: path.join(folder.path, relative) }); return folder.with({ path: path.join(folder.path, relative.path) });
}).filter(s => !!s) as vscode.Uri[]; }).filter(s => !!s) as vscode.Uri[];
} }
protected async buildTree(options: vscode.FileSearchOptions, token: vscode.CancellationToken): Promise<string[]> { protected async buildTree(options: vscode.FileSearchOptions, token: vscode.CancellationToken): Promise<vscode.Uri[]> {
const { folder } = options; const { folder } = options;
const fs = await this.manager.getFs(folder); const fs = await this.manager.getFs(folder);
if (!fs || token.isCancellationRequested) return []; if (!fs || token.isCancellationRequested) return [];
const cmd = `ls -AQ1R "${fs.absoluteFromRelative(folder.path)}"`; const excludes = options.excludes.map(e => minimatch.makeRe(e, { nocase: true }));
console.log('Creating tree with command:', cmd); const exclude = (p: string) => excludes.some(reg => reg.test(p));
const exec = await toPromise<ClientChannel>(cb => fs.client.exec(cmd, cb)).catch(() => null); const res: vscode.Uri[] = [];
if (!exec || token.isCancellationRequested) return []; async function readDirectory(uri: vscode.Uri) {
const res: string[] = []; if (token.isCancellationRequested) return;
const rl = createInterface(exec); const entries = await fs!.readDirectory(uri).catch(() => [] as never);
let root = ''; if (token.isCancellationRequested) return;
rl.on('line', (line: string) => { return Promise.all(entries.map(([name, type]) => {
if (!line) return; if (token.isCancellationRequested) return;
if (line.endsWith(':')) { const joined = path.join(uri.path, name);
root = JSON.parse(line.substr(0, line.length - 1)); if (exclude(joined)) return;
} else { // tslint:disable-next-line:no-bitwise
let relative = JSON.parse(line); if (type & vscode.FileType.Directory) {
relative = path.join(root, relative); return readDirectory(uri.with({ path: joined }));
relative = fs.relativeFromAbsolute(relative); } else {
res.push(relative); res.push(uri.with({ path: joined }));
} }
}); }));
token.onCancellationRequested(rl.close, rl); }
await toPromise(cb => rl.on('close', cb)); await readDirectory(folder);
return res; return res;
} }
} }

Loading…
Cancel
Save