parent
119f2bdc1e
commit
543c95c99a
@ -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…
Reference in new issue