Merge from vscode 0fde6619172c9f04c41f2e816479e432cc974b8b (#5199)

This commit is contained in:
Anthony Dresser
2019-04-24 22:26:02 -07:00
committed by GitHub
parent d63f07d29a
commit 34457880c7
86 changed files with 1254 additions and 702 deletions

View File

@@ -34,6 +34,7 @@ interface FileQuickPickItem extends IQuickPickItem {
enum UpdateResult {
Updated,
Updating,
NotUpdated,
InvalidPath
}
@@ -51,6 +52,7 @@ export class RemoteFileDialog {
private allowFolderSelection: boolean;
private remoteAuthority: string | undefined;
private requiresTrailing: boolean;
private trailing: string | undefined;
private scheme: string = REMOTE_HOST_SCHEME;
private contextKey: IContextKey<boolean>;
private userEnteredPathSegment: string;
@@ -149,7 +151,6 @@ export class RemoteFileDialog {
this.allowFileSelection = !!this.options.canSelectFiles;
this.hidden = false;
let homedir: URI = this.options.defaultUri ? this.options.defaultUri : this.workspaceContextService.getWorkspace().folders[0].uri;
let trailing: string | undefined;
let stat: IFileStat | undefined;
let ext: string = resources.extname(homedir);
if (this.options.defaultUri) {
@@ -160,14 +161,14 @@ export class RemoteFileDialog {
}
if (!stat || !stat.isDirectory) {
homedir = resources.dirname(this.options.defaultUri);
trailing = resources.basename(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];
trailing = trailing ? trailing + ext : ext;
this.trailing = this.trailing ? this.trailing + ext : ext;
break;
}
}
@@ -176,6 +177,7 @@ export class RemoteFileDialog {
return new Promise<URI | undefined>(async (resolve) => {
this.filePickBox = this.quickInputService.createQuickPick<FileQuickPickItem>();
this.filePickBox.busy = true;
this.filePickBox.matchOnLabel = false;
this.filePickBox.autoFocusOnList = false;
this.filePickBox.ignoreFocusOut = true;
@@ -221,6 +223,7 @@ export class RemoteFileDialog {
this.options.availableFileSystems.shift();
}
this.options.defaultUri = undefined;
this.filePickBox.hide();
if (this.requiresTrailing) {
return this.fileDialogService.showSaveDialog(this.options).then(result => {
doResolve(this, result);
@@ -264,7 +267,7 @@ export class RemoteFileDialog {
// onDidChangeValue can also be triggered by the auto complete, so if it looks like the auto complete, don't do anything
if (this.isChangeFromUser()) {
// If the user has just entered more bad path, don't change anything
if (value !== this.constructFullUserPath() && !this.isBadSubpath(value)) {
if (!equalsIgnoreCase(value, this.constructFullUserPath()) && !this.isBadSubpath(value)) {
this.filePickBox.validationMessage = undefined;
const valueUri = this.remoteUriFrom(this.trimTrailingSlash(this.filePickBox.value));
let updated: UpdateResult = UpdateResult.NotUpdated;
@@ -288,12 +291,13 @@ export class RemoteFileDialog {
this.filePickBox.show();
this.contextKey.set(true);
await this.updateItems(homedir, trailing);
if (trailing) {
this.filePickBox.valueSelection = [this.filePickBox.value.length - trailing.length, this.filePickBox.value.length - ext.length];
await this.updateItems(homedir, 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.filePickBox.busy = false;
});
}
@@ -302,7 +306,7 @@ export class RemoteFileDialog {
}
private isChangeFromUser(): boolean {
if ((this.filePickBox.value === this.pathAppend(this.currentFolder, this.userEnteredPathSegment + this.autoCompletePathSegment))
if (equalsIgnoreCase(this.filePickBox.value, this.pathAppend(this.currentFolder, this.userEnteredPathSegment + this.autoCompletePathSegment))
&& (this.activeItem === (this.filePickBox.activeItems ? this.filePickBox.activeItems[0] : undefined))) {
return false;
}
@@ -314,6 +318,7 @@ export class RemoteFileDialog {
}
private async onDidAccept(): Promise<URI | undefined> {
this.filePickBox.busy = true;
let resolveValue: URI | undefined;
let navigateValue: URI | undefined;
const trimmedPickBoxValue = ((this.filePickBox.value.length > 1) && this.endsWithSlash(this.filePickBox.value)) ? this.filePickBox.value.substr(0, this.filePickBox.value.length - 1) : this.filePickBox.value;
@@ -351,21 +356,25 @@ export class RemoteFileDialog {
if (resolveValue) {
resolveValue = this.addPostfix(resolveValue);
if (await this.validate(resolveValue)) {
return Promise.resolve(resolveValue);
this.filePickBox.busy = false;
return resolveValue;
}
} else if (navigateValue) {
// Try to navigate into the folder
await this.updateItems(navigateValue);
// Try to navigate into the folder.
await this.updateItems(navigateValue, this.trailing);
} else {
// validation error. Path does not exist.
}
return Promise.resolve(undefined);
this.filePickBox.busy = false;
return undefined;
}
private async tryUpdateItems(value: string, valueUri: URI): Promise<UpdateResult> {
if (value[value.length - 1] === '~') {
await this.updateItems(this.userHome);
if (this.filePickBox.busy) {
this.badPath = undefined;
return UpdateResult.Updating;
} else if (value[value.length - 1] === '~') {
await this.updateItems(this.userHome);
return UpdateResult.Updated;
} else if (this.endsWithSlash(value) || (!resources.isEqual(this.currentFolder, resources.dirname(valueUri), true) && resources.isEqualOrParent(this.currentFolder, resources.dirname(valueUri), true))) {
let stat: IFileStat | undefined;
@@ -409,7 +418,7 @@ export class RemoteFileDialog {
const inputBasename = resources.basename(this.remoteUriFrom(value));
// Make sure that the folder whose children we are currently viewing matches the path in the input
const userPath = this.constructFullUserPath();
if (userPath === value.substring(0, userPath.length)) {
if (equalsIgnoreCase(userPath, value.substring(0, userPath.length))) {
let hasMatch = false;
for (let i = 0; i < this.filePickBox.items.length; i++) {
const item = <FileQuickPickItem>this.filePickBox.items[i];
@@ -424,7 +433,7 @@ export class RemoteFileDialog {
this.filePickBox.activeItems = [];
}
} else {
if (inputBasename !== resources.basename(this.currentFolder)) {
if (!equalsIgnoreCase(inputBasename, resources.basename(this.currentFolder))) {
this.userEnteredPathSegment = inputBasename;
} else {
this.userEnteredPathSegment = '';
@@ -442,24 +451,34 @@ export class RemoteFileDialog {
}
const itemBasename = quickPickItem.label;
// Either force the autocomplete, or the old value should be one smaller than the new value and match the new value.
if (!force && (itemBasename.length >= startingBasename.length) && equalsIgnoreCase(itemBasename.substr(0, startingBasename.length), startingBasename)) {
if (itemBasename === '..') {
// Don't match on the up directory item ever.
this.userEnteredPathSegment = startingValue;
this.autoCompletePathSegment = '';
this.activeItem = quickPickItem;
if (force) {
// clear any selected text
this.insertText(this.userEnteredPathSegment, '');
}
return false;
} else if (!force && (itemBasename.length >= startingBasename.length) && equalsIgnoreCase(itemBasename.substr(0, startingBasename.length), startingBasename)) {
this.userEnteredPathSegment = startingBasename;
this.activeItem = quickPickItem;
// Changing the active items will trigger the onDidActiveItemsChanged. Clear the autocomplete first, then set it after.
this.autoCompletePathSegment = '';
this.filePickBox.activeItems = [quickPickItem];
this.autoCompletePathSegment = itemBasename.substr(startingBasename.length);
this.autoCompletePathSegment = this.trimTrailingSlash(itemBasename.substr(startingBasename.length));
this.insertText(startingValue + this.autoCompletePathSegment, this.autoCompletePathSegment);
this.filePickBox.valueSelection = [startingValue.length, this.filePickBox.value.length];
return true;
} else if (force && (quickPickItem.label !== (this.userEnteredPathSegment + this.autoCompletePathSegment))) {
} else if (force && (!equalsIgnoreCase(quickPickItem.label, (this.userEnteredPathSegment + this.autoCompletePathSegment)))) {
this.userEnteredPathSegment = '';
this.autoCompletePathSegment = itemBasename;
this.autoCompletePathSegment = this.trimTrailingSlash(itemBasename);
this.activeItem = quickPickItem;
this.filePickBox.valueSelection = [this.pathFromUri(this.currentFolder, true).length, this.filePickBox.value.length];
// use insert text to preserve undo buffer
this.insertText(this.pathAppend(this.currentFolder, itemBasename), itemBasename);
this.filePickBox.valueSelection = [this.filePickBox.value.length - itemBasename.length, this.filePickBox.value.length];
this.insertText(this.pathAppend(this.currentFolder, this.autoCompletePathSegment), this.autoCompletePathSegment);
this.filePickBox.valueSelection = [this.filePickBox.value.length - this.autoCompletePathSegment.length, this.filePickBox.value.length];
return true;
} else {
this.userEnteredPathSegment = startingBasename;
@@ -506,21 +525,24 @@ export class RemoteFileDialog {
return ((path.length > 1) && this.endsWithSlash(path)) ? path.substr(0, path.length - 1) : path;
}
private yesNoPrompt(message: string): Promise<boolean> {
private yesNoPrompt(uri: URI, message: string): Promise<boolean> {
interface YesNoItem extends IQuickPickItem {
value: boolean;
}
const prompt = this.quickInputService.createQuickPick<YesNoItem>();
const no = nls.localize('remoteFileDialog.no', 'No');
prompt.items = [{ label: no, value: false }, { label: nls.localize('remoteFileDialog.yes', 'Yes'), value: true }];
prompt.title = message;
prompt.placeholder = no;
prompt.ignoreFocusOut = true;
prompt.ok = true;
prompt.customButton = true;
prompt.customLabel = nls.localize('remoteFileDialog.cancel', 'Cancel');
prompt.value = this.pathFromUri(uri);
let isResolving = false;
return new Promise<boolean>(resolve => {
prompt.onDidAccept(() => {
isResolving = true;
prompt.hide();
resolve(prompt.selectedItems ? prompt.selectedItems[0].value : false);
resolve(true);
});
prompt.onDidHide(() => {
if (!isResolving) {
@@ -531,6 +553,12 @@ export class RemoteFileDialog {
this.filePickBox.items = this.filePickBox.items;
prompt.dispose();
});
prompt.onDidChangeValue(() => {
prompt.hide();
});
prompt.onDidCustom(() => {
prompt.hide();
});
prompt.show();
});
}
@@ -554,7 +582,7 @@ export class RemoteFileDialog {
// Replacing a file.
// Show a yes/no prompt
const message = nls.localize('remoteFileDialog.validateExisting', '{0} already exists. Are you sure you want to overwrite it?', resources.basename(uri));
return this.yesNoPrompt(message);
return this.yesNoPrompt(uri, message);
} else if (!this.isValidBaseName(resources.basename(uri))) {
// Filename not allowed
this.filePickBox.validationMessage = nls.localize('remoteFileDialog.validateBadFilename', 'Please enter a valid file name.');
@@ -587,15 +615,24 @@ export class RemoteFileDialog {
this.userEnteredPathSegment = trailing ? trailing : '';
this.autoCompletePathSegment = '';
const newValue = trailing ? this.pathFromUri(resources.joinPath(newFolder, trailing)) : this.pathFromUri(newFolder, true);
this.currentFolder = this.remoteUriFrom(this.pathFromUri(newFolder, true));
const oldFolder = this.currentFolder;
const newFolderPath = this.pathFromUri(newFolder, true);
this.currentFolder = this.remoteUriFrom(newFolderPath);
return this.createItems(this.currentFolder).then(items => {
this.filePickBox.items = items;
if (this.allowFolderSelection) {
this.filePickBox.activeItems = [];
}
if (!equalsIgnoreCase(this.filePickBox.value, newValue)) {
this.filePickBox.valueSelection = [0, this.filePickBox.value.length];
this.insertText(newValue, newValue);
// the user might have continued typing while we were updating. Only update the input box if it doesn't match the directory.
if (!equalsIgnoreCase(this.filePickBox.value.substring(0, newValue.length), newValue)) {
this.filePickBox.valueSelection = [0, this.filePickBox.value.length];
this.insertText(newValue, newValue);
} else if (equalsIgnoreCase(this.pathFromUri(resources.dirname(oldFolder), true), newFolderPath)) {
// This is the case where the user went up one dir. We need to make sure that we remove the final dir.
this.filePickBox.valueSelection = [newFolderPath.length, this.filePickBox.value.length];
this.insertText(newValue, '');
}
}
this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length];
this.filePickBox.busy = false;