mirror of
https://github.com/Microsoft/vscode
synced 2024-07-17 02:57:19 +00:00
Separate quick diff API from SCM (#170544)
* Separate quick diff API from SCM Part 1: split up the API. upcoming in part 2: In editor UX for multiple quick diffs. Fixes #169012 * Respond to review feedback Co-authored-by: João Moreno <joao.moreno@microsoft.com>
This commit is contained in:
parent
6d40104789
commit
04f0fb46ff
|
@ -45,6 +45,7 @@ import './mainThreadLogService';
|
|||
import './mainThreadMessageService';
|
||||
import './mainThreadOutputService';
|
||||
import './mainThreadProgress';
|
||||
import './mainThreadQuickDiff';
|
||||
import './mainThreadQuickOpen';
|
||||
import './mainThreadRemoteConnectionData';
|
||||
import './mainThreadSaveParticipant';
|
||||
|
|
54
src/vs/workbench/api/browser/mainThreadQuickDiff.ts
Normal file
54
src/vs/workbench/api/browser/mainThreadQuickDiff.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ExtHostContext, ExtHostQuickDiffShape, MainContext, MainThreadQuickDiffShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IQuickDiffService, QuickDiffProvider } from 'vs/workbench/contrib/scm/common/quickDiff';
|
||||
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadQuickDiff)
|
||||
export class MainThreadQuickDiff implements MainThreadQuickDiffShape {
|
||||
|
||||
private readonly proxy: ExtHostQuickDiffShape;
|
||||
private providers = new Map<number, QuickDiffProvider>();
|
||||
private providerDisposables = new Map<number, IDisposable>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IQuickDiffService private readonly quickDiffService: IQuickDiffService
|
||||
) {
|
||||
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostQuickDiff);
|
||||
}
|
||||
|
||||
async $registerQuickDiffProvider(handle: number, label: string, rootUri: UriComponents | undefined): Promise<void> {
|
||||
const provider: QuickDiffProvider = {
|
||||
label,
|
||||
rootUri: URI.revive(rootUri),
|
||||
getOriginalResource: async (uri: URI) => {
|
||||
return URI.revive(await this.proxy.$provideOriginalResource(handle, uri, new CancellationTokenSource().token));
|
||||
}
|
||||
};
|
||||
this.providers.set(handle, provider);
|
||||
const disposable = this.quickDiffService.addQuickDiffProvider(provider);
|
||||
this.providerDisposables.set(handle, disposable);
|
||||
}
|
||||
|
||||
async $unregisterQuickDiffProvider(handle: number): Promise<void> {
|
||||
if (this.providers.has(handle)) {
|
||||
this.providers.delete(handle);
|
||||
}
|
||||
if (this.providerDisposables.has(handle)) {
|
||||
this.providerDisposables.delete(handle);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.providers.clear();
|
||||
dispose(this.providerDisposables.values());
|
||||
this.providerDisposables.clear();
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
|||
import { MarshalledId } from 'vs/base/common/marshallingIds';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IQuickDiffService, QuickDiffProvider } from 'vs/workbench/contrib/scm/common/quickDiff';
|
||||
|
||||
class MainThreadSCMResourceGroup implements ISCMResourceGroup {
|
||||
|
||||
|
@ -89,7 +90,7 @@ class MainThreadSCMResource implements ISCMResource {
|
|||
}
|
||||
}
|
||||
|
||||
class MainThreadSCMProvider implements ISCMProvider {
|
||||
class MainThreadSCMProvider implements ISCMProvider, QuickDiffProvider {
|
||||
|
||||
private static ID_HANDLE = 0;
|
||||
private _id = `scm${MainThreadSCMProvider.ID_HANDLE++}`;
|
||||
|
@ -133,12 +134,15 @@ class MainThreadSCMProvider implements ISCMProvider {
|
|||
private readonly _onDidChange = new Emitter<void>();
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
private _quickDiff: IDisposable | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly proxy: ExtHostSCMShape,
|
||||
private readonly _handle: number,
|
||||
private readonly _contextValue: string,
|
||||
private readonly _label: string,
|
||||
private readonly _rootUri: URI | undefined
|
||||
private readonly _rootUri: URI | undefined,
|
||||
private readonly _quickDiffService: IQuickDiffService
|
||||
) { }
|
||||
|
||||
$updateSourceControl(features: SCMProviderFeatures): void {
|
||||
|
@ -152,6 +156,13 @@ class MainThreadSCMProvider implements ISCMProvider {
|
|||
if (typeof features.statusBarCommands !== 'undefined') {
|
||||
this._onDidChangeStatusBarCommands.fire(this.statusBarCommands!);
|
||||
}
|
||||
|
||||
if (features.hasQuickDiffProvider && !this._quickDiff) {
|
||||
this._quickDiff = this._quickDiffService.addQuickDiffProvider(this);
|
||||
} else if (features.hasQuickDiffProvider === false && this._quickDiff) {
|
||||
this._quickDiff.dispose();
|
||||
this._quickDiff = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
$registerGroups(_groups: [number /*handle*/, string /*id*/, string /*label*/, SCMGroupFeatures][]): void {
|
||||
|
@ -284,7 +295,8 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
|||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ISCMService private readonly scmService: ISCMService,
|
||||
@ISCMViewService private readonly scmViewService: ISCMViewService
|
||||
@ISCMViewService private readonly scmViewService: ISCMViewService,
|
||||
@IQuickDiffService private readonly quickDiffService: IQuickDiffService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSCM);
|
||||
}
|
||||
|
@ -300,7 +312,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
|||
}
|
||||
|
||||
$registerSourceControl(handle: number, id: string, label: string, rootUri: UriComponents | undefined): void {
|
||||
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri ? URI.revive(rootUri) : undefined);
|
||||
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri ? URI.revive(rootUri) : undefined, this.quickDiffService);
|
||||
const repository = this.scmService.registerSCMProvider(provider);
|
||||
this._repositories.set(handle, repository);
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/contrib/debu
|
|||
import { IExtHostLocalizationService } from 'vs/workbench/api/common/extHostLocalizationService';
|
||||
import { EditSessionIdentityMatch } from 'vs/platform/workspace/common/editSessions';
|
||||
import { ExtHostProfileContentHandlers } from 'vs/workbench/api/common/extHostProfileContentHandler';
|
||||
import { ExtHostQuickDiff } from 'vs/workbench/api/common/extHostQuickDiff';
|
||||
|
||||
export interface IExtensionRegistries {
|
||||
mine: ExtensionDescriptionRegistry;
|
||||
|
@ -175,6 +176,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostLogService, extHostDocumentsAndEditors));
|
||||
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, createExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
|
||||
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
|
||||
const extHostQuickDiff = rpcProtocol.set(ExtHostContext.ExtHostQuickDiff, new ExtHostQuickDiff(rpcProtocol));
|
||||
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, createExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
|
@ -802,6 +804,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
checkProposedApiEnabled(extension, 'profileContentHandlers');
|
||||
return extHostProfileContentHandlers.registrProfileContentHandler(extension, id, handler);
|
||||
},
|
||||
async registerQuickDiffProvider(quickDiffProvider: vscode.QuickDiffProvider, label: string, rootUri?: vscode.Uri): Promise<vscode.Disposable> {
|
||||
checkProposedApiEnabled(extension, 'quickDiffProvider');
|
||||
return extHostQuickDiff.registerQuickDiffProvider(quickDiffProvider, label, rootUri);
|
||||
},
|
||||
get tabGroups(): vscode.TabGroups {
|
||||
return extHostEditorTabs.tabGroups;
|
||||
}
|
||||
|
|
|
@ -1237,6 +1237,11 @@ export interface MainThreadSCMShape extends IDisposable {
|
|||
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void;
|
||||
}
|
||||
|
||||
export interface MainThreadQuickDiffShape extends IDisposable {
|
||||
$registerQuickDiffProvider(handle: number, label: string, rootUri: UriComponents | undefined): Promise<void>;
|
||||
$unregisterQuickDiffProvider(handle: number): Promise<void>;
|
||||
}
|
||||
|
||||
export type DebugSessionUUID = string;
|
||||
|
||||
export interface IDebugConfiguration {
|
||||
|
@ -1869,6 +1874,10 @@ export interface ExtHostSCMShape {
|
|||
$setSelectedSourceControl(selectedSourceControlHandle: number | undefined): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostQuickDiffShape {
|
||||
$provideOriginalResource(sourceControlHandle: number, uri: UriComponents, token: CancellationToken): Promise<UriComponents | null>;
|
||||
}
|
||||
|
||||
export interface ExtHostTaskShape {
|
||||
$provideTasks(handle: number, validTypes: { [key: string]: boolean }): Promise<tasks.ITaskSetDTO>;
|
||||
$resolveTask(handle: number, taskDTO: tasks.ITaskDTO): Promise<tasks.ITaskDTO | undefined>;
|
||||
|
@ -2333,6 +2342,7 @@ export const MainContext = {
|
|||
MainThreadMessageService: createProxyIdentifier<MainThreadMessageServiceShape>('MainThreadMessageService'),
|
||||
MainThreadOutputService: createProxyIdentifier<MainThreadOutputServiceShape>('MainThreadOutputService'),
|
||||
MainThreadProgress: createProxyIdentifier<MainThreadProgressShape>('MainThreadProgress'),
|
||||
MainThreadQuickDiff: createProxyIdentifier<MainThreadQuickDiffShape>('MainThreadQuickDiff'),
|
||||
MainThreadQuickOpen: createProxyIdentifier<MainThreadQuickOpenShape>('MainThreadQuickOpen'),
|
||||
MainThreadStatusBar: createProxyIdentifier<MainThreadStatusBarShape>('MainThreadStatusBar'),
|
||||
MainThreadSecretState: createProxyIdentifier<MainThreadSecretStateShape>('MainThreadSecretState'),
|
||||
|
@ -2385,6 +2395,7 @@ export const ExtHostContext = {
|
|||
ExtHostLanguages: createProxyIdentifier<ExtHostLanguagesShape>('ExtHostLanguages'),
|
||||
ExtHostLanguageFeatures: createProxyIdentifier<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
|
||||
ExtHostQuickOpen: createProxyIdentifier<ExtHostQuickOpenShape>('ExtHostQuickOpen'),
|
||||
ExtHostQuickDiff: createProxyIdentifier<ExtHostQuickDiffShape>('ExtHostQuickDiff'),
|
||||
ExtHostExtensionService: createProxyIdentifier<ExtHostExtensionServiceShape>('ExtHostExtensionService'),
|
||||
ExtHostLogLevelServiceShape: createProxyIdentifier<ExtHostLogLevelServiceShape>('ExtHostLogLevelServiceShape'),
|
||||
ExtHostTerminalService: createProxyIdentifier<ExtHostTerminalServiceShape>('ExtHostTerminalService'),
|
||||
|
|
44
src/vs/workbench/api/common/extHostQuickDiff.ts
Normal file
44
src/vs/workbench/api/common/extHostQuickDiff.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import type * as vscode from 'vscode';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ExtHostQuickDiffShape, IMainContext, MainContext, MainThreadQuickDiffShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
|
||||
export class ExtHostQuickDiff implements ExtHostQuickDiffShape {
|
||||
private static handlePool: number = 0;
|
||||
|
||||
private proxy: MainThreadQuickDiffShape;
|
||||
private providers: Map<number, vscode.QuickDiffProvider> = new Map();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext
|
||||
) {
|
||||
this.proxy = mainContext.getProxy(MainContext.MainThreadQuickDiff);
|
||||
}
|
||||
|
||||
$provideOriginalResource(handle: number, uriComponents: UriComponents, token: CancellationToken): Promise<UriComponents | null> {
|
||||
const uri = URI.revive(uriComponents);
|
||||
const provider = this.providers.get(handle);
|
||||
|
||||
if (!provider) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return asPromise(() => provider.provideOriginalResource!(uri, token))
|
||||
.then<UriComponents | null>(r => r || null);
|
||||
}
|
||||
|
||||
async registerQuickDiffProvider(quickDiffProvider: vscode.QuickDiffProvider, label: string, rootUri?: vscode.Uri): Promise<vscode.Disposable> {
|
||||
const handle = ExtHostQuickDiff.handlePool++;
|
||||
this.providers.set(handle, quickDiffProvider);
|
||||
await this.proxy.$registerQuickDiffProvider(handle, label, rootUri);
|
||||
return {
|
||||
dispose: () => this.providers.delete(handle)
|
||||
};
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
|||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Progress } from 'vs/platform/progress/common/progress';
|
||||
import { getOriginalResource } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator';
|
||||
import { ISCMService } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { IQuickDiffService } from 'vs/workbench/contrib/scm/common/quickDiff';
|
||||
|
||||
registerEditorAction(class FormatModifiedAction extends EditorAction {
|
||||
|
||||
|
@ -50,11 +50,11 @@ registerEditorAction(class FormatModifiedAction extends EditorAction {
|
|||
|
||||
|
||||
export async function getModifiedRanges(accessor: ServicesAccessor, modified: ITextModel): Promise<Range[] | undefined | null> {
|
||||
const scmService = accessor.get(ISCMService);
|
||||
const quickDiffService = accessor.get(IQuickDiffService);
|
||||
const workerService = accessor.get(IEditorWorkerService);
|
||||
const modelService = accessor.get(ITextModelService);
|
||||
|
||||
const original = await getOriginalResource(scmService, modified.uri);
|
||||
const original = await getOriginalResource(quickDiffService, modified.uri);
|
||||
if (!original) {
|
||||
return null; // let undefined signify no changes, null represents no source control (there's probably a better way, but I can't think of one rn)
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as nls from 'vs/nls';
|
||||
|
||||
import 'vs/css!./media/dirtydiffDecorator';
|
||||
import { ThrottledDelayer, first } from 'vs/base/common/async';
|
||||
import { ThrottledDelayer } from 'vs/base/common/async';
|
||||
import { IDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as ext from 'vs/workbench/common/contributions';
|
||||
|
@ -15,7 +15,7 @@ import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/se
|
|||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ISCMService, ISCMRepository, ISCMProvider } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { ISCMService, ISCMRepository } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { IColorTheme, themeColorFromId, IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { editorErrorForeground, registerColor, transparent } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
@ -34,7 +34,7 @@ import { IDiffEditorOptions, EditorOption } from 'vs/editor/common/config/editor
|
|||
import { Action, IAction, ActionRunner } from 'vs/base/common/actions';
|
||||
import { IActionBarOptions } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { basename, isEqualOrParent } from 'vs/base/common/resources';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { MenuId, IMenuService, IMenu, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IEditorModel, ScrollType, IEditorContribution, IDiffEditorModel } from 'vs/editor/common/editorCommon';
|
||||
|
@ -51,13 +51,13 @@ import { TextCompareEditorActiveContext } from 'vs/workbench/common/contextkeys'
|
|||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IChange } from 'vs/editor/common/diff/smartLinesDiffComputer';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
|
||||
import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IQuickDiffService } from 'vs/workbench/contrib/scm/common/quickDiff';
|
||||
|
||||
class DiffActionRunner extends ActionRunner {
|
||||
|
||||
|
@ -1095,37 +1095,10 @@ function compareChanges(a: IChange, b: IChange): number {
|
|||
return a.originalEndLineNumber - b.originalEndLineNumber;
|
||||
}
|
||||
|
||||
export 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 async function getOriginalResource(scmService: ISCMService, uri: URI): Promise<URI | null> {
|
||||
const providers = Iterable.map(scmService.repositories, r => r.provider);
|
||||
const rootedProviders = Array.from(Iterable.filter(providers, p => !!p.rootUri));
|
||||
|
||||
rootedProviders.sort(createProviderComparer(uri));
|
||||
|
||||
const result = await first(rootedProviders.map(p => () => p.getOriginalResource(uri)));
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const nonRootedProviders = Iterable.filter(providers, p => !p.rootUri);
|
||||
return first(Array.from(nonRootedProviders, p => () => p.getOriginalResource(uri)));
|
||||
export async function getOriginalResource(quickDiffService: IQuickDiffService, uri: URI): Promise<URI | null> {
|
||||
const quickDiffs = await quickDiffService.getQuickDiffs(uri);
|
||||
return quickDiffs.length > 0 ? quickDiffs[0].originalResource : null;
|
||||
}
|
||||
|
||||
export class DirtyDiffModel extends Disposable {
|
||||
|
@ -1151,6 +1124,7 @@ export class DirtyDiffModel extends Disposable {
|
|||
constructor(
|
||||
textFileModel: IResolvedTextFileEditorModel,
|
||||
@ISCMService private readonly scmService: ISCMService,
|
||||
@IQuickDiffService private readonly quickDiffService: IQuickDiffService,
|
||||
@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@ITextModelService private readonly textModelResolverService: ITextModelService,
|
||||
|
@ -1306,7 +1280,7 @@ export class DirtyDiffModel extends Disposable {
|
|||
}
|
||||
|
||||
const uri = this._model.resource;
|
||||
return getOriginalResource(this.scmService, uri);
|
||||
return getOriginalResource(this.quickDiffService, uri);
|
||||
}
|
||||
|
||||
findNextClosestChange(lineNumber: number, inclusive = true): number {
|
||||
|
|
|
@ -30,6 +30,8 @@ import { SCMRepositoriesViewPane } from 'vs/workbench/contrib/scm/browser/scmRep
|
|||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Context as SuggestContext } from 'vs/editor/contrib/suggest/browser/suggest';
|
||||
import { MANAGE_TRUST_COMMAND_ID, WorkspaceTrustContext } from 'vs/workbench/contrib/workspace/common/workspace';
|
||||
import { IQuickDiffService } from 'vs/workbench/contrib/scm/common/quickDiff';
|
||||
import { QuickDiffService } from 'vs/workbench/contrib/scm/common/quickDiffService';
|
||||
|
||||
ModesRegistry.registerLanguage({
|
||||
id: 'scminput',
|
||||
|
@ -385,3 +387,4 @@ MenuRegistry.appendMenuItem(MenuId.SCMSourceControl, {
|
|||
|
||||
registerSingleton(ISCMService, SCMService, InstantiationType.Delayed);
|
||||
registerSingleton(ISCMViewService, SCMViewService, InstantiationType.Delayed);
|
||||
registerSingleton(IQuickDiffService, QuickDiffService, InstantiationType.Delayed);
|
||||
|
|
28
src/vs/workbench/contrib/scm/common/quickDiff.ts
Normal file
28
src/vs/workbench/contrib/scm/common/quickDiff.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export const IQuickDiffService = createDecorator<IQuickDiffService>('quickDiff');
|
||||
|
||||
export interface QuickDiffProvider {
|
||||
label: string;
|
||||
rootUri: URI | undefined;
|
||||
getOriginalResource(uri: URI): Promise<URI | null>;
|
||||
}
|
||||
|
||||
export interface QuickDiff {
|
||||
label: string;
|
||||
originalResource: URI;
|
||||
}
|
||||
|
||||
export interface IQuickDiffService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
addQuickDiffProvider(quickDiff: QuickDiffProvider): IDisposable;
|
||||
getQuickDiffs(uri: URI): Promise<QuickDiff[]>;
|
||||
}
|
66
src/vs/workbench/contrib/scm/common/quickDiffService.ts
Normal file
66
src/vs/workbench/contrib/scm/common/quickDiffService.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IQuickDiffService, QuickDiff, QuickDiffProvider } from 'vs/workbench/contrib/scm/common/quickDiff';
|
||||
import { isEqualOrParent } from 'vs/base/common/resources';
|
||||
|
||||
function createProviderComparer(uri: URI): (a: QuickDiffProvider, b: QuickDiffProvider) => number {
|
||||
return (a, b) => {
|
||||
if (a.rootUri && !b.rootUri) {
|
||||
return -1;
|
||||
} else if (!a.rootUri && b.rootUri) {
|
||||
return 1;
|
||||
} else if (!a.rootUri && !b.rootUri) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 QuickDiffService implements IQuickDiffService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private quickDiffProviders: Set<QuickDiffProvider> = new Set();
|
||||
|
||||
addQuickDiffProvider(quickDiff: QuickDiffProvider): IDisposable {
|
||||
this.quickDiffProviders.add(quickDiff);
|
||||
return {
|
||||
dispose: () => {
|
||||
this.quickDiffProviders.delete(quickDiff);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private isQuickDiff(diff: { originalResource: URI | null; label: string }): diff is QuickDiff {
|
||||
return !!diff.originalResource;
|
||||
}
|
||||
|
||||
async getQuickDiffs(uri: URI): Promise<QuickDiff[]> {
|
||||
const sorted = Array.from(this.quickDiffProviders).sort(createProviderComparer(uri));
|
||||
|
||||
const diffs = await Promise.all(Array.from(sorted.values()).map(async (provider) => {
|
||||
const diff = {
|
||||
originalResource: await provider.getOriginalResource(uri),
|
||||
label: provider.label
|
||||
};
|
||||
return diff;
|
||||
}));
|
||||
return diffs.filter<QuickDiff>(this.isQuickDiff);
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@ export const allApiProposals = Object.freeze({
|
|||
notebookMime: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookMime.d.ts',
|
||||
portsAttributes: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.portsAttributes.d.ts',
|
||||
profileContentHandlers: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.profileContentHandlers.d.ts',
|
||||
quickDiffProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickDiffProvider.d.ts',
|
||||
quickPickSortByLabel: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickSortByLabel.d.ts',
|
||||
resolvers: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.resolvers.d.ts',
|
||||
scmActionButton: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmActionButton.d.ts',
|
||||
|
|
13
src/vscode-dts/vscode.proposed.quickDiffProvider.d.ts
vendored
Normal file
13
src/vscode-dts/vscode.proposed.quickDiffProvider.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
// https://github.com/microsoft/vscode/issues/169012
|
||||
|
||||
export namespace window {
|
||||
export function registerQuickDiffProvider(quickDiffProvider: QuickDiffProvider, label: string, rootUri?: Uri): Thenable<Disposable>;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue