mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-30 16:50:30 -04:00
Merge from vscode 1b314ab317fbff7d799b21754326b7d849889ceb
This commit is contained in:
@@ -48,6 +48,8 @@ import { ISplice } from 'vs/base/common/sequence';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { createStyleSheet } from 'vs/base/browser/dom';
|
||||
import { ITextFileEditorModel, IResolvedTextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { EncodingMode } from 'vs/workbench/common/editor';
|
||||
|
||||
class DiffActionRunner extends ActionRunner {
|
||||
|
||||
@@ -1012,14 +1014,16 @@ function createProviderComparer(uri: URI): (a: ISCMProvider, b: ISCMProvider) =>
|
||||
|
||||
export class DirtyDiffModel extends Disposable {
|
||||
|
||||
private _originalModel: ITextModel | null = null;
|
||||
get original(): ITextModel | null { return this._originalModel; }
|
||||
get modified(): ITextModel | null { return this._editorModel; }
|
||||
private _originalModel: IResolvedTextFileEditorModel | null = null;
|
||||
private _model: ITextFileEditorModel;
|
||||
get original(): ITextModel | null { return this._originalModel?.textEditorModel || null; }
|
||||
get modified(): ITextModel | null { return this._model.textEditorModel || null; }
|
||||
|
||||
private diffDelayer: ThrottledDelayer<IChange[] | null> | null;
|
||||
private diffDelayer = new ThrottledDelayer<IChange[] | null>(200);
|
||||
private _originalURIPromise?: Promise<URI | null>;
|
||||
private repositoryDisposables = new Set<IDisposable>();
|
||||
private readonly originalModelDisposables = this._register(new DisposableStore());
|
||||
private _disposed = false;
|
||||
|
||||
private readonly _onDidChange = new Emitter<{ changes: IChange[], diff: ISplice<IChange>[] }>();
|
||||
readonly onDidChange: Event<{ changes: IChange[], diff: ISplice<IChange>[] }> = this._onDidChange.event;
|
||||
@@ -1027,22 +1031,27 @@ export class DirtyDiffModel extends Disposable {
|
||||
private _changes: IChange[] = [];
|
||||
get changes(): IChange[] { return this._changes; }
|
||||
|
||||
private _editorModel: ITextModel | null;
|
||||
|
||||
constructor(
|
||||
editorModel: ITextModel,
|
||||
textFileModel: IResolvedTextFileEditorModel,
|
||||
@ISCMService private readonly scmService: ISCMService,
|
||||
@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService,
|
||||
@ITextModelService private readonly textModelResolverService: ITextModelService
|
||||
) {
|
||||
super();
|
||||
this._editorModel = editorModel;
|
||||
this.diffDelayer = new ThrottledDelayer<IChange[]>(200);
|
||||
this._model = textFileModel;
|
||||
|
||||
this._register(editorModel.onDidChangeContent(() => this.triggerDiff()));
|
||||
this._register(textFileModel.textEditorModel.onDidChangeContent(() => this.triggerDiff()));
|
||||
this._register(scmService.onDidAddRepository(this.onDidAddRepository, this));
|
||||
scmService.repositories.forEach(r => this.onDidAddRepository(r));
|
||||
|
||||
this._register(this._model.onDidChangeEncoding(() => {
|
||||
this.diffDelayer.cancel();
|
||||
this._originalModel = null;
|
||||
this._originalURIPromise = undefined;
|
||||
this.setChanges([]);
|
||||
this.triggerDiff();
|
||||
}));
|
||||
|
||||
this.triggerDiff();
|
||||
}
|
||||
|
||||
@@ -1069,11 +1078,11 @@ export class DirtyDiffModel extends Disposable {
|
||||
return this.diffDelayer
|
||||
.trigger(() => this.diff())
|
||||
.then((changes: IChange[] | null) => {
|
||||
if (!this._editorModel || this._editorModel.isDisposed() || !this._originalModel || this._originalModel.isDisposed()) {
|
||||
if (this._disposed || this._model.isDisposed() || !this._originalModel || this._originalModel.isDisposed()) {
|
||||
return; // disposed
|
||||
}
|
||||
|
||||
if (this._originalModel.getValueLength() === 0) {
|
||||
if (this._originalModel.textEditorModel.getValueLength() === 0) {
|
||||
changes = [];
|
||||
}
|
||||
|
||||
@@ -1081,23 +1090,27 @@ export class DirtyDiffModel extends Disposable {
|
||||
changes = [];
|
||||
}
|
||||
|
||||
const diff = sortedDiff(this._changes, changes, compareChanges);
|
||||
this._changes = changes;
|
||||
this._onDidChange.fire({ changes, diff });
|
||||
this.setChanges(changes);
|
||||
});
|
||||
}
|
||||
|
||||
private setChanges(changes: IChange[]): void {
|
||||
const diff = sortedDiff(this._changes, changes, compareChanges);
|
||||
this._changes = changes;
|
||||
this._onDidChange.fire({ changes, diff });
|
||||
}
|
||||
|
||||
private diff(): Promise<IChange[] | null> {
|
||||
return this.getOriginalURIPromise().then(originalURI => {
|
||||
if (!this._editorModel || this._editorModel.isDisposed() || !originalURI) {
|
||||
if (this._disposed || this._model.isDisposed() || !originalURI) {
|
||||
return Promise.resolve([]); // disposed
|
||||
}
|
||||
|
||||
if (!this.editorWorkerService.canComputeDirtyDiff(originalURI, this._editorModel.uri)) {
|
||||
if (!this.editorWorkerService.canComputeDirtyDiff(originalURI, this._model.resource)) {
|
||||
return Promise.resolve([]); // Files too large
|
||||
}
|
||||
|
||||
return this.editorWorkerService.computeDirtyDiff(originalURI, this._editorModel.uri, false);
|
||||
return this.editorWorkerService.computeDirtyDiff(originalURI, this._model.resource, false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1107,7 +1120,7 @@ export class DirtyDiffModel extends Disposable {
|
||||
}
|
||||
|
||||
this._originalURIPromise = this.getOriginalResource().then(originalUri => {
|
||||
if (!this._editorModel) { // disposed
|
||||
if (this._disposed) { // disposed
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1116,17 +1129,23 @@ export class DirtyDiffModel extends Disposable {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this._originalModel && this._originalModel.uri.toString() === originalUri.toString()) {
|
||||
if (this._originalModel && this._originalModel.resource.toString() === originalUri.toString()) {
|
||||
return originalUri;
|
||||
}
|
||||
|
||||
return this.textModelResolverService.createModelReference(originalUri).then(ref => {
|
||||
if (!this._editorModel) { // disposed
|
||||
if (this._disposed) { // disposed
|
||||
ref.dispose();
|
||||
return null;
|
||||
}
|
||||
|
||||
this._originalModel = ref.object.textEditorModel;
|
||||
this._originalModel = ref.object as IResolvedTextFileEditorModel;
|
||||
|
||||
const encoding = this._model.getEncoding();
|
||||
|
||||
if (encoding) {
|
||||
this._originalModel.setEncoding(encoding, EncodingMode.Decode);
|
||||
}
|
||||
|
||||
this.originalModelDisposables.clear();
|
||||
this.originalModelDisposables.add(ref);
|
||||
@@ -1144,11 +1163,11 @@ export class DirtyDiffModel extends Disposable {
|
||||
}
|
||||
|
||||
private async getOriginalResource(): Promise<URI | null> {
|
||||
if (!this._editorModel) {
|
||||
if (this._disposed) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
const uri = this._editorModel.uri;
|
||||
const uri = this._model.resource;
|
||||
const providers = this.scmService.repositories.map(r => r.provider);
|
||||
const rootedProviders = providers.filter(p => !!p.rootUri);
|
||||
|
||||
@@ -1203,14 +1222,9 @@ export class DirtyDiffModel extends Disposable {
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this._editorModel = null;
|
||||
this._disposed = true;
|
||||
this._originalModel = null;
|
||||
|
||||
if (this.diffDelayer) {
|
||||
this.diffDelayer.cancel();
|
||||
this.diffDelayer = null;
|
||||
}
|
||||
|
||||
this.diffDelayer.cancel();
|
||||
this.repositoryDisposables.forEach(d => dispose(d));
|
||||
this.repositoryDisposables.clear();
|
||||
}
|
||||
@@ -1235,15 +1249,15 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor
|
||||
|
||||
private enabled = false;
|
||||
private viewState: IViewState = { width: 3, visibility: 'always' };
|
||||
private models: ITextModel[] = [];
|
||||
private items: { [modelId: string]: DirtyDiffItem; } = Object.create(null);
|
||||
private items = new Map<IResolvedTextFileEditorModel, DirtyDiffItem>();
|
||||
private readonly transientDisposables = this._register(new DisposableStore());
|
||||
private stylesheet: HTMLStyleElement;
|
||||
|
||||
constructor(
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService
|
||||
) {
|
||||
super();
|
||||
this.stylesheet = createStyleSheet();
|
||||
@@ -1313,9 +1327,12 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor
|
||||
}
|
||||
|
||||
this.transientDisposables.clear();
|
||||
this.models.forEach(m => this.items[m.id].dispose());
|
||||
this.models = [];
|
||||
this.items = Object.create(null);
|
||||
|
||||
for (const [, dirtyDiff] of this.items) {
|
||||
dirtyDiff.dispose();
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
this.enabled = false;
|
||||
}
|
||||
|
||||
@@ -1337,37 +1354,39 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor
|
||||
})
|
||||
|
||||
// remove nulls and duplicates
|
||||
.filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1) as ITextModel[];
|
||||
.filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1)
|
||||
|
||||
const newModels = models.filter(o => this.models.every(m => o !== m));
|
||||
const oldModels = this.models.filter(m => models.every(o => o !== m));
|
||||
// only want resolved text file service models
|
||||
.map(m => this.textFileService.files.get(m!.uri))
|
||||
.filter(m => m?.isResolved()) as IResolvedTextFileEditorModel[];
|
||||
|
||||
const set = new Set(models);
|
||||
const newModels = models.filter(o => !this.items.has(o));
|
||||
const oldModels = [...this.items.keys()].filter(m => !set.has(m));
|
||||
|
||||
oldModels.forEach(m => this.onModelInvisible(m));
|
||||
newModels.forEach(m => this.onModelVisible(m));
|
||||
|
||||
this.models = models;
|
||||
}
|
||||
|
||||
private onModelVisible(editorModel: ITextModel): void {
|
||||
const model = this.instantiationService.createInstance(DirtyDiffModel, editorModel);
|
||||
const decorator = new DirtyDiffDecorator(editorModel, model, this.configurationService);
|
||||
|
||||
this.items[editorModel.id] = new DirtyDiffItem(model, decorator);
|
||||
private onModelVisible(textFileModel: IResolvedTextFileEditorModel): void {
|
||||
const model = this.instantiationService.createInstance(DirtyDiffModel, textFileModel);
|
||||
const decorator = new DirtyDiffDecorator(textFileModel.textEditorModel, model, this.configurationService);
|
||||
this.items.set(textFileModel, new DirtyDiffItem(model, decorator));
|
||||
}
|
||||
|
||||
private onModelInvisible(editorModel: ITextModel): void {
|
||||
this.items[editorModel.id].dispose();
|
||||
delete this.items[editorModel.id];
|
||||
private onModelInvisible(textFileModel: IResolvedTextFileEditorModel): void {
|
||||
this.items.get(textFileModel)!.dispose();
|
||||
this.items.delete(textFileModel);
|
||||
}
|
||||
|
||||
getModel(editorModel: ITextModel): DirtyDiffModel | null {
|
||||
const item = this.items[editorModel.id];
|
||||
|
||||
if (!item) {
|
||||
return null;
|
||||
for (const [model, diff] of this.items) {
|
||||
if (model.textEditorModel.id === editorModel.id) {
|
||||
return diff.model;
|
||||
}
|
||||
}
|
||||
|
||||
return item.model;
|
||||
return null;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
|
||||
.scm-view .count {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.scm-view .count {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
@@ -33,12 +30,27 @@
|
||||
flex-flow: nowrap;
|
||||
}
|
||||
|
||||
.scm-view.hide-provider-counts .scm-provider > .count,
|
||||
.scm-view.auto-provider-counts .scm-provider > .count[data-count="0"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scm-view .scm-provider > .label {
|
||||
display: flex;
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scm-view .scm-provider > .label > .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.scm-view .scm-provider > .label > .description {
|
||||
opacity: 0.7;
|
||||
margin-left: 0.5em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.scm-view .scm-provider > .actions {
|
||||
flex: 1;
|
||||
padding-left: 10px;
|
||||
@@ -46,27 +58,30 @@
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.scm-view .scm-provider > .actions .monaco-action-bar .action-item {
|
||||
margin-left: 4px;
|
||||
text-overflow: ellipsis;
|
||||
/**
|
||||
* The following rules are very specific because of inline drop down menus
|
||||
* https://github.com/microsoft/vscode/issues/101410
|
||||
*/
|
||||
.scm-view .scm-provider > .actions > .monaco-toolbar > .monaco-action-bar > .actions-container > .action-item {
|
||||
padding-left: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 14px;
|
||||
min-width: 16px;
|
||||
}
|
||||
|
||||
.scm-view .scm-provider > .actions .monaco-action-bar .action-label {
|
||||
text-overflow: ellipsis;
|
||||
.scm-view .scm-provider > .actions > .monaco-toolbar > .monaco-action-bar > .actions-container > .action-item > .action-label,
|
||||
.scm-view .scm-provider > .actions > .monaco-toolbar > .monaco-action-bar > .actions-container > .action-item > .monaco-dropdown > .dropdown-label > .action-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
min-width: 14px; /* for flex */
|
||||
min-width: 16px; /* for flex */
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.scm-view .scm-provider > .actions .monaco-action-bar .action-label .codicon {
|
||||
vertical-align: sub;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.scm-view .scm-provider > .actions .monaco-action-bar .action-item:last-of-type {
|
||||
.scm-view .scm-provider > .actions > .monaco-toolbar > .monaco-action-bar > .actions-container > .action-item:last-of-type {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,39 +7,24 @@ import { localize } from 'vs/nls';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { DirtyDiffWorkbenchController } from './dirtydiffDecorator';
|
||||
import { ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
||||
import { VIEWLET_ID, ISCMRepository, ISCMService, VIEW_PANE_ID } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { SCMStatusController } from './activity';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { SCMService } from 'vs/workbench/contrib/scm/common/scmService';
|
||||
import { IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry } from 'vs/workbench/common/views';
|
||||
import { IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry, IViewsService } from 'vs/workbench/common/views';
|
||||
import { SCMViewPaneContainer } from 'vs/workbench/contrib/scm/browser/scmViewPaneContainer';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { SCMViewPane } from 'vs/workbench/contrib/scm/browser/scmViewPane';
|
||||
|
||||
class OpenSCMViewletAction extends ShowViewletAction {
|
||||
|
||||
static readonly ID = VIEWLET_ID;
|
||||
static readonly LABEL = localize('toggleSCMViewlet', "Show SCM");
|
||||
|
||||
constructor(id: string, label: string, @IViewletService viewletService: IViewletService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService) {
|
||||
super(id, label, VIEWLET_ID, viewletService, editorGroupService, layoutService);
|
||||
}
|
||||
}
|
||||
|
||||
ModesRegistry.registerLanguage({
|
||||
id: 'scminput',
|
||||
extensions: [],
|
||||
@@ -73,23 +58,32 @@ viewsRegistry.registerViews([{
|
||||
ctorDescriptor: new SyncDescriptor(SCMViewPane),
|
||||
canToggleVisibility: true,
|
||||
workspace: true,
|
||||
canMoveView: true
|
||||
canMoveView: true,
|
||||
containerIcon: Codicon.sourceControl.classNames
|
||||
}], viewContainer);
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
|
||||
.registerWorkbenchContribution(SCMStatusController, LifecyclePhase.Restored);
|
||||
|
||||
// Register Action to Open Viewlet
|
||||
Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction(
|
||||
SyncActionDescriptor.from(OpenSCMViewletAction, {
|
||||
primary: 0,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G },
|
||||
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_G }
|
||||
}),
|
||||
'View: Show SCM',
|
||||
localize('view', "View")
|
||||
);
|
||||
// Register Action to Open View
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: VIEWLET_ID,
|
||||
description: { description: localize('toggleSCMViewlet', "Show SCM"), args: [] },
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: 0,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G },
|
||||
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_G },
|
||||
handler: accessor => {
|
||||
const viewsService = accessor.get(IViewsService);
|
||||
|
||||
if (viewsService.isViewVisible(VIEW_PANE_ID)) {
|
||||
viewsService.closeView(VIEW_PANE_ID);
|
||||
} else {
|
||||
viewsService.openView(VIEW_PANE_ID);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).registerConfiguration({
|
||||
id: 'scm',
|
||||
@@ -136,13 +130,24 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
|
||||
type: 'string',
|
||||
enum: ['all', 'focused', 'off'],
|
||||
enumDescriptions: [
|
||||
localize('scm.countBadge.all', "Show the sum of all Source Control Providers count badges."),
|
||||
localize('scm.countBadge.all', "Show the sum of all Source Control Provider count badges."),
|
||||
localize('scm.countBadge.focused', "Show the count badge of the focused Source Control Provider."),
|
||||
localize('scm.countBadge.off', "Disable the Source Control count badge.")
|
||||
],
|
||||
description: localize('scm.countBadge', "Controls the Source Control count badge."),
|
||||
description: localize('scm.countBadge', "Controls the count badge on the Source Control icon on the Activity Bar."),
|
||||
default: 'all'
|
||||
},
|
||||
'scm.providerCountBadge': {
|
||||
type: 'string',
|
||||
enum: ['hidden', 'auto', 'visible'],
|
||||
enumDescriptions: [
|
||||
localize('scm.providerCountBadge.hidden', "Hide Source Control Provider count badges."),
|
||||
localize('scm.providerCountBadge.auto', "Only show count badge for Source Control Provider when non-zero."),
|
||||
localize('scm.providerCountBadge.visible', "Show Source Control Provider count badges.")
|
||||
],
|
||||
description: localize('scm.providerCountBadge', "Controls the count badges on Source Control Provider headers. These headers only appear when there is more than one provider."),
|
||||
default: 'hidden'
|
||||
},
|
||||
'scm.defaultViewMode': {
|
||||
type: 'string',
|
||||
enum: ['tree', 'list'],
|
||||
|
||||
@@ -47,10 +47,10 @@ import { flatten } from 'vs/base/common/arrays';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { SIDE_BAR_BACKGROUND, SIDE_BAR_BORDER, PANEL_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { SIDE_BAR_BACKGROUND, SIDE_BAR_BORDER, PANEL_BACKGROUND, PANEL_INPUT_BORDER } from 'vs/workbench/common/theme';
|
||||
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';
|
||||
import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';
|
||||
@@ -59,7 +59,7 @@ import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEdito
|
||||
import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { escape, compare, format } from 'vs/base/common/strings';
|
||||
import { inputPlaceholderForeground, inputValidationInfoBorder, inputValidationWarningBorder, inputValidationErrorBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationErrorBackground, inputValidationErrorForeground, inputBackground, inputForeground, inputBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { inputPlaceholderForeground, inputValidationInfoBorder, inputValidationWarningBorder, inputValidationErrorBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationErrorBackground, inputValidationErrorForeground, inputBackground, inputForeground, inputBorder, focusBorder, registerColor, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -76,9 +76,11 @@ import { ContextSubMenu } from 'vs/base/browser/contextmenu';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
|
||||
import { Command } from 'vs/editor/common/modes';
|
||||
import { renderCodicons } from 'vs/base/common/codicons';
|
||||
import { renderCodicons, Codicon } from 'vs/base/common/codicons';
|
||||
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
|
||||
type TreeElement = ISCMRepository | ISCMInput | ISCMResourceGroup | IResourceNode<ISCMResource, ISCMResourceGroup> | ISCMResource;
|
||||
|
||||
@@ -151,6 +153,7 @@ interface ISCMLayout {
|
||||
|
||||
interface RepositoryTemplate {
|
||||
readonly name: HTMLElement;
|
||||
readonly description: HTMLElement;
|
||||
readonly countContainer: HTMLElement;
|
||||
readonly count: CountBadge;
|
||||
readonly toolBar: ToolBar;
|
||||
@@ -178,6 +181,7 @@ class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMRepository, Fu
|
||||
const provider = append(container, $('.scm-provider'));
|
||||
const label = append(provider, $('.label'));
|
||||
const name = append(label, $('span.name'));
|
||||
const description = append(label, $('span.description'));
|
||||
const actions = append(provider, $('.actions'));
|
||||
const toolBar = new ToolBar(actions, this.contextMenuService, { actionViewItemProvider: this.actionViewItemProvider });
|
||||
const countContainer = append(provider, $('.count'));
|
||||
@@ -188,7 +192,7 @@ class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMRepository, Fu
|
||||
const disposable = Disposable.None;
|
||||
const templateDisposable = combinedDisposable(visibilityDisposable, toolBar, badgeStyler);
|
||||
|
||||
return { name, countContainer, count, toolBar, disposable, templateDisposable };
|
||||
return { name, description, countContainer, count, toolBar, disposable, templateDisposable };
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<ISCMRepository, FuzzyScore>, index: number, templateData: RepositoryTemplate, height: number | undefined): void {
|
||||
@@ -199,8 +203,10 @@ class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMRepository, Fu
|
||||
|
||||
if (repository.provider.rootUri) {
|
||||
templateData.name.textContent = basename(repository.provider.rootUri);
|
||||
templateData.description.textContent = repository.provider.label;
|
||||
} else {
|
||||
templateData.name.textContent = repository.provider.label;
|
||||
templateData.description.textContent = '';
|
||||
}
|
||||
|
||||
let statusPrimaryActions: IAction[] = [];
|
||||
@@ -216,6 +222,7 @@ class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMRepository, Fu
|
||||
updateToolbar();
|
||||
|
||||
const count = repository.provider.count || 0;
|
||||
templateData.countContainer.setAttribute('data-count', String(count));
|
||||
templateData.count.setCount(count);
|
||||
};
|
||||
disposables.add(repository.provider.onDidChange(onDidChangeProvider, null));
|
||||
@@ -265,6 +272,7 @@ class InputRenderer implements ICompressibleTreeRenderer<ISCMInput, FuzzyScore,
|
||||
constructor(
|
||||
private outerLayout: ISCMLayout,
|
||||
private updateHeight: (input: ISCMInput, height: number) => void,
|
||||
private focusTree: () => void,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
) { }
|
||||
|
||||
@@ -272,10 +280,16 @@ class InputRenderer implements ICompressibleTreeRenderer<ISCMInput, FuzzyScore,
|
||||
// hack
|
||||
addClass(container.parentElement!.parentElement!.querySelector('.monaco-tl-twistie')! as HTMLElement, 'force-no-twistie');
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
const inputElement = append(container, $('.scm-input'));
|
||||
const inputWidget = this.instantiationService.createInstance(SCMInputWidget, inputElement);
|
||||
disposables.add(inputWidget);
|
||||
|
||||
return { inputWidget, disposable: Disposable.None, templateDisposable: inputWidget };
|
||||
const onKeyDown = Event.map(domEvent(container, 'keydown'), e => new StandardKeyboardEvent(e));
|
||||
const onEscape = Event.filter(onKeyDown, e => e.keyCode === KeyCode.Escape);
|
||||
disposables.add(onEscape(this.focusTree));
|
||||
|
||||
return { inputWidget, disposable: Disposable.None, templateDisposable: disposables };
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<ISCMInput, FuzzyScore>, index: number, templateData: InputTemplate): void {
|
||||
@@ -297,22 +311,19 @@ class InputRenderer implements ICompressibleTreeRenderer<ISCMInput, FuzzyScore,
|
||||
this.contentHeights.set(input, contentHeight);
|
||||
|
||||
if (lastContentHeight !== contentHeight) {
|
||||
if (lastContentHeight !== undefined) {
|
||||
this.updateHeight(input, contentHeight + 10);
|
||||
templateData.inputWidget.layout();
|
||||
} else if (contentHeight !== InputRenderer.DEFAULT_HEIGHT) {
|
||||
// first time render, we must rerender on the next stack frame
|
||||
const timeout = setTimeout(() => {
|
||||
this.updateHeight(input, contentHeight + 10);
|
||||
templateData.inputWidget.layout();
|
||||
});
|
||||
disposables.add({ dispose: () => clearTimeout(timeout) });
|
||||
}
|
||||
this.updateHeight(input, contentHeight + 10);
|
||||
templateData.inputWidget.layout();
|
||||
}
|
||||
};
|
||||
|
||||
disposables.add(templateData.inputWidget.onDidChangeContentHeight(onDidChangeContentHeight));
|
||||
onDidChangeContentHeight();
|
||||
const startListeningContentHeightChange = () => {
|
||||
disposables.add(templateData.inputWidget.onDidChangeContentHeight(onDidChangeContentHeight));
|
||||
onDidChangeContentHeight();
|
||||
};
|
||||
|
||||
// Setup height change listener on next tick
|
||||
const timeout = disposableTimeout(startListeningContentHeightChange, 0);
|
||||
disposables.add(timeout);
|
||||
|
||||
// Layout the editor whenever the outer layout happens
|
||||
const layoutEditor = () => templateData.inputWidget.layout();
|
||||
@@ -720,20 +731,20 @@ class SCMResourceIdentityProvider implements IIdentityProvider<TreeElement> {
|
||||
getId(element: TreeElement): string {
|
||||
if (ResourceTree.isResourceNode(element)) {
|
||||
const group = element.context;
|
||||
return `folder:${group.provider.contextValue}/${group.id}/$FOLDER/${element.uri.toString()}`;
|
||||
return `folder:${group.provider.id}/${group.id}/$FOLDER/${element.uri.toString()}`;
|
||||
} else if (isSCMRepository(element)) {
|
||||
const provider = element.provider;
|
||||
return `repo:${provider.contextValue}`;
|
||||
return `repo:${provider.id}`;
|
||||
} else if (isSCMInput(element)) {
|
||||
const provider = element.repository.provider;
|
||||
return `input:${provider.contextValue}`;
|
||||
return `input:${provider.id}`;
|
||||
} else if (isSCMResource(element)) {
|
||||
const group = element.resourceGroup;
|
||||
const provider = group.provider;
|
||||
return `resource:${provider.contextValue}/${group.id}/${element.sourceUri.toString()}`;
|
||||
return `resource:${provider.id}/${group.id}/${element.sourceUri.toString()}`;
|
||||
} else {
|
||||
const provider = element.provider;
|
||||
return `group:${provider.contextValue}/${element.id}`;
|
||||
return `group:${provider.id}/${element.id}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -816,6 +827,10 @@ class ViewModel {
|
||||
private readonly _onDidChangeMode = new Emitter<ViewModelMode>();
|
||||
readonly onDidChangeMode = this._onDidChangeMode.event;
|
||||
|
||||
private _onDidChangeRepositoryCollapseState = new Emitter<void>();
|
||||
readonly onDidChangeRepositoryCollapseState: Event<void>;
|
||||
private visible: boolean = false;
|
||||
|
||||
get mode(): ViewModelMode { return this._mode; }
|
||||
set mode(mode: ViewModelMode) {
|
||||
this._mode = mode;
|
||||
@@ -848,10 +863,11 @@ class ViewModel {
|
||||
private visibilityDisposables = new DisposableStore();
|
||||
private scrollTop: number | undefined;
|
||||
private firstVisible = true;
|
||||
private repositoryCollapseStates: Map<ISCMRepository, boolean> | undefined;
|
||||
private disposables = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
private repositories: ISequence<ISCMRepository>,
|
||||
readonly repositories: ISequence<ISCMRepository>,
|
||||
private tree: WorkbenchCompressibleObjectTree<TreeElement, FuzzyScore>,
|
||||
private menus: SCMMenus,
|
||||
private inputRenderer: InputRenderer,
|
||||
@@ -859,12 +875,17 @@ class ViewModel {
|
||||
private _sortKey: ViewModelSortKey,
|
||||
@IEditorService protected editorService: IEditorService,
|
||||
@IConfigurationService protected configurationService: IConfigurationService,
|
||||
) { }
|
||||
) {
|
||||
this.onDidChangeRepositoryCollapseState = Event.any(
|
||||
this._onDidChangeRepositoryCollapseState.event,
|
||||
Event.signal(Event.filter(this.tree.onDidChangeCollapseState, e => isSCMRepository(e.node.element)))
|
||||
);
|
||||
}
|
||||
|
||||
private onDidSpliceRepositories({ start, deleteCount, toInsert }: ISplice<ISCMRepository>): void {
|
||||
private _onDidSpliceRepositories({ start, deleteCount, toInsert }: ISplice<ISCMRepository>): void {
|
||||
const itemsToInsert = toInsert.map(repository => {
|
||||
const disposable = combinedDisposable(
|
||||
repository.provider.groups.onDidSplice(splice => this.onDidSpliceGroups(item, splice)),
|
||||
repository.provider.groups.onDidSplice(splice => this._onDidSpliceGroups(item, splice)),
|
||||
repository.input.onDidChangeVisibility(() => this.refresh(item))
|
||||
);
|
||||
const groupItems = repository.provider.groups.elements.map(group => this.createGroupItem(group));
|
||||
@@ -886,7 +907,7 @@ class ViewModel {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
private onDidSpliceGroups(item: IRepositoryItem, { start, deleteCount, toInsert }: ISplice<ISCMResourceGroup>): void {
|
||||
private _onDidSpliceGroups(item: IRepositoryItem, { start, deleteCount, toInsert }: ISplice<ISCMResourceGroup>): void {
|
||||
const itemsToInsert: IGroupItem[] = toInsert.map(group => this.createGroupItem(group));
|
||||
const itemsToDispose = item.groupItems.splice(start, deleteCount, ...itemsToInsert);
|
||||
|
||||
@@ -902,7 +923,7 @@ class ViewModel {
|
||||
const resources: ISCMResource[] = [...group.elements];
|
||||
const disposable = combinedDisposable(
|
||||
group.onDidChange(() => this.tree.refilter()),
|
||||
group.onDidSplice(splice => this.onDidSpliceGroup(item, splice))
|
||||
group.onDidSplice(splice => this._onDidSpliceGroup(item, splice))
|
||||
);
|
||||
|
||||
const item: IGroupItem = { element: group, resources, tree, disposable };
|
||||
@@ -916,7 +937,7 @@ class ViewModel {
|
||||
return item;
|
||||
}
|
||||
|
||||
private onDidSpliceGroup(item: IGroupItem, { start, deleteCount, toInsert }: ISplice<ISCMResource>): void {
|
||||
private _onDidSpliceGroup(item: IGroupItem, { start, deleteCount, toInsert }: ISplice<ISCMResource>): void {
|
||||
const before = item.resources.length;
|
||||
const deleted = item.resources.splice(start, deleteCount, ...toInsert);
|
||||
const after = item.resources.length;
|
||||
@@ -941,8 +962,9 @@ class ViewModel {
|
||||
setVisible(visible: boolean): void {
|
||||
if (visible) {
|
||||
this.visibilityDisposables = new DisposableStore();
|
||||
this.repositories.onDidSplice(this.onDidSpliceRepositories, this, this.visibilityDisposables);
|
||||
this.onDidSpliceRepositories({ start: 0, deleteCount: 0, toInsert: this.repositories.elements });
|
||||
this.repositories.onDidSplice(this._onDidSpliceRepositories, this, this.visibilityDisposables);
|
||||
this._onDidSpliceRepositories({ start: 0, deleteCount: 0, toInsert: this.repositories.elements });
|
||||
this.repositoryCollapseStates = undefined;
|
||||
|
||||
if (typeof this.scrollTop === 'number') {
|
||||
this.tree.scrollTop = this.scrollTop;
|
||||
@@ -952,10 +974,21 @@ class ViewModel {
|
||||
this.editorService.onDidActiveEditorChange(this.onDidActiveEditorChange, this, this.visibilityDisposables);
|
||||
this.onDidActiveEditorChange();
|
||||
} else {
|
||||
if (this.items.length > 1) {
|
||||
this.repositoryCollapseStates = new Map();
|
||||
|
||||
for (const item of this.items) {
|
||||
this.repositoryCollapseStates.set(item.element, this.tree.isCollapsed(item.element));
|
||||
}
|
||||
}
|
||||
|
||||
this.visibilityDisposables.dispose();
|
||||
this.onDidSpliceRepositories({ start: 0, deleteCount: this.items.length, toInsert: [] });
|
||||
this._onDidSpliceRepositories({ start: 0, deleteCount: this.items.length, toInsert: [] });
|
||||
this.scrollTop = this.tree.scrollTop;
|
||||
}
|
||||
|
||||
this.visible = visible;
|
||||
this._onDidChangeRepositoryCollapseState.fire();
|
||||
}
|
||||
|
||||
private refresh(item?: IRepositoryItem | IGroupItem): void {
|
||||
@@ -966,6 +999,8 @@ class ViewModel {
|
||||
} else {
|
||||
this.tree.setChildren(null, this.items.map(item => this.render(item)));
|
||||
}
|
||||
|
||||
this._onDidChangeRepositoryCollapseState.fire();
|
||||
}
|
||||
|
||||
private render(item: IRepositoryItem | IGroupItem): ICompressedTreeElement<TreeElement> {
|
||||
@@ -981,7 +1016,8 @@ class ViewModel {
|
||||
children.push(...item.groupItems.map(i => this.render(i)));
|
||||
}
|
||||
|
||||
return { element: item.element, children, incompressible: true, collapsible: true };
|
||||
const collapsed = this.repositoryCollapseStates?.get(item.element);
|
||||
return { element: item.element, children, incompressible: true, collapsed, collapsible: hasSomeChanges };
|
||||
} else {
|
||||
const children = this.mode === ViewModelMode.List
|
||||
? Iterable.map(item.resources, element => ({ element, incompressible: true }))
|
||||
@@ -1056,6 +1092,10 @@ class ViewModel {
|
||||
}
|
||||
|
||||
getViewSecondaryActions(): IAction[] {
|
||||
if (this.repositories.elements.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const viewAction = new SCMViewSubMenuAction(this);
|
||||
|
||||
if (this.repositories.elements.length !== 1) {
|
||||
@@ -1080,6 +1120,38 @@ class ViewModel {
|
||||
return this.repositories.elements[0].provider;
|
||||
}
|
||||
|
||||
collapseAllProviders(): void {
|
||||
for (const repository of this.repositories.elements) {
|
||||
if (this.tree.isCollapsible(repository)) {
|
||||
this.tree.collapse(repository);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expandAllProviders(): void {
|
||||
for (const repository of this.repositories.elements) {
|
||||
if (this.tree.isCollapsible(repository)) {
|
||||
this.tree.expand(repository);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isAnyProviderCollapsible(): boolean {
|
||||
if (!this.visible || this.repositories.elements.length === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.repositories.elements.some(r => this.tree.hasElement(r) && this.tree.isCollapsible(r));
|
||||
}
|
||||
|
||||
areAllProvidersCollapsed(): boolean {
|
||||
if (!this.visible || this.repositories.elements.length === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.repositories.elements.every(r => this.tree.hasElement(r) && (!this.tree.isCollapsible(r) || this.tree.isCollapsed(r)));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.visibilityDisposables.dispose();
|
||||
this.disposables.dispose();
|
||||
@@ -1464,6 +1536,34 @@ class SCMInputWidget extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
class SCMCollapseAction extends Action {
|
||||
|
||||
private allCollapsed = false;
|
||||
|
||||
constructor(private viewModel: ViewModel) {
|
||||
super('scm.collapse', undefined, undefined, true);
|
||||
this._register(viewModel.onDidChangeRepositoryCollapseState(this.update, this));
|
||||
this.update();
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
if (this.allCollapsed) {
|
||||
this.viewModel.expandAllProviders();
|
||||
} else {
|
||||
this.viewModel.collapseAllProviders();
|
||||
}
|
||||
}
|
||||
|
||||
private update(): void {
|
||||
const isAnyProviderCollapsible = this.viewModel.isAnyProviderCollapsible();
|
||||
|
||||
this.enabled = isAnyProviderCollapsible;
|
||||
this.allCollapsed = isAnyProviderCollapsible && this.viewModel.areAllProvidersCollapsed();
|
||||
this.label = this.allCollapsed ? localize('expand all', "Expand All Providers") : localize('collapse all', "Collapse All Providers");
|
||||
this.class = this.allCollapsed ? Codicon.expandAll.classNames : Codicon.collapseAll.classNames;
|
||||
}
|
||||
}
|
||||
|
||||
export class SCMViewPane extends ViewPane {
|
||||
|
||||
private _onDidLayout = new Emitter<void>();
|
||||
@@ -1513,6 +1613,14 @@ export class SCMViewPane extends ViewPane {
|
||||
Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.alwaysShowActions'))(updateActionsVisibility);
|
||||
updateActionsVisibility();
|
||||
|
||||
const updateProviderCountVisibility = () => {
|
||||
const value = this.configurationService.getValue<'hidden' | 'auto' | 'visible'>('scm.providerCountBadge');
|
||||
toggleClass(this.listContainer, 'hide-provider-counts', value === 'hidden');
|
||||
toggleClass(this.listContainer, 'auto-provider-counts', value === 'auto');
|
||||
};
|
||||
Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.providerCountBadge'))(updateProviderCountVisibility);
|
||||
updateProviderCountVisibility();
|
||||
|
||||
const repositories = new SimpleSequence(this.scmService.repositories, this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository);
|
||||
this._register(repositories);
|
||||
|
||||
@@ -1521,7 +1629,7 @@ export class SCMViewPane extends ViewPane {
|
||||
|
||||
this._register(repositories.onDidSplice(() => this.updateActions()));
|
||||
|
||||
this.inputRenderer = this.instantiationService.createInstance(InputRenderer, this.layoutCache, (input, height) => this.tree.updateElementHeight(input, height));
|
||||
this.inputRenderer = this.instantiationService.createInstance(InputRenderer, this.layoutCache, (input, height) => this.tree.updateElementHeight(input, height), () => this.tree.domFocus());
|
||||
const delegate = new ProviderListDelegate(this.inputRenderer);
|
||||
|
||||
const actionViewItemProvider = (action: IAction) => this.getActionViewItem(action);
|
||||
@@ -1634,7 +1742,14 @@ export class SCMViewPane extends ViewPane {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.viewModel.getViewActions();
|
||||
if (this.viewModel.repositories.elements.length < 2) {
|
||||
return this.viewModel.getViewActions();
|
||||
}
|
||||
|
||||
return [
|
||||
new SCMCollapseAction(this.viewModel),
|
||||
...this.viewModel.getViewActions()
|
||||
];
|
||||
}
|
||||
|
||||
getSecondaryActions(): IAction[] {
|
||||
@@ -1768,13 +1883,15 @@ export class SCMViewPane extends ViewPane {
|
||||
}
|
||||
}
|
||||
|
||||
export const scmProviderSeparatorBorderColor = registerColor('scm.providerBorder', { dark: '#454545', light: '#C8C8C8', hc: contrastBorder }, localize('scm.providerBorder', "SCM Provider separator border."));
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const inputBackgroundColor = theme.getColor(inputBackground);
|
||||
if (inputBackgroundColor) {
|
||||
collector.addRule(`.scm-view .scm-editor-container .monaco-editor-background,
|
||||
.scm-view .scm-editor-container .monaco-editor,
|
||||
.scm-view .scm-editor-container .monaco-editor .margin
|
||||
{ background-color: ${inputBackgroundColor}; }`);
|
||||
{ background-color: ${inputBackgroundColor} !important; }`);
|
||||
}
|
||||
|
||||
const inputForegroundColor = theme.getColor(inputForeground);
|
||||
@@ -1787,6 +1904,11 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.scm-view .scm-editor-container { outline: 1px solid ${inputBorderColor}; }`);
|
||||
}
|
||||
|
||||
const panelInputBorder = theme.getColor(PANEL_INPUT_BORDER);
|
||||
if (panelInputBorder) {
|
||||
collector.addRule(`.monaco-workbench .part.panel .scm-view .scm-editor-container { outline: 1px solid ${panelInputBorder}; }`);
|
||||
}
|
||||
|
||||
const focusBorderColor = theme.getColor(focusBorder);
|
||||
if (focusBorderColor) {
|
||||
collector.addRule(`.scm-view .scm-editor-container.synthetic-focus { outline: 1px solid ${focusBorderColor}; }`);
|
||||
@@ -1799,7 +1921,7 @@ registerThemingParticipant((theme, collector) => {
|
||||
|
||||
const inputValidationInfoBorderColor = theme.getColor(inputValidationInfoBorder);
|
||||
if (inputValidationInfoBorderColor) {
|
||||
collector.addRule(`.scm-view .scm-editor-container.validation-info { outline: 1px solid ${inputValidationInfoBorderColor}; }`);
|
||||
collector.addRule(`.scm-view .scm-editor-container.validation-info { outline: 1px solid ${inputValidationInfoBorderColor} !important; }`);
|
||||
collector.addRule(`.scm-editor-validation.validation-info { border-color: ${inputValidationInfoBorderColor}; }`);
|
||||
}
|
||||
|
||||
@@ -1815,7 +1937,7 @@ registerThemingParticipant((theme, collector) => {
|
||||
|
||||
const inputValidationWarningBorderColor = theme.getColor(inputValidationWarningBorder);
|
||||
if (inputValidationWarningBorderColor) {
|
||||
collector.addRule(`.scm-view .scm-editor-container.validation-warning { outline: 1px solid ${inputValidationWarningBorderColor}; }`);
|
||||
collector.addRule(`.scm-view .scm-editor-container.validation-warning { outline: 1px solid ${inputValidationWarningBorderColor} !important; }`);
|
||||
collector.addRule(`.scm-editor-validation.validation-warning { border-color: ${inputValidationWarningBorderColor}; }`);
|
||||
}
|
||||
|
||||
@@ -1831,7 +1953,7 @@ registerThemingParticipant((theme, collector) => {
|
||||
|
||||
const inputValidationErrorBorderColor = theme.getColor(inputValidationErrorBorder);
|
||||
if (inputValidationErrorBorderColor) {
|
||||
collector.addRule(`.scm-view .scm-editor-container.validation-error { outline: 1px solid ${inputValidationErrorBorderColor}; }`);
|
||||
collector.addRule(`.scm-view .scm-editor-container.validation-error { outline: 1px solid ${inputValidationErrorBorderColor} !important; }`);
|
||||
collector.addRule(`.scm-editor-validation.validation-error { border-color: ${inputValidationErrorBorderColor}; }`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user