mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
lineWarningLength -> validationProvider
This commit is contained in:
parent
786ea020f7
commit
888f74495d
|
@ -946,6 +946,16 @@
|
|||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%config.showInlineOpenFileAction%"
|
||||
},
|
||||
"git.inputValidation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"always",
|
||||
"warn",
|
||||
"off"
|
||||
],
|
||||
"default": "warn",
|
||||
"description": "%config.inputValidation%"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
"config.decorations.enabled": "Controls if Git contributes colors and badges to the explorer and the open editors view.",
|
||||
"config.promptToSaveFilesBeforeCommit": "Controls whether Git should check for unsaved files before committing.",
|
||||
"config.showInlineOpenFileAction": "Controls whether to show an inline Open File action in the Git changes view.",
|
||||
"config.inputValidation": "Controls when to show input validation the input counter.",
|
||||
"colors.modified": "Color for modified resources.",
|
||||
"colors.deleted": "Color for deleted resources.",
|
||||
"colors.untracked": "Color for untracked resources.",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento } from 'vscode';
|
||||
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType } from 'vscode';
|
||||
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError, Submodule, DiffOptions } from './git';
|
||||
import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent } from './util';
|
||||
import { memoize, throttle, debounce } from './decorators';
|
||||
|
@ -419,6 +419,8 @@ class ProgressManager {
|
|||
|
||||
export class Repository implements Disposable {
|
||||
|
||||
private static readonly InputValidationLength = 72;
|
||||
|
||||
private _onDidChangeRepository = new EventEmitter<Uri>();
|
||||
readonly onDidChangeRepository: Event<Uri> = this._onDidChangeRepository.event;
|
||||
|
||||
|
@ -521,7 +523,7 @@ export class Repository implements Disposable {
|
|||
this._sourceControl.inputBox.placeholder = localize('commitMessage', "Message (press {0} to commit)");
|
||||
this._sourceControl.acceptInputCommand = { command: 'git.commitWithInput', title: localize('commit', "Commit"), arguments: [this._sourceControl] };
|
||||
this._sourceControl.quickDiffProvider = this;
|
||||
this._sourceControl.inputBox.lineWarningLength = 72;
|
||||
this._sourceControl.inputBox.validationProvider = this;
|
||||
this.disposables.push(this._sourceControl);
|
||||
|
||||
this._mergeGroup = this._sourceControl.createResourceGroup('merge', localize('merge changes', "Merge Changes"));
|
||||
|
@ -549,6 +551,43 @@ export class Repository implements Disposable {
|
|||
this.status();
|
||||
}
|
||||
|
||||
validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const setting = config.get<'always' | 'warn' | 'off'>('inputValidation');
|
||||
|
||||
if (setting === 'off') {
|
||||
return;
|
||||
}
|
||||
|
||||
let start = 0, end;
|
||||
let match: RegExpExecArray | null;
|
||||
const regex = /\r?\n/g;
|
||||
|
||||
while ((match = regex.exec(text)) && position > match.index) {
|
||||
start = match.index + match[0].length;
|
||||
}
|
||||
|
||||
end = match ? match.index : text.length;
|
||||
|
||||
const line = text.substring(start, end);
|
||||
|
||||
if (line.length <= Repository.InputValidationLength) {
|
||||
if (setting !== 'always') {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
message: localize('commitMessageCountdown', "{0} characters left in current line", Repository.InputValidationLength - line.length),
|
||||
type: SourceControlInputBoxValidationType.Information
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
message: localize('commitMessageWarning', "{0} characters over {1} in current line", line.length - Repository.InputValidationLength, Repository.InputValidationLength),
|
||||
type: SourceControlInputBoxValidationType.Warning
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
provideOriginalResource(uri: Uri): Uri | undefined {
|
||||
if (uri.scheme !== 'file') {
|
||||
return;
|
||||
|
|
55
src/vs/vscode.d.ts
vendored
55
src/vs/vscode.d.ts
vendored
|
@ -5986,6 +5986,56 @@ declare module 'vscode' {
|
|||
export function setLanguageConfiguration(language: string, configuration: LanguageConfiguration): Disposable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the validation type of the Source Control input.
|
||||
*/
|
||||
export enum SourceControlInputBoxValidationType {
|
||||
|
||||
/**
|
||||
* Something not allowed by the rules of a language or other means.
|
||||
*/
|
||||
Error = 0,
|
||||
|
||||
/**
|
||||
* Something suspicious but allowed.
|
||||
*/
|
||||
Warning = 1,
|
||||
|
||||
/**
|
||||
* Something to inform about but not a problem.
|
||||
*/
|
||||
Information = 2
|
||||
}
|
||||
|
||||
export interface SourceControlInputBoxValidation {
|
||||
|
||||
/**
|
||||
* The validation message to display.
|
||||
*/
|
||||
readonly message: string;
|
||||
|
||||
/**
|
||||
* The validation type.
|
||||
*/
|
||||
readonly type: SourceControlInputBoxValidationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* A validation provider which can validate Source Control input.
|
||||
*/
|
||||
export interface SourceControlInputBoxValidationProvider {
|
||||
|
||||
/**
|
||||
* A function that will be called to validate input and give a hint to the user.
|
||||
*
|
||||
* @param value The current value of the input box.
|
||||
* @param cursorPosition The cusror position within the input box.
|
||||
* @return A human readable string which is presented as diagnostic message.
|
||||
* Return `undefined`, `null`, or the empty string when 'value' is valid.
|
||||
*/
|
||||
validateInput(value: string, cursorPosition: number): ProviderResult<SourceControlInputBoxValidation | undefined | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the input box in the Source Control viewlet.
|
||||
*/
|
||||
|
@ -6002,9 +6052,10 @@ declare module 'vscode' {
|
|||
placeholder: string;
|
||||
|
||||
/**
|
||||
* The warning threshold for lines in the input box.
|
||||
* A validation provider for the input box. It's possible to change
|
||||
* the validation provider simply by setting this property to a different value.
|
||||
*/
|
||||
lineWarningLength: number | undefined;
|
||||
validationProvider: SourceControlInputBoxValidationProvider;
|
||||
}
|
||||
|
||||
interface QuickDiffProvider {
|
||||
|
|
|
@ -10,7 +10,7 @@ import URI from 'vs/base/common/uri';
|
|||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations } from 'vs/workbench/services/scm/common/scm';
|
||||
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation } from 'vs/workbench/services/scm/common/scm';
|
||||
import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { Command } from 'vs/editor/common/modes';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
|
@ -393,13 +393,28 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
|||
repository.input.placeholder = placeholder;
|
||||
}
|
||||
|
||||
$setLineWarningLength(sourceControlHandle: number, lineWarningLength: number): void {
|
||||
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
}
|
||||
|
||||
repository.input.lineWarningLength = lineWarningLength;
|
||||
if (enabled) {
|
||||
repository.input.validateInput = async (value, pos): TPromise<IInputValidation | undefined> => {
|
||||
const result = await this._proxy.$validateInput(sourceControlHandle, value, pos);
|
||||
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
message: result[0],
|
||||
type: result[1]
|
||||
};
|
||||
};
|
||||
} else {
|
||||
repository.input.validateInput = () => TPromise.as(undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -601,6 +601,7 @@ export function createApiFactory(
|
|||
StatusBarAlignment: extHostTypes.StatusBarAlignment,
|
||||
SymbolInformation: extHostTypes.SymbolInformation,
|
||||
SymbolKind: extHostTypes.SymbolKind,
|
||||
SourceControlInputBoxValidationType: extHostTypes.SourceControlInputBoxValidationType,
|
||||
TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason,
|
||||
TextEdit: extHostTypes.TextEdit,
|
||||
TextEditorCursorStyle: TextEditorCursorStyle,
|
||||
|
|
|
@ -431,7 +431,7 @@ export interface MainThreadSCMShape extends IDisposable {
|
|||
|
||||
$setInputBoxValue(sourceControlHandle: number, value: string): void;
|
||||
$setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void;
|
||||
$setLineWarningLength(sourceControlHandle: number, lineWarningLength: number): void;
|
||||
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void;
|
||||
}
|
||||
|
||||
export type DebugSessionUUID = string;
|
||||
|
@ -693,6 +693,7 @@ export interface ExtHostSCMShape {
|
|||
$provideOriginalResource(sourceControlHandle: number, uri: string): TPromise<string>;
|
||||
$onInputBoxValueChange(sourceControlHandle: number, value: string): TPromise<void>;
|
||||
$executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): TPromise<void>;
|
||||
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): TPromise<[string, number] | undefined>;
|
||||
}
|
||||
|
||||
export interface ExtHostTaskShape {
|
||||
|
|
|
@ -140,15 +140,20 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox {
|
|||
this._placeholder = placeholder;
|
||||
}
|
||||
|
||||
private _lineWarningLength: number | undefined;
|
||||
private _validationProvider: vscode.SourceControlInputBoxValidationProvider;
|
||||
|
||||
get lineWarningLength(): number | undefined {
|
||||
return this._lineWarningLength;
|
||||
get validationProvider(): vscode.SourceControlInputBoxValidationProvider {
|
||||
return this._validationProvider;
|
||||
}
|
||||
|
||||
set lineWarningLength(lineWarningLength: number) {
|
||||
this._proxy.$setLineWarningLength(this._sourceControlHandle, lineWarningLength);
|
||||
this._lineWarningLength = lineWarningLength;
|
||||
set validationProvider(provider: vscode.SourceControlInputBoxValidationProvider) {
|
||||
if (!provider || typeof provider.validateInput !== 'function') {
|
||||
console.warn('INVALID SCM input box validation provider');
|
||||
return;
|
||||
}
|
||||
|
||||
this._validationProvider = provider;
|
||||
this._proxy.$setValidationProviderIsEnabled(this._sourceControlHandle, true);
|
||||
}
|
||||
|
||||
constructor(private _proxy: MainThreadSCMShape, private _sourceControlHandle: number) {
|
||||
|
@ -567,4 +572,22 @@ export class ExtHostSCM implements ExtHostSCMShape {
|
|||
|
||||
await group.$executeResourceCommand(handle);
|
||||
}
|
||||
|
||||
async $validateInput(sourceControlHandle: number, value: string, cursorPosition: number): TPromise<[string, number] | undefined> {
|
||||
this.logService.trace('ExtHostSCM#$validateInput', sourceControlHandle);
|
||||
|
||||
const sourceControl = this._sourceControls.get(sourceControlHandle);
|
||||
|
||||
if (!sourceControl) {
|
||||
return TPromise.as(undefined);
|
||||
}
|
||||
|
||||
const result = await sourceControl.inputBox.validationProvider.validateInput(value, cursorPosition);
|
||||
|
||||
if (!result) {
|
||||
return TPromise.as(undefined);
|
||||
}
|
||||
|
||||
return [result.message, result.type];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1200,6 +1200,12 @@ export enum ColorFormat {
|
|||
HSL = 2
|
||||
}
|
||||
|
||||
export enum SourceControlInputBoxValidationType {
|
||||
Error = 0,
|
||||
Warning = 1,
|
||||
Information = 2
|
||||
}
|
||||
|
||||
export enum TaskRevealKind {
|
||||
Always = 1,
|
||||
|
||||
|
|
|
@ -79,12 +79,6 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
|
|||
enum: ['all', 'gutter', 'overview', 'none'],
|
||||
default: 'all',
|
||||
description: localize('diffDecorations', "Controls diff decorations in the editor.")
|
||||
},
|
||||
'scm.inputCounter': {
|
||||
type: 'string',
|
||||
enum: ['always', 'warn', 'off'],
|
||||
default: 'warn',
|
||||
description: localize('inputCounter', "Controls when to display the input counter.")
|
||||
}
|
||||
}
|
||||
});
|
|
@ -22,7 +22,7 @@ import { IDelegate, IRenderer, IListContextMenuEvent, IListEvent } from 'vs/base
|
|||
import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm';
|
||||
import { FileLabel } from 'vs/workbench/browser/labels';
|
||||
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
|
||||
import { ISCMService, ISCMRepository, ISCMResourceGroup, ISCMResource } from 'vs/workbench/services/scm/common/scm';
|
||||
import { ISCMService, ISCMRepository, ISCMResourceGroup, ISCMResource, InputValidationType } from 'vs/workbench/services/scm/common/scm';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
@ -45,7 +45,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
|
|||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions';
|
||||
import { IMessage, InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Command } from 'vs/editor/common/modes';
|
||||
|
@ -57,6 +57,7 @@ import { ISpliceable, ISequence, ISplice } from 'vs/base/common/sequence';
|
|||
import { firstIndex } from 'vs/base/common/arrays';
|
||||
import { WorkbenchList } from 'vs/platform/list/browser/listService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ThrottledDelayer } from 'vs/base/common/async';
|
||||
|
||||
// TODO@Joao
|
||||
// Need to subclass MenuItemActionItem in order to respect
|
||||
|
@ -684,6 +685,14 @@ class ResourceGroupSplicer {
|
|||
}
|
||||
}
|
||||
|
||||
function convertValidationType(type: InputValidationType): MessageType {
|
||||
switch (type) {
|
||||
case InputValidationType.Information: return MessageType.INFO;
|
||||
case InputValidationType.Warning: return MessageType.WARNING;
|
||||
case InputValidationType.Error: return MessageType.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
export class RepositoryPanel extends ViewletPanel {
|
||||
|
||||
private cachedHeight: number | undefined = undefined;
|
||||
|
@ -764,62 +773,31 @@ export class RepositoryPanel extends ViewletPanel {
|
|||
this.inputBox.setPlaceHolder(placeholder);
|
||||
};
|
||||
|
||||
const validation = (text: string): IMessage => {
|
||||
const setting = this.configurationService.getValue<'always' | 'warn' | 'off'>('scm.inputCounter');
|
||||
const validationDelayer = new ThrottledDelayer(200);
|
||||
|
||||
if (setting === 'off') {
|
||||
return null;
|
||||
}
|
||||
const validate = () => {
|
||||
validationDelayer.trigger(async (): TPromise<any> => {
|
||||
const result = await this.repository.input.validateInput(this.inputBox.value, this.inputBox.inputElement.selectionStart);
|
||||
|
||||
let position = this.inputBox.inputElement.selectionStart;
|
||||
let start = 0, end;
|
||||
let match: RegExpExecArray;
|
||||
const regex = /\r?\n/g;
|
||||
|
||||
while ((match = regex.exec(text)) && position > match.index) {
|
||||
start = match.index + match[0].length;
|
||||
}
|
||||
|
||||
end = match ? match.index : text.length;
|
||||
|
||||
const line = text.substring(start, end);
|
||||
|
||||
const lineWarningLength = this.repository.input.lineWarningLength;
|
||||
|
||||
if (lineWarningLength === undefined) {
|
||||
return {
|
||||
content: localize('commitMessageInfo', "{0} characters in current line", text.length),
|
||||
type: MessageType.INFO
|
||||
};
|
||||
}
|
||||
|
||||
if (line.length <= lineWarningLength) {
|
||||
if (setting !== 'always') {
|
||||
return null;
|
||||
if (!result) {
|
||||
this.inputBox.inputElement.removeAttribute('aria-invalid');
|
||||
this.inputBox.hideMessage();
|
||||
} else {
|
||||
this.inputBox.inputElement.setAttribute('aria-invalid', 'true');
|
||||
this.inputBox.showMessage({ content: result.message, type: convertValidationType(result.type) });
|
||||
}
|
||||
|
||||
return {
|
||||
content: localize('commitMessageCountdown', "{0} characters left in current line", lineWarningLength - line.length),
|
||||
type: MessageType.INFO
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
content: localize('commitMessageWarning', "{0} characters over {1} in current line", line.length - lineWarningLength, lineWarningLength),
|
||||
type: MessageType.WARNING
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, {
|
||||
flexibleHeight: true,
|
||||
validationOptions: { validation: validation }
|
||||
});
|
||||
this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, { flexibleHeight: true });
|
||||
this.disposables.push(attachInputBoxStyler(this.inputBox, this.themeService));
|
||||
this.disposables.push(this.inputBox);
|
||||
|
||||
this.inputBox.onDidChange(validate, null, this.disposables);
|
||||
|
||||
const onKeyUp = domEvent(this.inputBox.inputElement, 'keyup');
|
||||
const onMouseUp = domEvent(this.inputBox.inputElement, 'mouseup');
|
||||
anyEvent<any>(onKeyUp, onMouseUp)(() => this.inputBox.validate(), null, this.disposables);
|
||||
anyEvent<any>(onKeyUp, onMouseUp)(() => validate(), null, this.disposables);
|
||||
|
||||
this.inputBox.value = this.repository.input.value;
|
||||
this.inputBox.onDidChange(value => this.repository.input.value = value, null, this.disposables);
|
||||
|
|
|
@ -68,6 +68,21 @@ export interface ISCMProvider extends IDisposable {
|
|||
getOriginalResource(uri: URI): TPromise<URI>;
|
||||
}
|
||||
|
||||
export enum InputValidationType {
|
||||
Error = 0,
|
||||
Warning = 1,
|
||||
Information = 2
|
||||
}
|
||||
|
||||
export interface IInputValidation {
|
||||
message: string;
|
||||
type: InputValidationType;
|
||||
}
|
||||
|
||||
export interface IInputValidator {
|
||||
(value: string, cursorPosition: number): TPromise<IInputValidation | undefined>;
|
||||
}
|
||||
|
||||
export interface ISCMInput {
|
||||
value: string;
|
||||
readonly onDidChange: Event<string>;
|
||||
|
@ -75,7 +90,8 @@ export interface ISCMInput {
|
|||
placeholder: string;
|
||||
readonly onDidChangePlaceholder: Event<string>;
|
||||
|
||||
lineWarningLength: number | undefined;
|
||||
validateInput: IInputValidator;
|
||||
readonly onDidChangeValidateInput: Event<void>;
|
||||
}
|
||||
|
||||
export interface ISCMRepository extends IDisposable {
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { ISCMService, ISCMProvider, ISCMInput, ISCMRepository } from './scm';
|
||||
import { ISCMService, ISCMProvider, ISCMInput, ISCMRepository, IInputValidator } from './scm';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
|
||||
class SCMInput implements ISCMInput {
|
||||
|
||||
|
@ -40,7 +41,19 @@ class SCMInput implements ISCMInput {
|
|||
private _onDidChangePlaceholder = new Emitter<string>();
|
||||
get onDidChangePlaceholder(): Event<string> { return this._onDidChangePlaceholder.event; }
|
||||
|
||||
public lineWarningLength: number | undefined = undefined;
|
||||
private _validateInput: IInputValidator = () => TPromise.as(undefined);
|
||||
|
||||
get validateInput(): IInputValidator {
|
||||
return this._validateInput;
|
||||
}
|
||||
|
||||
set validateInput(validateInput: IInputValidator) {
|
||||
this._validateInput = validateInput;
|
||||
this._onDidChangeValidateInput.fire();
|
||||
}
|
||||
|
||||
private _onDidChangeValidateInput = new Emitter<void>();
|
||||
get onDidChangeValidateInput(): Event<void> { return this._onDidChangeValidateInput.event; }
|
||||
}
|
||||
|
||||
class SCMRepository implements ISCMRepository {
|
||||
|
|
Loading…
Reference in a new issue