private async pickResource()

in src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts [181:366]


	private async pickResource(isSave: boolean = false): Promise<URI | undefined> {
		this.allowFolderSelection = !!this.options.canSelectFolders;
		this.allowFileSelection = !!this.options.canSelectFiles;
		this.separator = this.labelService.getSeparator(this.scheme, this.remoteAuthority);
		this.hidden = false;
		let homedir: URI = this.options.defaultUri ? this.options.defaultUri : this.workspaceContextService.getWorkspace().folders[0].uri;
		let stat: IFileStat | undefined;
		let ext: string = resources.extname(homedir);
		if (this.options.defaultUri) {
			try {
				stat = await this.fileService.resolve(this.options.defaultUri);
			} catch (e) {
				// The file or folder doesn't exist
			}
			if (!stat || !stat.isDirectory) {
				homedir = resources.dirname(this.options.defaultUri);
				this.trailing = resources.basename(this.options.defaultUri);
			}
			// append extension
			if (isSave && !ext && this.options.filters) {
				for (let i = 0; i < this.options.filters.length; i++) {
					if (this.options.filters[i].extensions[0] !== '*') {
						ext = '.' + this.options.filters[i].extensions[0];
						this.trailing = this.trailing ? this.trailing + ext : ext;
						break;
					}
				}
			}
		}

		return new Promise<URI | undefined>(async (resolve) => {
			this.filePickBox = this.quickInputService.createQuickPick<FileQuickPickItem>();
			this.busy = true;
			this.filePickBox.matchOnLabel = false;
			this.filePickBox.autoFocusOnList = false;
			this.filePickBox.ignoreFocusOut = true;
			this.filePickBox.ok = true;
			if (this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) {
				this.filePickBox.customButton = true;
				this.filePickBox.customLabel = nls.localize('remoteFileDialog.local', 'Show Local');
				let action;
				if (isSave) {
					action = SaveLocalFileCommand;
				} else {
					action = this.allowFileSelection ? (this.allowFolderSelection ? OpenLocalFileFolderCommand : OpenLocalFileCommand) : OpenLocalFolderCommand;
				}
				const keybinding = this.keybindingService.lookupKeybinding(action.ID);
				if (keybinding) {
					const label = keybinding.getLabel();
					if (label) {
						this.filePickBox.customHover = format('{0} ({1})', action.LABEL, label);
					}
				}
			}

			let isResolving: number = 0;
			let isAcceptHandled = false;
			this.currentFolder = resources.dirname(homedir);
			this.userEnteredPathSegment = '';
			this.autoCompletePathSegment = '';

			this.filePickBox.title = this.options.title;
			this.filePickBox.value = this.pathFromUri(this.currentFolder, true);
			this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length];
			this.filePickBox.items = [];

			function doResolve(dialog: RemoteFileDialog, uri: URI | undefined) {
				if (uri) {
					uri = resources.removeTrailingPathSeparator(uri);
				}
				resolve(uri);
				dialog.contextKey.set(false);
				dialog.filePickBox.dispose();
				dispose(dialog.disposables);
			}

			this.filePickBox.onDidCustom(() => {
				if (isAcceptHandled || this.busy) {
					return;
				}

				isAcceptHandled = true;
				isResolving++;
				if (this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) {
					this.options.availableFileSystems.shift();
				}
				this.filePickBox.hide();
				if (isSave) {
					return this.fileDialogService.showSaveDialog(this.options).then(result => {
						doResolve(this, result);
					});
				} else {
					return this.fileDialogService.showOpenDialog(this.options).then(result => {
						doResolve(this, result ? result[0] : undefined);
					});
				}
			});

			function handleAccept(dialog: RemoteFileDialog) {
				if (dialog.busy) {
					// Save the accept until the file picker is not busy.
					dialog.onBusyChangeEmitter.event((busy: boolean) => {
						if (!busy) {
							handleAccept(dialog);
						}
					});
					return;
				} else if (isAcceptHandled) {
					return;
				}

				isAcceptHandled = true;
				isResolving++;
				dialog.onDidAccept().then(resolveValue => {
					if (resolveValue) {
						dialog.filePickBox.hide();
						doResolve(dialog, resolveValue);
					} else if (dialog.hidden) {
						doResolve(dialog, undefined);
					} else {
						isResolving--;
						isAcceptHandled = false;
					}
				});
			}

			this.filePickBox.onDidAccept(_ => {
				handleAccept(this);
			});

			this.filePickBox.onDidChangeActive(i => {
				isAcceptHandled = false;
				// update input box to match the first selected item
				if ((i.length === 1) && this.isSelectionChangeFromUser()) {
					this.filePickBox.validationMessage = undefined;
					const userPath = this.constructFullUserPath();
					if (!equalsIgnoreCase(this.filePickBox.value.substring(0, userPath.length), userPath)) {
						this.filePickBox.valueSelection = [0, this.filePickBox.value.length];
						this.insertText(userPath, userPath);
					}
					this.setAutoComplete(userPath, this.userEnteredPathSegment, i[0], true);
				}
			});

			this.filePickBox.onDidChangeValue(async value => {
				try {
					// onDidChangeValue can also be triggered by the auto complete, so if it looks like the auto complete, don't do anything
					if (this.isValueChangeFromUser()) {
						// If the user has just entered more bad path, don't change anything
						if (!equalsIgnoreCase(value, this.constructFullUserPath()) && !this.isBadSubpath(value)) {
							this.filePickBox.validationMessage = undefined;
							const filePickBoxUri = this.filePickBoxValue();
							let updated: UpdateResult = UpdateResult.NotUpdated;
							if (!resources.isEqual(this.currentFolder, filePickBoxUri, true)) {
								updated = await this.tryUpdateItems(value, filePickBoxUri);
							}
							if (updated === UpdateResult.NotUpdated) {
								this.setActiveItems(value);
							}
						} else {
							this.filePickBox.activeItems = [];
							this.userEnteredPathSegment = '';
						}
					}
				} catch {
					// Since any text can be entered in the input box, there is potential for error causing input. If this happens, do nothing.
				}
			});
			this.filePickBox.onDidHide(() => {
				this.hidden = true;
				if (isResolving === 0) {
					doResolve(this, undefined);
				}
			});

			this.filePickBox.show();
			this.contextKey.set(true);
			await this.updateItems(homedir, true, this.trailing);
			if (this.trailing) {
				this.filePickBox.valueSelection = [this.filePickBox.value.length - this.trailing.length, this.filePickBox.value.length - ext.length];
			} else {
				this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length];
			}
			this.busy = false;
		});
	}