Adds new proposed api for scm input validation

This commit is contained in:
Eric Amodio
2021-04-08 19:24:53 -04:00
parent 852375649c
commit 3622dafdc0
7 changed files with 94 additions and 7 deletions
+11 -1
View File
@@ -727,11 +727,21 @@ declare module 'vscode' {
*/
export interface SourceControlInputBox {
/**
* Sets focus to the input.
*/
focus(): void;
/**
* Shows a transient contextual message on the input.
*/
showValidationMessage(message: string, type: SourceControlInputBoxValidationType): void;
/**
* A validation function for the input box. It's possible to change
* the validation provider simply by setting this property to a different function.
*/
validateInput?(value: string, cursorPosition: number): ProviderResult<SourceControlInputBoxValidation | undefined | null>;
validateInput?(value: string, cursorPosition: number): ProviderResult<SourceControlInputBoxValidation>;
}
//#endregion
+19 -1
View File
@@ -6,7 +6,7 @@
import { URI, UriComponents } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation, ISCMViewService } from 'vs/workbench/contrib/scm/common/scm';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation, ISCMViewService, InputValidationType } from 'vs/workbench/contrib/scm/common/scm';
import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../common/extHost.protocol';
import { Command } from 'vs/editor/common/modes';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
@@ -424,6 +424,24 @@ export class MainThreadSCM implements MainThreadSCMShape {
repository.input.visible = visible;
}
$setInputBoxFocus(sourceControlHandle: number): void {
const repository = this._repositories.get(sourceControlHandle);
if (!repository) {
return;
}
repository.input.setFocus();
}
$showValidationMessage(sourceControlHandle: number, message: string, type: InputValidationType) {
const repository = this._repositories.get(sourceControlHandle);
if (!repository) {
return;
}
repository.input.showValidationMessage(message, type);
}
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void {
const repository = this._repositories.get(sourceControlHandle);
@@ -62,6 +62,7 @@ import { WorkspaceTrustRequestOptions, WorkspaceTrustStateChangeEvent } from 'vs
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError } from 'vs/platform/terminal/common/terminal';
import { ITerminalProfile } from 'vs/workbench/contrib/terminal/common/terminal';
import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
@@ -1037,6 +1038,8 @@ export interface MainThreadSCMShape extends IDisposable {
$setInputBoxValue(sourceControlHandle: number, value: string): void;
$setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void;
$setInputBoxVisibility(sourceControlHandle: number, visible: boolean): void;
$setInputBoxFocus(sourceControlHandle: number): void;
$showValidationMessage(sourceControlHandle: number, message: string, type: InputValidationType): void;
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void;
}
+12
View File
@@ -259,6 +259,18 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox {
// noop
}
focus(): void {
if (!this._visible) {
this.visible = true;
}
this._proxy.$setInputBoxFocus(this._sourceControlHandle);
}
showValidationMessage(message: string, type: vscode.SourceControlInputBoxValidationType) {
this._proxy.$showValidationMessage(this._sourceControlHandle, message, type as any);
}
$onInputBoxValueChange(value: string): void {
this.updateValue(value);
}
@@ -1438,6 +1438,11 @@ registerAction2(CollapseAllRepositoriesAction);
registerAction2(ExpandAllRepositoriesAction);
class SCMInputWidget extends Disposable {
private static readonly ValidationTimeouts: { [severity: number]: number } = {
[InputValidationType.Information]: 15000,
[InputValidationType.Warning]: 18000,
[InputValidationType.Error]: 20000
};
private readonly defaultInputFontFamily = DEFAULT_FONT_FAMILY;
@@ -1452,6 +1457,7 @@ class SCMInputWidget extends Disposable {
private validation: IInputValidation | undefined;
private validationDisposable: IDisposable = Disposable.None;
private _validationTimer: any;
// This is due to "Setup height change listener on next tick" above
// https://github.com/microsoft/vscode/issues/108067
@@ -1509,8 +1515,7 @@ class SCMInputWidget extends Disposable {
const offset = position && textModel.getOffsetAt(position);
const value = textModel.getValue();
this.validation = await input.validateInput(value, offset || 0);
this.renderValidation();
this.setValidation(await input.validateInput(value, offset || 0));
};
const triggerValidation = () => validationDelayer.trigger(validate);
@@ -1536,6 +1541,8 @@ class SCMInputWidget extends Disposable {
this.inputEditor.setPosition(position);
this.inputEditor.revealPositionInCenterIfOutsideViewport(position);
}));
this.repositoryDisposables.add(input.onDidChangeFocus(() => this.inputEditor.focus()));
this.repositoryDisposables.add(input.onDidChangeValidationMessage((e) => this.setValidation(e, { focus: true, timeout: true })));
// Keep API in sync with model, update placeholder visibility and validate
const updatePlaceholderVisibility = () => this.placeholderTextContainer.classList.toggle('hidden', textModel.getValueLength() > 0);
@@ -1594,6 +1601,23 @@ class SCMInputWidget extends Disposable {
}
}
private setValidation(validation: IInputValidation | undefined, options?: { focus?: boolean; timeout?: boolean }) {
if (this._validationTimer) {
clearTimeout(this._validationTimer);
this._validationTimer = 0;
}
this.validation = validation;
if (options?.focus) {
this.inputEditor.focus();
}
this.renderValidation();
if (validation && options?.timeout) {
this._validationTimer = setTimeout(() => this.setValidation(undefined), SCMInputWidget.ValidationTimeouts[validation.type]);
}
}
constructor(
container: HTMLElement,
overflowWidgetsDomNode: HTMLElement,
@@ -110,6 +110,12 @@ export interface ISCMInput {
visible: boolean;
readonly onDidChangeVisibility: Event<boolean>;
setFocus(): void;
readonly onDidChangeFocus: Event<void>;
showValidationMessage(message: string, type: InputValidationType): void;
readonly onDidChangeValidationMessage: Event<IInputValidation>;
showNextHistoryValue(): void;
showPreviousHistoryValue(): void;
}
@@ -5,7 +5,7 @@
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import { ISCMService, ISCMProvider, ISCMInput, ISCMRepository, IInputValidator, ISCMInputChangeEvent, SCMInputChangeReason } from './scm';
import { ISCMService, ISCMProvider, ISCMInput, ISCMRepository, IInputValidator, ISCMInputChangeEvent, SCMInputChangeReason, InputValidationType, IInputValidation } from './scm';
import { ILogService } from 'vs/platform/log/common/log';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
@@ -48,8 +48,22 @@ class SCMInput implements ISCMInput {
}
private readonly _onDidChangeVisibility = new Emitter<boolean>();
readonly onDidChangeVisibility: Event<boolean> = this._onDidChangeVisibility
.event;
readonly onDidChangeVisibility: Event<boolean> = this._onDidChangeVisibility.event;
setFocus(): void {
this._onDidChangeFocus.fire();
}
private readonly _onDidChangeFocus = new Emitter<void>();
readonly onDidChangeFocus: Event<void> = this._onDidChangeFocus.event;
showValidationMessage(message: string, type: InputValidationType): void {
this._onDidChangeValidationMessage.fire({ message: message, type: type });
}
private readonly _onDidChangeValidationMessage = new Emitter<IInputValidation>();
readonly onDidChangeValidationMessage: Event<IInputValidation> = this._onDidChangeValidationMessage.event;
private _validateInput: IInputValidator = () => Promise.resolve(undefined);