提交 48b58bdf 编写于 作者: J Joao

scm: use diff algorithm for ext host communication

上级 e34900af
...@@ -13,7 +13,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; ...@@ -13,7 +13,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations } from 'vs/workbench/services/scm/common/scm'; import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations } from 'vs/workbench/services/scm/common/scm';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICommandService } from 'vs/platform/commands/common/commands';
import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceGroup, SCMGroupFeatures, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { Command } from 'vs/editor/common/modes'; import { Command } from 'vs/editor/common/modes';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
...@@ -155,36 +155,43 @@ class MainThreadSCMProvider implements ISCMProvider { ...@@ -155,36 +155,43 @@ class MainThreadSCMProvider implements ISCMProvider {
this._onDidChange.fire(); this._onDidChange.fire();
} }
$updateGroupResourceStates(groups: SCMRawResourceGroup[]): void { $spliceGroupResourceStates(slices: SCMRawResourceSplices[]): void {
for (const [groupHandle, resources] of groups) { for (const [groupHandle, groupSlices] of slices) {
const group = this._groupsByHandle[groupHandle]; const group = this._groupsByHandle[groupHandle];
if (!group) { if (!group) {
return; return;
} }
group.resources = resources.map(rawResource => { // reverse the splices sequence in order to apply them correctly
const [handle, sourceUri, command, icons, tooltip, strikeThrough, faded] = rawResource; groupSlices.reverse();
const icon = icons[0];
const iconDark = icons[1] || icon; for (const [start, deleteCount, rawResources] of groupSlices) {
const decorations = { const resources = rawResources.map(rawResource => {
icon: icon && URI.parse(icon), const [handle, sourceUri, command, icons, tooltip, strikeThrough, faded] = rawResource;
iconDark: iconDark && URI.parse(iconDark), const icon = icons[0];
tooltip, const iconDark = icons[1] || icon;
strikeThrough, const decorations = {
faded icon: icon && URI.parse(icon),
}; iconDark: iconDark && URI.parse(iconDark),
tooltip,
return new MainThreadSCMResource( strikeThrough,
this.handle, faded
groupHandle, };
handle,
URI.parse(sourceUri), return new MainThreadSCMResource(
command, this.handle,
group, groupHandle,
decorations handle,
); URI.parse(sourceUri),
}); command,
group,
decorations
);
});
group.resources.splice(start, deleteCount, ...resources);
}
} }
this._onDidChangeResources.fire(); this._onDidChangeResources.fire();
...@@ -317,7 +324,7 @@ export class MainThreadSCM implements MainThreadSCMShape { ...@@ -317,7 +324,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
provider.$updateGroupLabel(groupHandle, label); provider.$updateGroupLabel(groupHandle, label);
} }
$updateResourceStates(sourceControlHandle: number, resources: SCMRawResourceGroup[]): void { $spliceResourceStates(sourceControlHandle: number, splices: SCMRawResourceSplices[]): void {
const repository = this._repositories[sourceControlHandle]; const repository = this._repositories[sourceControlHandle];
if (!repository) { if (!repository) {
...@@ -325,7 +332,7 @@ export class MainThreadSCM implements MainThreadSCMShape { ...@@ -325,7 +332,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
} }
const provider = repository.provider as MainThreadSCMProvider; const provider = repository.provider as MainThreadSCMProvider;
provider.$updateGroupResourceStates(resources); provider.$spliceGroupResourceStates(splices);
} }
$unregisterGroup(sourceControlHandle: number, handle: number): void { $unregisterGroup(sourceControlHandle: number, handle: number): void {
......
...@@ -337,11 +337,17 @@ export type SCMRawResource = [ ...@@ -337,11 +337,17 @@ export type SCMRawResource = [
boolean /*faded*/ boolean /*faded*/
]; ];
export type SCMRawResourceGroup = [ export type SCMRawResourceSplice = [
number, /*handle*/ number /* start */,
number /* delete count */,
SCMRawResource[] SCMRawResource[]
]; ];
export type SCMRawResourceSplices = [
number, /*handle*/
SCMRawResourceSplice[]
];
export interface MainThreadSCMShape extends IDisposable { export interface MainThreadSCMShape extends IDisposable {
$registerSourceControl(handle: number, id: string, label: string): void; $registerSourceControl(handle: number, id: string, label: string): void;
$updateSourceControl(handle: number, features: SCMProviderFeatures): void; $updateSourceControl(handle: number, features: SCMProviderFeatures): void;
...@@ -352,7 +358,7 @@ export interface MainThreadSCMShape extends IDisposable { ...@@ -352,7 +358,7 @@ export interface MainThreadSCMShape extends IDisposable {
$updateGroupLabel(sourceControlHandle: number, handle: number, label: string): void; $updateGroupLabel(sourceControlHandle: number, handle: number, label: string): void;
$unregisterGroup(sourceControlHandle: number, handle: number): void; $unregisterGroup(sourceControlHandle: number, handle: number): void;
$updateResourceStates(sourceControlHandle: number, resources: SCMRawResourceGroup[]): void; $spliceResourceStates(sourceControlHandle: number, splices: SCMRawResourceSplices[]): void;
$setInputBoxValue(sourceControlHandle: number, value: string): void; $setInputBoxValue(sourceControlHandle: number, value: string): void;
} }
......
...@@ -12,8 +12,9 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle'; ...@@ -12,8 +12,9 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { asWinJsPromise } from 'vs/base/common/async'; import { asWinJsPromise } from 'vs/base/common/async';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceGroup, IMainContext } from './extHost.protocol'; import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext } from './extHost.protocol';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { LcsDiff, ISequence } from 'vs/base/common/diff/diff';
function getIconPath(decorations: vscode.SourceControlResourceThemableDecorations) { function getIconPath(decorations: vscode.SourceControlResourceThemableDecorations) {
if (!decorations) { if (!decorations) {
...@@ -59,6 +60,22 @@ export class ExtHostSCMInputBox { ...@@ -59,6 +60,22 @@ export class ExtHostSCMInputBox {
} }
} }
class ResourceSequence implements ISequence {
constructor(private resources: vscode.SourceControlResourceState[]) { }
getLength() {
return this.resources.length;
}
getElementHash(index) {
const resource = this.resources[index];
// TODO!!!
return resource.resourceUri.toString();
}
}
class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceGroup { class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceGroup {
private static _handlePool: number = 0; private static _handlePool: number = 0;
...@@ -73,6 +90,9 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG ...@@ -73,6 +90,9 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
private _onDidDispose = new Emitter<void>(); private _onDidDispose = new Emitter<void>();
readonly onDidDispose = this._onDidDispose.event; readonly onDidDispose = this._onDidDispose.event;
private _handlesSnapshot: number[] = [];
private _resourcesSnapshot: vscode.SourceControlResourceState[] = [];
get id(): string { return this._id; } get id(): string { return this._id; }
get label(): string { return this._label; } get label(): string { return this._label; }
...@@ -94,43 +114,61 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG ...@@ -94,43 +114,61 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
this._onDidUpdateResourceStates.fire(); this._onDidUpdateResourceStates.fire();
} }
get _rawResources(): SCMRawResource[] { _snapshot(): SCMRawResourceSplice[] {
const handles: number[] = []; const original = new ResourceSequence(this._resourcesSnapshot);
const rawResources = this._resourceStates.map(r => { const modified = new ResourceSequence(this._resourceStates);
const handle = this._resourceHandlePool++; const lcs = new LcsDiff(original, modified);
this._resourceStatesMap.set(handle, r); const diffs = lcs.ComputeDiff(false);
handles.push(handle); const handlesToDelete: number[] = [];
const splices = diffs.map(diff => {
const start = diff.originalStart;
const deleteCount = diff.originalLength;
const handles: number[] = [];
const rawResources = this._resourceStates
.slice(diff.modifiedStart, diff.modifiedStart + diff.modifiedLength)
.map(r => {
const handle = this._resourceHandlePool++;
this._resourceStatesMap.set(handle, r);
handles.push(handle);
const sourceUri = r.resourceUri.toString();
const command = this._commands.toInternal(r.command);
const iconPath = getIconPath(r.decorations);
const lightIconPath = r.decorations && getIconPath(r.decorations.light) || iconPath;
const darkIconPath = r.decorations && getIconPath(r.decorations.dark) || iconPath;
const icons: string[] = [];
if (lightIconPath || darkIconPath) {
icons.push(lightIconPath);
}
const sourceUri = r.resourceUri.toString(); if (darkIconPath !== lightIconPath) {
const command = this._commands.toInternal(r.command); icons.push(darkIconPath);
const iconPath = getIconPath(r.decorations); }
const lightIconPath = r.decorations && getIconPath(r.decorations.light) || iconPath;
const darkIconPath = r.decorations && getIconPath(r.decorations.dark) || iconPath;
const icons: string[] = [];
if (lightIconPath || darkIconPath) { const tooltip = (r.decorations && r.decorations.tooltip) || '';
icons.push(lightIconPath); const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
} const faded = r.decorations && !!r.decorations.faded;
if (darkIconPath !== lightIconPath) { return [handle, sourceUri, command, icons, tooltip, strikeThrough, faded] as SCMRawResource;
icons.push(darkIconPath); });
}
const tooltip = (r.decorations && r.decorations.tooltip) || ''; handlesToDelete.push(...this._handlesSnapshot.splice(start, deleteCount, ...handles));
const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
const faded = r.decorations && !!r.decorations.faded;
return [handle, sourceUri, command, icons, tooltip, strikeThrough, faded] as SCMRawResource; return [start, deleteCount, rawResources] as SCMRawResourceSplice;
}); });
const disposable = () => handles.forEach(handle => this._resourceStatesMap.delete(handle)); const disposable = () => handlesToDelete.forEach(handle => this._resourceStatesMap.delete(handle));
this._resourceStatesRollingDisposables.push(disposable); this._resourceStatesRollingDisposables.push(disposable);
while (this._resourceStatesRollingDisposables.length >= 10) { while (this._resourceStatesRollingDisposables.length >= 10) {
this._resourceStatesRollingDisposables.shift()(); this._resourceStatesRollingDisposables.shift()();
} }
return rawResources; this._resourcesSnapshot = this._resourceStates;
return splices;
} }
readonly handle = ExtHostSourceControlResourceGroup._handlePool++; readonly handle = ExtHostSourceControlResourceGroup._handlePool++;
...@@ -266,12 +304,12 @@ class ExtHostSourceControl implements vscode.SourceControl { ...@@ -266,12 +304,12 @@ class ExtHostSourceControl implements vscode.SourceControl {
@debounce(100) @debounce(100)
eventuallyUpdateResourceStates(): void { eventuallyUpdateResourceStates(): void {
const resources: SCMRawResourceGroup[] = []; const resources: SCMRawResourceSplices[] = [];
this.updatedResourceGroups this.updatedResourceGroups
.forEach(group => resources.push([group.handle, group._rawResources])); .forEach(group => resources.push([group.handle, group._snapshot()]));
this._proxy.$updateResourceStates(this.handle, resources); this._proxy.$spliceResourceStates(this.handle, resources);
this.updatedResourceGroups.clear(); this.updatedResourceGroups.clear();
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册