Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/vs/workbench/contrib/scm/browser/scm.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ModesRegistry } from 'vs/editor/common/languages/modesRegistry';
import { Codicon } from 'vs/base/common/codicons';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { SCMViewPane } from 'vs/workbench/contrib/scm/browser/scmViewPane';
import { ContextKeys, SCMViewPane } from 'vs/workbench/contrib/scm/browser/scmViewPane';
import { SCMViewService } from 'vs/workbench/contrib/scm/browser/scmViewService';
import { SCMRepositoriesViewPane } from 'vs/workbench/contrib/scm/browser/scmRepositoriesViewPane';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
Expand All @@ -34,6 +34,7 @@ import { IQuickDiffService } from 'vs/workbench/contrib/scm/common/quickDiff';
import { QuickDiffService } from 'vs/workbench/contrib/scm/common/quickDiffService';
import { getActiveElement } from 'vs/base/browser/dom';
import { SCMWorkingSetController } from 'vs/workbench/contrib/scm/browser/workingSet';
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';

ModesRegistry.registerLanguage({
id: 'scminput',
Expand Down Expand Up @@ -475,6 +476,32 @@ MenuRegistry.appendMenuItem(MenuId.SCMSourceControl, {
when: ContextKeyExpr.and(ContextKeyExpr.equals('scmProviderHasRootUri', true), ContextKeyExpr.or(ContextKeyExpr.equals('config.terminal.sourceControlRepositoriesKind', 'integrated'), ContextKeyExpr.equals('config.terminal.sourceControlRepositoriesKind', 'both')))
});

KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.scm.action.focusPreviousInput',
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeys.RepositoryVisibilityCount.notEqualsTo(0),
handler: async accessor => {
const viewsService = accessor.get(IViewsService);
const scmView = await viewsService.openView<SCMViewPane>(VIEW_PANE_ID);
if (scmView) {
scmView.focusPreviousInput();
}
}
});

KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.scm.action.focusNextInput',
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeys.RepositoryVisibilityCount.notEqualsTo(0),
handler: async accessor => {
const viewsService = accessor.get(IViewsService);
const scmView = await viewsService.openView<SCMViewPane>(VIEW_PANE_ID);
if (scmView) {
scmView.focusNextInput();
}
}
});

registerSingleton(ISCMService, SCMService, InstantiationType.Delayed);
registerSingleton(ISCMViewService, SCMViewService, InstantiationType.Delayed);
registerSingleton(IQuickDiffService, QuickDiffService, InstantiationType.Delayed);
71 changes: 37 additions & 34 deletions src/vs/workbench/contrib/scm/browser/scmViewPane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { FileKind } from 'vs/platform/files/common/files';
import { compareFileNames, comparePaths } from 'vs/base/common/comparers';
import { FuzzyScore, createMatches, IMatch } from 'vs/base/common/filters';
import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views';
import { localize, localize2 } from 'vs/nls';
import { localize } from 'vs/nls';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor';
import { SIDE_BAR_BACKGROUND, PANEL_BACKGROUND } from 'vs/workbench/common/theme';
Expand Down Expand Up @@ -100,7 +100,7 @@ import { foreground, listActiveSelectionForeground, registerColor, transparent }
import { IMenuWorkbenchToolBarOptions, MenuWorkbenchToolBar, WorkbenchToolBar } from 'vs/platform/actions/browser/toolbar';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { DropdownWithPrimaryActionViewItem } from 'vs/platform/actions/browser/dropdownWithPrimaryActionViewItem';
import { clamp } from 'vs/base/common/numbers';
import { clamp, rot } from 'vs/base/common/numbers';
import { ILogService } from 'vs/platform/log/common/log';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';
import { MarkdownString } from 'vs/base/common/htmlContent';
Expand All @@ -109,7 +109,6 @@ import { IHoverService } from 'vs/platform/hover/browser/hover';
import { OpenScmGroupAction } from 'vs/workbench/contrib/multiDiffEditor/browser/scmMultiDiffSourceResolver';
import { HoverController } from 'vs/editor/contrib/hover/browser/hoverController';
import { ITextModel } from 'vs/editor/common/model';
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';

