mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-31 09:10:30 -04:00
Merge from vscode c58aaab8a1cc22a7139b761166a0d4f37d41e998 (#7880)
* Merge from vscode c58aaab8a1cc22a7139b761166a0d4f37d41e998 * fix pipelines * fix strict-null-checks * add missing files
This commit is contained in:
@@ -17,7 +17,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ISCMService, ISCMRepository } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { ISCMService, ISCMRepository, ISCMProvider } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromId, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
|
||||
@@ -37,7 +37,7 @@ import { IDiffEditorOptions, EditorOption } from 'vs/editor/common/config/editor
|
||||
import { Action, IAction, ActionRunner } from 'vs/base/common/actions';
|
||||
import { IActionBarOptions, ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { basename, isEqualOrParent } from 'vs/base/common/resources';
|
||||
import { MenuId, IMenuService, IMenu, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { createAndFillInActionBarActions, ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IChange, IEditorModel, ScrollType, IEditorContribution, IDiffEditorModel } from 'vs/editor/common/editorCommon';
|
||||
@@ -149,7 +149,7 @@ function getChangeTypeColor(theme: ITheme, changeType: ChangeType): Color | unde
|
||||
}
|
||||
}
|
||||
|
||||
function getOuterEditorFromDiffEditor(accessor: ServicesAccessor): ICodeEditor | undefined {
|
||||
function getOuterEditorFromDiffEditor(accessor: ServicesAccessor): ICodeEditor | null {
|
||||
const diffEditors = accessor.get(ICodeEditorService).listDiffEditors();
|
||||
|
||||
for (const diffEditor of diffEditors) {
|
||||
@@ -163,11 +163,11 @@ function getOuterEditorFromDiffEditor(accessor: ServicesAccessor): ICodeEditor |
|
||||
|
||||
class DirtyDiffWidget extends PeekViewWidget {
|
||||
|
||||
private diffEditor: EmbeddedDiffEditorWidget;
|
||||
private diffEditor!: EmbeddedDiffEditorWidget;
|
||||
private title: string;
|
||||
private menu: IMenu;
|
||||
private index: number;
|
||||
private change: IChange;
|
||||
private index: number = 0;
|
||||
private change: IChange | undefined;
|
||||
private height: number | undefined = undefined;
|
||||
private contextKeyService: IContextKeyService;
|
||||
|
||||
@@ -320,7 +320,7 @@ class DirtyDiffWidget extends PeekViewWidget {
|
||||
super._doLayoutBody(height, width);
|
||||
this.diffEditor.layout({ height, width });
|
||||
|
||||
if (typeof this.height === 'undefined') {
|
||||
if (typeof this.height === 'undefined' && this.change) {
|
||||
this.revealChange(this.change);
|
||||
}
|
||||
|
||||
@@ -556,7 +556,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
|
||||
export class DirtyDiffController extends Disposable implements IEditorContribution {
|
||||
|
||||
private static readonly ID = 'editor.contrib.dirtydiff';
|
||||
public static readonly ID = 'editor.contrib.dirtydiff';
|
||||
|
||||
static get(editor: ICodeEditor): DirtyDiffController {
|
||||
return editor.getContribution<DirtyDiffController>(DirtyDiffController.ID);
|
||||
@@ -567,7 +567,7 @@ export class DirtyDiffController extends Disposable implements IEditorContributi
|
||||
private model: DirtyDiffModel | null = null;
|
||||
private widget: DirtyDiffWidget | null = null;
|
||||
private currentIndex: number = -1;
|
||||
private readonly isDirtyDiffVisible: IContextKey<boolean>;
|
||||
private readonly isDirtyDiffVisible!: IContextKey<boolean>;
|
||||
private session: IDisposable = Disposable.None;
|
||||
private mouseDownInfo: { lineNumber: number } | null = null;
|
||||
private enabled = false;
|
||||
@@ -588,10 +588,6 @@ export class DirtyDiffController extends Disposable implements IEditorContributi
|
||||
}
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return DirtyDiffController.ID;
|
||||
}
|
||||
|
||||
canNavigate(): boolean {
|
||||
return this.currentIndex === -1 || (!!this.model && this.model.changes.length > 1);
|
||||
}
|
||||
@@ -676,7 +672,10 @@ export class DirtyDiffController extends Disposable implements IEditorContributi
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
disposables.add(Event.once(this.widget.onDidClose)(this.close, this));
|
||||
disposables.add(model.onDidChange(this.onDidModelChange, this));
|
||||
Event.chain(model.onDidChange)
|
||||
.filter(e => e.diff.length > 0)
|
||||
.map(e => e.diff)
|
||||
.event(this.onDidModelChange, this, disposables);
|
||||
|
||||
disposables.add(this.widget);
|
||||
disposables.add(toDisposable(() => {
|
||||
@@ -951,9 +950,26 @@ function compareChanges(a: IChange, b: IChange): number {
|
||||
return a.originalEndLineNumber - b.originalEndLineNumber;
|
||||
}
|
||||
|
||||
function createProviderComparer(uri: URI): (a: ISCMProvider, b: ISCMProvider) => number {
|
||||
return (a, b) => {
|
||||
const aIsParent = isEqualOrParent(uri, a.rootUri!);
|
||||
const bIsParent = isEqualOrParent(uri, b.rootUri!);
|
||||
|
||||
if (aIsParent && bIsParent) {
|
||||
return a.rootUri!.fsPath.length - b.rootUri!.fsPath.length;
|
||||
} else if (aIsParent) {
|
||||
return -1;
|
||||
} else if (bIsParent) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class DirtyDiffModel extends Disposable {
|
||||
|
||||
private _originalModel: ITextModel | null;
|
||||
private _originalModel: ITextModel | null = null;
|
||||
get original(): ITextModel | null { return this._originalModel; }
|
||||
get modified(): ITextModel | null { return this._editorModel; }
|
||||
|
||||
@@ -962,13 +978,11 @@ export class DirtyDiffModel extends Disposable {
|
||||
private repositoryDisposables = new Set<IDisposable>();
|
||||
private readonly originalModelDisposables = this._register(new DisposableStore());
|
||||
|
||||
private readonly _onDidChange = new Emitter<ISplice<IChange>[]>();
|
||||
readonly onDidChange: Event<ISplice<IChange>[]> = this._onDidChange.event;
|
||||
private readonly _onDidChange = new Emitter<{ changes: IChange[], diff: ISplice<IChange>[] }>();
|
||||
readonly onDidChange: Event<{ changes: IChange[], diff: ISplice<IChange>[] }> = this._onDidChange.event;
|
||||
|
||||
private _changes: IChange[] = [];
|
||||
get changes(): IChange[] {
|
||||
return this._changes;
|
||||
}
|
||||
get changes(): IChange[] { return this._changes; }
|
||||
|
||||
private _editorModel: ITextModel | null;
|
||||
|
||||
@@ -1022,10 +1036,7 @@ export class DirtyDiffModel extends Disposable {
|
||||
|
||||
const diff = sortedDiff(this._changes, changes, compareChanges);
|
||||
this._changes = changes;
|
||||
|
||||
if (diff.length > 0) {
|
||||
this._onDidChange.fire(diff);
|
||||
}
|
||||
this._onDidChange.fire({ changes, diff });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1082,13 +1093,25 @@ export class DirtyDiffModel extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private getOriginalResource(): Promise<URI | null> {
|
||||
private async getOriginalResource(): Promise<URI | null> {
|
||||
if (!this._editorModel) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
const uri = this._editorModel.uri;
|
||||
return first(this.scmService.repositories.map(r => () => r.provider.getOriginalResource(uri)));
|
||||
const providers = this.scmService.repositories.map(r => r.provider);
|
||||
const rootedProviders = providers.filter(p => !!p.rootUri);
|
||||
|
||||
rootedProviders.sort(createProviderComparer(uri));
|
||||
|
||||
const result = await first(rootedProviders.map(p => () => p.getOriginalResource(uri)));
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const nonRootedProviders = providers.filter(p => !p.rootUri);
|
||||
return first(nonRootedProviders.map(p => () => p.getOriginalResource(uri)));
|
||||
}
|
||||
|
||||
findNextClosestChange(lineNumber: number, inclusive = true): number {
|
||||
@@ -1177,6 +1200,10 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor
|
||||
const onDidChangeDiffWidthConfiguration = Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.diffDecorationsGutterWidth'));
|
||||
onDidChangeDiffWidthConfiguration(this.onDidChangeDiffWidthConfiguration, this);
|
||||
this.onDidChangeDiffWidthConfiguration();
|
||||
|
||||
const onDidChangeDiffVisibilityConfiguration = Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.diffDecorationsGutterVisibility'));
|
||||
onDidChangeDiffVisibilityConfiguration(this.onDidChangeDiffVisibiltiyConfiguration, this);
|
||||
this.onDidChangeDiffVisibiltiyConfiguration();
|
||||
}
|
||||
|
||||
private onDidChangeConfiguration(): void {
|
||||
@@ -1199,6 +1226,16 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor
|
||||
this.stylesheet.innerHTML = `.monaco-editor .dirty-diff-modified,.monaco-editor .dirty-diff-added{border-left-width:${width}px;}`;
|
||||
}
|
||||
|
||||
private onDidChangeDiffVisibiltiyConfiguration(): void {
|
||||
const visibility = this.configurationService.getValue<string>('scm.diffDecorationsGutterVisibility');
|
||||
|
||||
this.stylesheet.innerHTML = `
|
||||
.monaco-editor .dirty-diff-modified, .monaco-editor .dirty-diff-added, .monaco-editor .dirty-diff-deleted {
|
||||
opacity: ${visibility === 'always' ? 1 : 0};
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
private enable(): void {
|
||||
if (this.enabled) {
|
||||
this.disable();
|
||||
@@ -1278,7 +1315,7 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorContribution(DirtyDiffController);
|
||||
registerEditorContribution(DirtyDiffController.ID, DirtyDiffController);
|
||||
|
||||
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
const editorGutterModifiedBackgroundColor = theme.getColor(editorGutterModifiedBackground);
|
||||
@@ -1286,10 +1323,14 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
collector.addRule(`
|
||||
.monaco-editor .dirty-diff-modified {
|
||||
border-left: 3px solid ${editorGutterModifiedBackgroundColor};
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
.monaco-editor .dirty-diff-modified:before {
|
||||
background: ${editorGutterModifiedBackgroundColor};
|
||||
}
|
||||
.monaco-editor .margin:hover .dirty-diff-modified {
|
||||
opacity: 1;
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
@@ -1298,10 +1339,14 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
collector.addRule(`
|
||||
.monaco-editor .dirty-diff-added {
|
||||
border-left: 3px solid ${editorGutterAddedBackgroundColor};
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
.monaco-editor .dirty-diff-added:before {
|
||||
background: ${editorGutterAddedBackgroundColor};
|
||||
}
|
||||
.monaco-editor .margin:hover .dirty-diff-added {
|
||||
opacity: 1;
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
@@ -1310,10 +1355,14 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
collector.addRule(`
|
||||
.monaco-editor .dirty-diff-deleted:after {
|
||||
border-left: 4px solid ${editorGutteDeletedBackgroundColor};
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
.monaco-editor .dirty-diff-deleted:before {
|
||||
background: ${editorGutteDeletedBackgroundColor};
|
||||
}
|
||||
.monaco-editor .margin:hover .dirty-diff-added {
|
||||
opacity: 1;
|
||||
}
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,7 +10,6 @@ import { basename } from 'vs/base/common/resources';
|
||||
import { IDisposable, dispose, Disposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { append, $, toggleClass } from 'vs/base/browser/dom';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListVirtualDelegate, IListRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { ISCMService, ISCMRepository } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
|
||||
@@ -26,7 +25,7 @@ import { ActionBar, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionba
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
|
||||
import { Command } from 'vs/editor/common/modes';
|
||||
import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
|
||||
import { renderCodicons } from 'vs/base/browser/ui/codiconLabel/codiconLabel';
|
||||
import { WorkbenchList } from 'vs/platform/list/browser/listService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IViewDescriptor } from 'vs/workbench/common/views';
|
||||
@@ -82,8 +81,8 @@ class StatusBarActionViewItem extends ActionViewItem {
|
||||
}
|
||||
|
||||
updateLabel(): void {
|
||||
if (this.options.label) {
|
||||
this.label.innerHTML = renderOcticons(this.getAction().label);
|
||||
if (this.options.label && this.label) {
|
||||
this.label.innerHTML = renderCodicons(this.getAction().label);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,7 +172,7 @@ export class MainPanel extends ViewletPanel {
|
||||
static readonly ID = 'scm.mainPanel';
|
||||
static readonly TITLE = localize('scm providers', "Source Control Providers");
|
||||
|
||||
private list: List<ISCMRepository>;
|
||||
private list!: WorkbenchList<ISCMRepository>;
|
||||
|
||||
constructor(
|
||||
protected viewModel: IViewModel,
|
||||
|
||||
@@ -41,8 +41,25 @@
|
||||
}
|
||||
|
||||
.scm-viewlet .monaco-list-row > .scm-provider > .monaco-action-bar .action-item {
|
||||
padding: 0 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.scm-viewlet .monaco-list-row > .scm-provider > .monaco-action-bar .action-label .codicon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.scm-viewlet .monaco-list-row > .scm-provider > .monaco-action-bar .action-item:last-of-type {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.scm-viewlet .scm-provider > .name,
|
||||
.scm-viewlet .scm-provider > .count {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.scm-viewlet .scm-provider > .count {
|
||||
@@ -97,7 +114,7 @@
|
||||
}
|
||||
|
||||
.scm-viewlet .monaco-list-row .resource-group > .count {
|
||||
padding: 0 8px;
|
||||
padding: 0 12px 0 8px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -106,6 +123,7 @@
|
||||
height: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% 50%;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.scm-viewlet .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions {
|
||||
@@ -142,7 +160,7 @@
|
||||
|
||||
.scm-viewlet .scm-editor {
|
||||
box-sizing: border-box;
|
||||
padding: 5px 9px 5px 16px;
|
||||
padding: 5px 12px 5px 16px;
|
||||
}
|
||||
|
||||
.scm-viewlet .scm-editor.hidden {
|
||||
@@ -170,3 +188,7 @@
|
||||
width: 8px !important;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.scm-viewlet .scm-status.show-file-icons.hide-arrows.tree-view-mode .monaco-tl-indent .indent-guide:first-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { format } from 'vs/base/common/strings';
|
||||
import { WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ThrottledDelayer } from 'vs/base/common/async';
|
||||
import { ThrottledDelayer, disposableTimeout } from 'vs/base/common/async';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { ITreeNode, ITreeFilter, ITreeSorter, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ResourceTree, IResourceNode } from 'vs/base/common/resourceTree';
|
||||
import { ISequence, ISplice } from 'vs/base/common/sequence';
|
||||
import { ResourceTree, IBranchNode, INode } from 'vs/base/common/resourceTree';
|
||||
import { ObjectTree, ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/tree/objectTree';
|
||||
import { Iterator } from 'vs/base/common/iterator';
|
||||
import { ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
@@ -50,8 +50,10 @@ import { localize } from 'vs/nls';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
|
||||
type TreeElement = ISCMResourceGroup | IBranchNode<ISCMResource, ISCMResourceGroup> | ISCMResource;
|
||||
type TreeElement = ISCMResourceGroup | IResourceNode<ISCMResource, ISCMResourceGroup> | ISCMResource;
|
||||
|
||||
interface ResourceGroupTemplate {
|
||||
readonly name: HTMLElement;
|
||||
@@ -63,7 +65,7 @@ interface ResourceGroupTemplate {
|
||||
|
||||
class ResourceGroupRenderer implements ICompressibleTreeRenderer<ISCMResourceGroup, FuzzyScore, ResourceGroupTemplate> {
|
||||
|
||||
static TEMPLATE_ID = 'resource group';
|
||||
static readonly TEMPLATE_ID = 'resource group';
|
||||
get templateId(): string { return ResourceGroupRenderer.TEMPLATE_ID; }
|
||||
|
||||
constructor(
|
||||
@@ -130,11 +132,11 @@ interface ResourceTemplate {
|
||||
|
||||
class MultipleSelectionActionRunner extends ActionRunner {
|
||||
|
||||
constructor(private getSelectedResources: () => (ISCMResource | IBranchNode<ISCMResource, ISCMResourceGroup>)[]) {
|
||||
constructor(private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[]) {
|
||||
super();
|
||||
}
|
||||
|
||||
runAction(action: IAction, context: ISCMResource | IBranchNode<ISCMResource, ISCMResourceGroup>): Promise<any> {
|
||||
runAction(action: IAction, context: ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>): Promise<any> {
|
||||
if (!(action instanceof MenuItemAction)) {
|
||||
return super.runAction(action, context);
|
||||
}
|
||||
@@ -142,21 +144,21 @@ class MultipleSelectionActionRunner extends ActionRunner {
|
||||
const selection = this.getSelectedResources();
|
||||
const contextIsSelected = selection.some(s => s === context);
|
||||
const actualContext = contextIsSelected ? selection : [context];
|
||||
const args = flatten(actualContext.map(e => ResourceTree.isBranchNode(e) ? ResourceTree.collect(e) : [e]));
|
||||
const args = flatten(actualContext.map(e => ResourceTree.isResourceNode(e) ? ResourceTree.collect(e) : [e]));
|
||||
return action.run(...args);
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IBranchNode<ISCMResource, ISCMResourceGroup>, FuzzyScore, ResourceTemplate> {
|
||||
class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>, FuzzyScore, ResourceTemplate> {
|
||||
|
||||
static TEMPLATE_ID = 'resource';
|
||||
static readonly TEMPLATE_ID = 'resource';
|
||||
get templateId(): string { return ResourceRenderer.TEMPLATE_ID; }
|
||||
|
||||
constructor(
|
||||
private viewModelProvider: () => ViewModel,
|
||||
private labels: ResourceLabels,
|
||||
private actionViewItemProvider: IActionViewItemProvider,
|
||||
private getSelectedResources: () => (ISCMResource | IBranchNode<ISCMResource, ISCMResourceGroup>)[],
|
||||
private getSelectedResources: () => (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[],
|
||||
private themeService: IThemeService,
|
||||
private menus: SCMMenus
|
||||
) { }
|
||||
@@ -177,16 +179,17 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IBran
|
||||
return { element, name, fileLabel, decorationIcon, actionBar, elementDisposables: Disposable.None, disposables };
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<ISCMResource, FuzzyScore> | ITreeNode<IBranchNode<ISCMResource, ISCMResourceGroup>, FuzzyScore>, index: number, template: ResourceTemplate): void {
|
||||
renderElement(node: ITreeNode<ISCMResource, FuzzyScore> | ITreeNode<ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>, FuzzyScore>, index: number, template: ResourceTemplate): void {
|
||||
template.elementDisposables.dispose();
|
||||
|
||||
const elementDisposables = new DisposableStore();
|
||||
const resourceOrFolder = node.element;
|
||||
const theme = this.themeService.getTheme();
|
||||
const icon = !ResourceTree.isBranchNode(resourceOrFolder) && (theme.type === LIGHT ? resourceOrFolder.decorations.icon : resourceOrFolder.decorations.iconDark);
|
||||
const iconResource = ResourceTree.isResourceNode(resourceOrFolder) ? resourceOrFolder.element : resourceOrFolder;
|
||||
const icon = iconResource && (theme.type === LIGHT ? iconResource.decorations.icon : iconResource.decorations.iconDark);
|
||||
|
||||
const uri = ResourceTree.isBranchNode(resourceOrFolder) ? resourceOrFolder.uri : resourceOrFolder.sourceUri;
|
||||
const fileKind = ResourceTree.isBranchNode(resourceOrFolder) ? FileKind.FOLDER : FileKind.FILE;
|
||||
const uri = ResourceTree.isResourceNode(resourceOrFolder) ? resourceOrFolder.uri : resourceOrFolder.sourceUri;
|
||||
const fileKind = ResourceTree.isResourceNode(resourceOrFolder) ? FileKind.FOLDER : FileKind.FILE;
|
||||
const viewModel = this.viewModelProvider();
|
||||
|
||||
template.fileLabel.setFile(uri, {
|
||||
@@ -199,17 +202,23 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IBran
|
||||
template.actionBar.clear();
|
||||
template.actionBar.context = resourceOrFolder;
|
||||
|
||||
if (ResourceTree.isBranchNode(resourceOrFolder)) {
|
||||
elementDisposables.add(connectPrimaryMenuToInlineActionBar(this.menus.getResourceFolderMenu(resourceOrFolder.context), template.actionBar));
|
||||
removeClass(template.name, 'strike-through');
|
||||
removeClass(template.element, 'faded');
|
||||
if (ResourceTree.isResourceNode(resourceOrFolder)) {
|
||||
if (resourceOrFolder.element) {
|
||||
elementDisposables.add(connectPrimaryMenuToInlineActionBar(this.menus.getResourceMenu(resourceOrFolder.element.resourceGroup), template.actionBar));
|
||||
toggleClass(template.name, 'strike-through', resourceOrFolder.element.decorations.strikeThrough);
|
||||
toggleClass(template.element, 'faded', resourceOrFolder.element.decorations.faded);
|
||||
} else {
|
||||
elementDisposables.add(connectPrimaryMenuToInlineActionBar(this.menus.getResourceFolderMenu(resourceOrFolder.context), template.actionBar));
|
||||
removeClass(template.name, 'strike-through');
|
||||
removeClass(template.element, 'faded');
|
||||
}
|
||||
} else {
|
||||
elementDisposables.add(connectPrimaryMenuToInlineActionBar(this.menus.getResourceMenu(resourceOrFolder.resourceGroup), template.actionBar));
|
||||
toggleClass(template.name, 'strike-through', resourceOrFolder.decorations.strikeThrough);
|
||||
toggleClass(template.element, 'faded', resourceOrFolder.decorations.faded);
|
||||
}
|
||||
|
||||
const tooltip = !ResourceTree.isBranchNode(resourceOrFolder) && resourceOrFolder.decorations.tooltip || '';
|
||||
const tooltip = !ResourceTree.isResourceNode(resourceOrFolder) && resourceOrFolder.decorations.tooltip || '';
|
||||
|
||||
if (icon) {
|
||||
template.decorationIcon.style.display = '';
|
||||
@@ -225,15 +234,15 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IBran
|
||||
template.elementDisposables = elementDisposables;
|
||||
}
|
||||
|
||||
disposeElement(resource: ITreeNode<ISCMResource, FuzzyScore> | ITreeNode<IBranchNode<ISCMResource, ISCMResourceGroup>, FuzzyScore>, index: number, template: ResourceTemplate): void {
|
||||
disposeElement(resource: ITreeNode<ISCMResource, FuzzyScore> | ITreeNode<IResourceNode<ISCMResource, ISCMResourceGroup>, FuzzyScore>, index: number, template: ResourceTemplate): void {
|
||||
template.elementDisposables.dispose();
|
||||
}
|
||||
|
||||
renderCompressedElements(node: ITreeNode<ICompressedTreeNode<ISCMResource> | ICompressedTreeNode<IBranchNode<ISCMResource, ISCMResourceGroup>>, FuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void {
|
||||
renderCompressedElements(node: ITreeNode<ICompressedTreeNode<ISCMResource> | ICompressedTreeNode<IResourceNode<ISCMResource, ISCMResourceGroup>>, FuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void {
|
||||
template.elementDisposables.dispose();
|
||||
|
||||
const elementDisposables = new DisposableStore();
|
||||
const compressed = node.element as ICompressedTreeNode<IBranchNode<ISCMResource, ISCMResourceGroup>>;
|
||||
const compressed = node.element as ICompressedTreeNode<IResourceNode<ISCMResource, ISCMResourceGroup>>;
|
||||
const folder = compressed.elements[compressed.elements.length - 1];
|
||||
|
||||
const label = compressed.elements.map(e => e.name).join('/');
|
||||
@@ -259,7 +268,7 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IBran
|
||||
template.elementDisposables = elementDisposables;
|
||||
}
|
||||
|
||||
disposeCompressedElements(node: ITreeNode<ICompressedTreeNode<ISCMResource> | ICompressedTreeNode<IBranchNode<ISCMResource, ISCMResourceGroup>>, FuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void {
|
||||
disposeCompressedElements(node: ITreeNode<ICompressedTreeNode<ISCMResource> | ICompressedTreeNode<IResourceNode<ISCMResource, ISCMResourceGroup>>, FuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void {
|
||||
template.elementDisposables.dispose();
|
||||
}
|
||||
|
||||
@@ -274,7 +283,7 @@ class ProviderListDelegate implements IListVirtualDelegate<TreeElement> {
|
||||
getHeight() { return 22; }
|
||||
|
||||
getTemplateId(element: TreeElement) {
|
||||
if (ResourceTree.isBranchNode(element) || isSCMResource(element)) {
|
||||
if (ResourceTree.isResourceNode(element) || isSCMResource(element)) {
|
||||
return ResourceRenderer.TEMPLATE_ID;
|
||||
} else {
|
||||
return ResourceGroupRenderer.TEMPLATE_ID;
|
||||
@@ -285,7 +294,7 @@ class ProviderListDelegate implements IListVirtualDelegate<TreeElement> {
|
||||
class SCMTreeFilter implements ITreeFilter<TreeElement> {
|
||||
|
||||
filter(element: TreeElement): boolean {
|
||||
if (ResourceTree.isBranchNode(element)) {
|
||||
if (ResourceTree.isResourceNode(element)) {
|
||||
return true;
|
||||
} else if (isSCMResourceGroup(element)) {
|
||||
return element.elements.length > 0 || !element.hideWhenEmpty;
|
||||
@@ -311,15 +320,15 @@ export class SCMTreeSorter implements ITreeSorter<TreeElement> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const oneIsDirectory = ResourceTree.isBranchNode(one);
|
||||
const otherIsDirectory = ResourceTree.isBranchNode(other);
|
||||
const oneIsDirectory = ResourceTree.isResourceNode(one);
|
||||
const otherIsDirectory = ResourceTree.isResourceNode(other);
|
||||
|
||||
if (oneIsDirectory !== otherIsDirectory) {
|
||||
return oneIsDirectory ? -1 : 1;
|
||||
}
|
||||
|
||||
const oneName = ResourceTree.isBranchNode(one) ? one.name : basename((one as ISCMResource).sourceUri);
|
||||
const otherName = ResourceTree.isBranchNode(other) ? other.name : basename((other as ISCMResource).sourceUri);
|
||||
const oneName = ResourceTree.isResourceNode(one) ? one.name : basename((one as ISCMResource).sourceUri);
|
||||
const otherName = ResourceTree.isResourceNode(other) ? other.name : basename((other as ISCMResource).sourceUri);
|
||||
|
||||
return compareFileNames(oneName, otherName);
|
||||
}
|
||||
@@ -328,7 +337,7 @@ export class SCMTreeSorter implements ITreeSorter<TreeElement> {
|
||||
export class SCMTreeKeyboardNavigationLabelProvider implements ICompressibleKeyboardNavigationLabelProvider<TreeElement> {
|
||||
|
||||
getKeyboardNavigationLabel(element: TreeElement): { toString(): string; } | undefined {
|
||||
if (ResourceTree.isBranchNode(element)) {
|
||||
if (ResourceTree.isResourceNode(element)) {
|
||||
return element.name;
|
||||
} else if (isSCMResourceGroup(element)) {
|
||||
return element.label;
|
||||
@@ -338,7 +347,7 @@ export class SCMTreeKeyboardNavigationLabelProvider implements ICompressibleKeyb
|
||||
}
|
||||
|
||||
getCompressedNodeKeyboardNavigationLabel(elements: TreeElement[]): { toString(): string | undefined; } | undefined {
|
||||
const folders = elements as IBranchNode<ISCMResource, ISCMResourceGroup>[];
|
||||
const folders = elements as IResourceNode<ISCMResource, ISCMResourceGroup>[];
|
||||
return folders.map(e => e.name).join('/');
|
||||
}
|
||||
}
|
||||
@@ -346,7 +355,7 @@ export class SCMTreeKeyboardNavigationLabelProvider implements ICompressibleKeyb
|
||||
class SCMResourceIdentityProvider implements IIdentityProvider<TreeElement> {
|
||||
|
||||
getId(element: TreeElement): string {
|
||||
if (ResourceTree.isBranchNode(element)) {
|
||||
if (ResourceTree.isResourceNode(element)) {
|
||||
const group = element.context;
|
||||
return `${group.provider.contextValue}/${group.id}/$FOLDER/${element.uri.toString()}`;
|
||||
} else if (isSCMResource(element)) {
|
||||
@@ -375,22 +384,17 @@ function groupItemAsTreeElement(item: IGroupItem, mode: ViewModelMode): ICompres
|
||||
return { element: item.group, children, incompressible: true, collapsible: true };
|
||||
}
|
||||
|
||||
function asTreeElement(node: INode<ISCMResource, ISCMResourceGroup>, incompressible: boolean): ICompressedTreeElement<TreeElement> {
|
||||
if (ResourceTree.isBranchNode(node)) {
|
||||
return {
|
||||
element: node,
|
||||
children: Iterator.map(node.children, node => asTreeElement(node, false)),
|
||||
incompressible,
|
||||
collapsed: false
|
||||
};
|
||||
}
|
||||
|
||||
return { element: node.element, incompressible: true };
|
||||
function asTreeElement(node: IResourceNode<ISCMResource, ISCMResourceGroup>, forceIncompressible: boolean): ICompressedTreeElement<TreeElement> {
|
||||
return {
|
||||
element: (node.childrenCount === 0 && node.element) ? node.element : node,
|
||||
children: Iterator.map(node.children, node => asTreeElement(node, false)),
|
||||
incompressible: !!node.element || forceIncompressible
|
||||
};
|
||||
}
|
||||
|
||||
const enum ViewModelMode {
|
||||
List,
|
||||
Tree
|
||||
List = 'list',
|
||||
Tree = 'tree'
|
||||
}
|
||||
|
||||
class ViewModel {
|
||||
@@ -401,6 +405,17 @@ class ViewModel {
|
||||
get mode(): ViewModelMode { return this._mode; }
|
||||
set mode(mode: ViewModelMode) {
|
||||
this._mode = mode;
|
||||
|
||||
for (const item of this.items) {
|
||||
item.tree.clear();
|
||||
|
||||
if (mode === ViewModelMode.Tree) {
|
||||
for (const resource of item.resources) {
|
||||
item.tree.add(resource.sourceUri, resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
this._onDidChangeMode.fire(mode);
|
||||
}
|
||||
@@ -408,12 +423,15 @@ class ViewModel {
|
||||
private items: IGroupItem[] = [];
|
||||
private visibilityDisposables = new DisposableStore();
|
||||
private scrollTop: number | undefined;
|
||||
private firstVisible = true;
|
||||
private disposables = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
private groups: ISequence<ISCMResourceGroup>,
|
||||
private tree: ObjectTree<TreeElement, FuzzyScore>,
|
||||
private _mode: ViewModelMode
|
||||
private _mode: ViewModelMode,
|
||||
@IEditorService protected editorService: IEditorService,
|
||||
@IConfigurationService protected configurationService: IConfigurationService,
|
||||
) { }
|
||||
|
||||
private onDidSpliceGroups({ start, deleteCount, toInsert }: ISplice<ISCMResourceGroup>): void {
|
||||
@@ -427,10 +445,12 @@ class ViewModel {
|
||||
group.onDidSplice(splice => this.onDidSpliceGroup(item, splice))
|
||||
);
|
||||
|
||||
const item = { group, resources, tree, disposable };
|
||||
const item: IGroupItem = { group, resources, tree, disposable };
|
||||
|
||||
for (const resource of resources) {
|
||||
item.tree.add(resource.sourceUri, resource);
|
||||
if (this._mode === ViewModelMode.Tree) {
|
||||
for (const resource of resources) {
|
||||
item.tree.add(resource.sourceUri, resource);
|
||||
}
|
||||
}
|
||||
|
||||
itemsToInsert.push(item);
|
||||
@@ -446,14 +466,18 @@ class ViewModel {
|
||||
}
|
||||
|
||||
private onDidSpliceGroup(item: IGroupItem, { start, deleteCount, toInsert }: ISplice<ISCMResource>): void {
|
||||
for (const resource of toInsert) {
|
||||
item.tree.add(resource.sourceUri, resource);
|
||||
if (this._mode === ViewModelMode.Tree) {
|
||||
for (const resource of toInsert) {
|
||||
item.tree.add(resource.sourceUri, resource);
|
||||
}
|
||||
}
|
||||
|
||||
const deleted = item.resources.splice(start, deleteCount, ...toInsert);
|
||||
|
||||
for (const resource of deleted) {
|
||||
item.tree.delete(resource.sourceUri);
|
||||
if (this._mode === ViewModelMode.Tree) {
|
||||
for (const resource of deleted) {
|
||||
item.tree.delete(resource.sourceUri);
|
||||
}
|
||||
}
|
||||
|
||||
this.refresh(item);
|
||||
@@ -469,6 +493,9 @@ class ViewModel {
|
||||
this.tree.scrollTop = this.scrollTop;
|
||||
this.scrollTop = undefined;
|
||||
}
|
||||
|
||||
this.editorService.onDidActiveEditorChange(this.onDidActiveEditorChange, this, this.visibilityDisposables);
|
||||
this.onDidActiveEditorChange();
|
||||
} else {
|
||||
this.visibilityDisposables.dispose();
|
||||
this.onDidSpliceGroups({ start: 0, deleteCount: this.items.length, toInsert: [] });
|
||||
@@ -484,6 +511,42 @@ class ViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
private onDidActiveEditorChange(): void {
|
||||
if (!this.configurationService.getValue<boolean>('scm.autoReveal')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.firstVisible) {
|
||||
this.firstVisible = false;
|
||||
this.visibilityDisposables.add(disposableTimeout(() => this.onDidActiveEditorChange(), 250));
|
||||
return;
|
||||
}
|
||||
|
||||
const editor = this.editorService.activeEditor;
|
||||
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uri = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
|
||||
// go backwards from last group
|
||||
for (let i = this.items.length - 1; i >= 0; i--) {
|
||||
const node = this.items[i].tree.getNode(uri);
|
||||
|
||||
if (node && node.element) {
|
||||
this.tree.reveal(node.element);
|
||||
this.tree.setSelection([node.element]);
|
||||
this.tree.setFocus([node.element]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.visibilityDisposables.dispose();
|
||||
this.disposables.dispose();
|
||||
@@ -524,15 +587,16 @@ export class RepositoryPanel extends ViewletPanel {
|
||||
|
||||
private cachedHeight: number | undefined = undefined;
|
||||
private cachedWidth: number | undefined = undefined;
|
||||
private inputBoxContainer: HTMLElement;
|
||||
private inputBox: InputBox;
|
||||
private listContainer: HTMLElement;
|
||||
private tree: ObjectTree<TreeElement, FuzzyScore>;
|
||||
private viewModel: ViewModel;
|
||||
private listLabels: ResourceLabels;
|
||||
private inputBoxContainer!: HTMLElement;
|
||||
private inputBox!: InputBox;
|
||||
private listContainer!: HTMLElement;
|
||||
private tree!: ObjectTree<TreeElement, FuzzyScore>;
|
||||
private viewModel!: ViewModel;
|
||||
private listLabels!: ResourceLabels;
|
||||
private menus: SCMMenus;
|
||||
private toggleViewModelModeAction: ToggleViewModeAction | undefined;
|
||||
protected contextKeyService: IContextKeyService;
|
||||
private commitTemplate = '';
|
||||
|
||||
constructor(
|
||||
readonly repository: ISCMRepository,
|
||||
@@ -547,7 +611,8 @@ export class RepositoryPanel extends ViewletPanel {
|
||||
@IInstantiationService protected instantiationService: IInstantiationService,
|
||||
@IConfigurationService protected configurationService: IConfigurationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IMenuService protected menuService: IMenuService
|
||||
@IMenuService protected menuService: IMenuService,
|
||||
@IStorageService private storageService: IStorageService
|
||||
) {
|
||||
super(options, keybindingService, contextMenuService, configurationService, contextKeyService);
|
||||
|
||||
@@ -634,10 +699,10 @@ export class RepositoryPanel extends ViewletPanel {
|
||||
this._register(this.inputBox.onDidHeightChange(() => this.layoutBody()));
|
||||
|
||||
if (this.repository.provider.onDidChangeCommitTemplate) {
|
||||
this._register(this.repository.provider.onDidChangeCommitTemplate(this.updateInputBox, this));
|
||||
this._register(this.repository.provider.onDidChangeCommitTemplate(this.onDidChangeCommitTemplate, this));
|
||||
}
|
||||
|
||||
this.updateInputBox();
|
||||
this.onDidChangeCommitTemplate();
|
||||
|
||||
// Input box visibility
|
||||
this._register(this.repository.input.onDidChangeVisibility(this.updateInputBoxVisibility, this));
|
||||
@@ -683,33 +748,38 @@ export class RepositoryPanel extends ViewletPanel {
|
||||
|
||||
this._register(Event.chain(this.tree.onDidOpen)
|
||||
.map(e => e.elements[0])
|
||||
.filter(e => !!e && !ResourceTree.isBranchNode(e) && isSCMResource(e))
|
||||
.filter(e => !!e && !isSCMResourceGroup(e) && !ResourceTree.isResourceNode(e))
|
||||
.on(this.open, this));
|
||||
|
||||
this._register(Event.chain(this.tree.onDidPin)
|
||||
.map(e => e.elements[0])
|
||||
.filter(e => !!e && !ResourceTree.isBranchNode(e) && isSCMResource(e))
|
||||
.filter(e => !!e && !isSCMResourceGroup(e) && !ResourceTree.isResourceNode(e))
|
||||
.on(this.pin, this));
|
||||
|
||||
this._register(this.tree.onContextMenu(this.onListContextMenu, this));
|
||||
this._register(this.tree);
|
||||
|
||||
const mode = this.configurationService.getValue<'tree' | 'list'>('scm.defaultViewMode') === 'list' ? ViewModelMode.List : ViewModelMode.Tree;
|
||||
this.viewModel = new ViewModel(this.repository.provider.groups, this.tree, mode);
|
||||
let mode = this.configurationService.getValue<'tree' | 'list'>('scm.defaultViewMode') === 'list' ? ViewModelMode.List : ViewModelMode.Tree;
|
||||
|
||||
const rootUri = this.repository.provider.rootUri;
|
||||
|
||||
if (typeof rootUri !== 'undefined') {
|
||||
const storageMode = this.storageService.get(`scm.repository.viewMode:${rootUri.toString()}`, StorageScope.WORKSPACE) as ViewModelMode;
|
||||
|
||||
if (typeof storageMode === 'string') {
|
||||
mode = storageMode;
|
||||
}
|
||||
}
|
||||
|
||||
this.viewModel = this.instantiationService.createInstance(ViewModel, this.repository.provider.groups, this.tree, mode);
|
||||
this._register(this.viewModel);
|
||||
|
||||
addClass(this.listContainer, 'file-icon-themable-tree');
|
||||
addClass(this.listContainer, 'show-file-icons');
|
||||
|
||||
const updateIndentStyles = (theme: IFileIconTheme) => {
|
||||
toggleClass(this.listContainer, 'list-view-mode', this.viewModel.mode === ViewModelMode.List);
|
||||
toggleClass(this.listContainer, 'align-icons-and-twisties', this.viewModel.mode === ViewModelMode.Tree && theme.hasFileIcons && !theme.hasFolderIcons);
|
||||
toggleClass(this.listContainer, 'hide-arrows', this.viewModel.mode === ViewModelMode.Tree && theme.hidesExplorerArrows === true);
|
||||
};
|
||||
|
||||
updateIndentStyles(this.themeService.getFileIconTheme());
|
||||
this._register(this.themeService.onDidFileIconThemeChange(updateIndentStyles));
|
||||
this._register(this.viewModel.onDidChangeMode(() => updateIndentStyles(this.themeService.getFileIconTheme())));
|
||||
this.updateIndentStyles(this.themeService.getFileIconTheme());
|
||||
this._register(this.themeService.onDidFileIconThemeChange(this.updateIndentStyles, this));
|
||||
this._register(this.viewModel.onDidChangeMode(this.onDidChangeMode, this));
|
||||
|
||||
this.toggleViewModelModeAction = new ToggleViewModeAction(this.viewModel);
|
||||
this._register(this.toggleViewModelModeAction);
|
||||
@@ -719,6 +789,25 @@ export class RepositoryPanel extends ViewletPanel {
|
||||
this.updateActions();
|
||||
}
|
||||
|
||||
private updateIndentStyles(theme: IFileIconTheme): void {
|
||||
toggleClass(this.listContainer, 'list-view-mode', this.viewModel.mode === ViewModelMode.List);
|
||||
toggleClass(this.listContainer, 'tree-view-mode', this.viewModel.mode === ViewModelMode.Tree);
|
||||
toggleClass(this.listContainer, 'align-icons-and-twisties', this.viewModel.mode === ViewModelMode.Tree && theme.hasFileIcons && !theme.hasFolderIcons);
|
||||
toggleClass(this.listContainer, 'hide-arrows', this.viewModel.mode === ViewModelMode.Tree && theme.hidesExplorerArrows === true);
|
||||
}
|
||||
|
||||
private onDidChangeMode(): void {
|
||||
this.updateIndentStyles(this.themeService.getFileIconTheme());
|
||||
|
||||
const rootUri = this.repository.provider.rootUri;
|
||||
|
||||
if (typeof rootUri === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.storageService.store(`scm.repository.viewMode:${rootUri.toString()}`, this.viewModel.mode, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
layoutBody(height: number | undefined = this.cachedHeight, width: number | undefined = this.cachedWidth): void {
|
||||
if (height === undefined) {
|
||||
return;
|
||||
@@ -809,12 +898,16 @@ export class RepositoryPanel extends ViewletPanel {
|
||||
const element = e.element;
|
||||
let actions: IAction[] = [];
|
||||
|
||||
if (ResourceTree.isBranchNode(element)) {
|
||||
actions = this.menus.getResourceFolderContextActions(element.context);
|
||||
} else if (isSCMResource(element)) {
|
||||
actions = this.menus.getResourceContextActions(element);
|
||||
} else {
|
||||
if (isSCMResourceGroup(element)) {
|
||||
actions = this.menus.getResourceGroupContextActions(element);
|
||||
} else if (ResourceTree.isResourceNode(element)) {
|
||||
if (element.element) {
|
||||
actions = this.menus.getResourceContextActions(element.element);
|
||||
} else {
|
||||
actions = this.menus.getResourceFolderContextActions(element.context);
|
||||
}
|
||||
} else {
|
||||
actions = this.menus.getResourceContextActions(element);
|
||||
}
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
@@ -825,17 +918,24 @@ export class RepositoryPanel extends ViewletPanel {
|
||||
});
|
||||
}
|
||||
|
||||
private getSelectedResources(): (ISCMResource | IBranchNode<ISCMResource, ISCMResourceGroup>)[] {
|
||||
private getSelectedResources(): (ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>)[] {
|
||||
return this.tree.getSelection()
|
||||
.filter(r => !!r && !isSCMResourceGroup(r))! as any;
|
||||
}
|
||||
|
||||
private updateInputBox(): void {
|
||||
if (typeof this.repository.provider.commitTemplate === 'undefined' || !this.repository.input.visible || this.inputBox.value) {
|
||||
private onDidChangeCommitTemplate(): void {
|
||||
if (typeof this.repository.provider.commitTemplate === 'undefined' || !this.repository.input.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.inputBox.value = this.repository.provider.commitTemplate;
|
||||
const oldCommitTemplate = this.commitTemplate;
|
||||
this.commitTemplate = this.repository.provider.commitTemplate;
|
||||
|
||||
if (this.inputBox.value && this.inputBox.value !== oldCommitTemplate) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.inputBox.value = this.commitTemplate;
|
||||
}
|
||||
|
||||
private updateInputBoxVisibility(): void {
|
||||
|
||||
@@ -28,7 +28,7 @@ import { SCMService } from 'vs/workbench/contrib/scm/common/scmService';
|
||||
class OpenSCMViewletAction extends ShowViewletAction {
|
||||
|
||||
static readonly ID = VIEWLET_ID;
|
||||
static LABEL = localize('toggleGitViewlet', "Show Git");
|
||||
static readonly LABEL = localize('toggleGitViewlet', "Show Git");
|
||||
|
||||
constructor(id: string, label: string, @IViewletService viewletService: IViewletService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService) {
|
||||
super(id, label, VIEWLET_ID, viewletService, editorGroupService, layoutService);
|
||||
@@ -91,6 +91,16 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
|
||||
default: 3,
|
||||
description: localize('diffGutterWidth', "Controls the width(px) of diff decorations in gutter (added & modified).")
|
||||
},
|
||||
'scm.diffDecorationsGutterVisibility': {
|
||||
type: 'string',
|
||||
enum: ['always', 'hover'],
|
||||
enumDescriptions: [
|
||||
localize('scm.diffDecorationsGutterVisibility.always', "Show the diff decorator in the gutter at all times."),
|
||||
localize('scm.diffDecorationsGutterVisibility.hover', "Show the diff decorator in the gutter only on hover.")
|
||||
],
|
||||
description: localize('scm.diffDecorationsGutterVisibility', "Controls the visibilty of the Source Control diff decorator in the gutter."),
|
||||
default: 'always'
|
||||
},
|
||||
'scm.alwaysShowActions': {
|
||||
type: 'boolean',
|
||||
description: localize('alwaysShowActions', "Controls whether inline actions are always visible in the Source Control view."),
|
||||
@@ -115,8 +125,13 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
|
||||
localize('scm.defaultViewMode.list', "Show the repository changes as a list.")
|
||||
],
|
||||
description: localize('scm.defaultViewMode', "Controls the default Source Control repository view mode."),
|
||||
default: 'tree'
|
||||
}
|
||||
default: 'list'
|
||||
},
|
||||
'scm.autoReveal': {
|
||||
type: 'boolean',
|
||||
description: localize('autoReveal', "Controls whether the SCM view should automatically reveal and select files when opening them."),
|
||||
default: true
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel {
|
||||
|
||||
private static readonly STATE_KEY = 'workbench.scm.views.state';
|
||||
|
||||
private el: HTMLElement;
|
||||
private el!: HTMLElement;
|
||||
private message: HTMLElement;
|
||||
private menus: SCMMenus;
|
||||
private _repositories: ISCMRepository[] = [];
|
||||
|
||||
Reference in New Issue
Block a user