| 47 | } |
| 48 | |
| 49 | async function pickFile() { |
| 50 | const disposables: Disposable[] = []; |
| 51 | try { |
| 52 | return await new Promise<Uri | undefined>((resolve) => { |
| 53 | const input = window.createQuickPick<FileItem | MessageItem>(); |
| 54 | input.placeholder = 'Type to search for files'; |
| 55 | let rgs: cp.ChildProcess[] = []; |
| 56 | disposables.push( |
| 57 | input.onDidChangeValue(value => { |
| 58 | rgs.forEach(rg => rg.kill()); |
| 59 | if (!value) { |
| 60 | input.items = []; |
| 61 | return; |
| 62 | } |
| 63 | input.busy = true; |
| 64 | const cwds = workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.fsPath) : [process.cwd()]; |
| 65 | const q = process.platform === 'win32' ? '"' : '\''; |
| 66 | rgs = cwds.map(cwd => { |
| 67 | const rg = cp.exec(`rg --files -g ${q}*${value}*${q}`, { cwd }, (err, stdout) => { |
| 68 | const i = rgs.indexOf(rg); |
| 69 | if (i !== -1) { |
| 70 | if (rgs.length === cwds.length) { |
| 71 | input.items = []; |
| 72 | } |
| 73 | if (!err) { |
| 74 | input.items = input.items.concat( |
| 75 | stdout |
| 76 | .split('\n').slice(0, 50) |
| 77 | .map(relative => new FileItem(Uri.file(cwd), Uri.file(path.join(cwd, relative)))) |
| 78 | ); |
| 79 | } |
| 80 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| 81 | if (err && !(err as any).killed && (err as any).code !== 1 && err.message) { |
| 82 | input.items = input.items.concat([ |
| 83 | new MessageItem(Uri.file(cwd), err.message) |
| 84 | ]); |
| 85 | } |
| 86 | rgs.splice(i, 1); |
| 87 | if (!rgs.length) { |
| 88 | input.busy = false; |
| 89 | } |
| 90 | } |
| 91 | }); |
| 92 | return rg; |
| 93 | }); |
| 94 | }), |
| 95 | input.onDidChangeSelection(items => { |
| 96 | const item = items[0]; |
| 97 | if (item instanceof FileItem) { |
| 98 | resolve(item.uri); |
| 99 | input.hide(); |
| 100 | } |
| 101 | }), |
| 102 | input.onDidHide(() => { |
| 103 | rgs.forEach(rg => rg.kill()); |
| 104 | resolve(undefined); |
| 105 | input.dispose(); |
| 106 | }) |