// type SCMResourceTreeNode = IResourceNode<ISCMResource, ISCMResourceGroup>;
// type SCMHistoryItemChangeResourceTreeNode = IResourceNode<SCMHistoryItemChangeTreeElement, SCMHistoryItemTreeElement>;
Expand Down Expand Up @@ -1462,7 +1461,7 @@ const Menus = {
ChangesSettings: new MenuId('SCMChangesSettings'),
};

const ContextKeys = {
export const ContextKeys = {
SCMViewMode: new RawContextKey<ViewMode>('scmViewMode', ViewMode.List),
SCMViewSortKey: new RawContextKey<ViewSortKey>('scmViewSortKey', ViewSortKey.Path),
SCMViewAreAllRepositoriesCollapsed: new RawContextKey<boolean>('scmViewAreAllRepositoriesCollapsed', false),
Expand Down Expand Up @@ -1958,26 +1957,6 @@ class ExpandAllRepositoriesAction extends ViewAction<SCMViewPane> {
registerAction2(CollapseAllRepositoriesAction);
registerAction2(ExpandAllRepositoriesAction);

registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.scm.action.focusInput',
title: { ...localize2('focusInput', "Focus Input") },
category: localize2('source control', "Source Control"),
precondition: ContextKeys.RepositoryCount.notEqualsTo(0),
f1: true
});
}

override async run(accessor: ServicesAccessor) {
const viewsService = accessor.get(IViewsService);
const scmView = await viewsService.openView<SCMViewPane>(VIEW_PANE_ID);
if (scmView) {
scmView.focusInput();
}
}
});

const enum SCMInputWidgetCommandId {
CancelAction = 'scm.input.cancelAction'
}
Expand Down Expand Up @@ -3453,17 +3432,39 @@ export class SCMViewPane extends ViewPane {
}
}

focusInput(): void {
this.treeOperationSequencer.queue(() => {
return new Promise<void>(resolve => {
if (this.scmViewService.focusedRepository) {
this.tree.reveal(this.scmViewService.focusedRepository.input, 0.5);
this.inputRenderer.getRenderedInputWidget(this.scmViewService.focusedRepository.input)?.focus();
}
focusPreviousInput(): void {
this.treeOperationSequencer.queue(() => this.focusInput(-1));
}

resolve();
});
});
focusNextInput(): void {
this.treeOperationSequencer.queue(() => this.focusInput(1));
}

private async focusInput(delta: number): Promise<void> {
if (!this.scmViewService.focusedRepository ||
this.scmViewService.visibleRepositories.length === 0) {
return;
}

let input = this.scmViewService.focusedRepository.input;
const repositories = this.scmViewService.visibleRepositories;

// One visible repository and the input is already focused
if (repositories.length === 1 && this.inputRenderer.getRenderedInputWidget(input)?.hasFocus() === true) {
return;
}

// Multiple visible repositories and the input already focused
if (repositories.length > 1 && this.inputRenderer.getRenderedInputWidget(input)?.hasFocus() === true) {
const focusedRepositoryIndex = repositories.indexOf(this.scmViewService.focusedRepository);
const newFocusedRepositoryIndex = rot(focusedRepositoryIndex + delta, repositories.length);
input = repositories[newFocusedRepositoryIndex].input;
}

await this.tree.expandTo(input);

this.tree.reveal(input);
this.inputRenderer.getRenderedInputWidget(input)?.focus();
}

override shouldShowWelcome(): boolean {
Expand Down Expand Up @@ -3847,6 +3848,8 @@ class SCMTreeDataSource implements IAsyncDataSource<ISCMViewService, TreeElement
}

return result;
} else if (isSCMInput(element)) {
return element.repository;
} else {
throw new Error('Unexpected call to getParent');
}
Expand Down