提交 41f0ff15 编写于 作者: J Johannes Rieken

deco - move scm decorations to git extension

上级 015901f1
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { window, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider } from 'vscode';
import { Repository, GitResourceGroup } from './repository';
import { Model } from './model';
class GitDecorationProvider implements DecorationProvider {
private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
readonly onDidChangeDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
private disposables: Disposable[] = [];
private decorations = new Map<string, DecorationData>();
constructor(private repository: Repository) {
this.disposables.push(
window.registerDecorationProvider(this, repository.root),
repository.onDidRunOperation(this.onDidRunOperation, this)
);
}
private onDidRunOperation(): void {
let newDecorations = new Map<string, DecorationData>();
this.collectDecorationData(this.repository.indexGroup, newDecorations);
this.collectDecorationData(this.repository.workingTreeGroup, newDecorations);
let uris: Uri[] = [];
newDecorations.forEach((value, uriString) => {
if (this.decorations.has(uriString)) {
this.decorations.delete(uriString);
} else {
uris.push(Uri.parse(uriString));
}
});
this.decorations.forEach((value, uriString) => {
uris.push(Uri.parse(uriString));
});
this.decorations = newDecorations;
this._onDidChangeDecorations.fire(uris);
}
private collectDecorationData(group: GitResourceGroup, bucket: Map<string, DecorationData>): void {
group.resourceStates.forEach(r => {
if (r.resourceDecoration) {
bucket.set(r.original.toString(), r.resourceDecoration);
}
});
}
provideDecoration(uri: Uri): DecorationData | undefined {
return this.decorations.get(uri.toString());
}
dispose(): void {
this.disposables.forEach(d => d.dispose());
}
}
export class GitDecorations {
private disposables: Disposable[] = [];
private providers = new Map<Repository, GitDecorationProvider>();
constructor(private model: Model) {
this.disposables.push(
model.onDidOpenRepository(this.onDidOpenRepository, this),
model.onDidCloseRepository(this.onDidCloseRepository, this)
);
model.repositories.forEach(this.onDidOpenRepository, this);
}
private onDidOpenRepository(repository: Repository): void {
const provider = new GitDecorationProvider(repository);
this.providers.set(repository, provider);
}
private onDidCloseRepository(repository: Repository): void {
const provider = this.providers.get(repository);
if (provider) {
provider.dispose();
this.providers.delete(repository);
}
}
dispose(): void {
this.disposables.forEach(d => d.dispose());
this.providers.forEach(value => value.dispose);
this.providers.clear();
}
}
......@@ -12,6 +12,7 @@ import { findGit, Git, IGit } from './git';
import { Model } from './model';
import { CommandCenter } from './commands';
import { GitContentProvider } from './contentProvider';
import { GitDecorations } from './decorationProvider';
import { Askpass } from './askpass';
import { toDisposable } from './util';
import TelemetryReporter from 'vscode-extension-telemetry';
......@@ -54,6 +55,7 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi
disposables.push(
new CommandCenter(git, model, outputChannel, telemetryReporter),
new GitContentProvider(model),
new GitDecorations(model)
);
await checkGitVersion(info);
......@@ -93,4 +95,4 @@ async function checkGitVersion(info: IGit): Promise<void> {
} else if (choice === neverShowAgain) {
await config.update('ignoreLegacyWarning', true, true);
}
}
\ No newline at end of file
}
......@@ -5,7 +5,7 @@
'use strict';
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor } from 'vscode';
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData } from 'vscode';
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType } from './git';
import { anyEvent, filterEvent, eventToPromise, dispose, find } from './util';
import { memoize, throttle, debounce } from './decorators';
......@@ -170,27 +170,29 @@ export class Resource implements SourceControlResourceState {
// return this.resourceUri.fsPath.substr(0, workspaceRootPath.length) !== workspaceRootPath;
}
private get color(): ThemeColor | undefined {
switch (this.type) {
case Status.INDEX_MODIFIED:
case Status.MODIFIED:
return new ThemeColor('git.color.modified');
case Status.UNTRACKED:
return new ThemeColor('git.color.untracked');
default:
return undefined;
}
}
get decorations(): SourceControlResourceDecorations {
const light = { iconPath: this.getIconPath('light') };
const dark = { iconPath: this.getIconPath('dark') };
const tooltip = this.tooltip;
const strikeThrough = this.strikeThrough;
const faded = this.faded;
const color = this.color;
return { strikeThrough, faded, tooltip, light, dark, color };
return { strikeThrough, faded, tooltip, light, dark };
}
get resourceDecoration(): DecorationData | undefined {
const title = this.tooltip;
switch (this.type) {
case Status.IGNORED:
return { priority: 3, title, opacity: 0.75 };
case Status.UNTRACKED:
return { priority: 1, title, abbreviation: localize('untracked, short', "U"), bubble: true, color: new ThemeColor('git.color.untracked') };
case Status.INDEX_MODIFIED:
case Status.MODIFIED:
return { priority: 2, title, abbreviation: localize('modified, short', "M"), bubble: true, color: new ThemeColor('git.color.modified') };
default:
return undefined;
}
}
constructor(
......
......@@ -5795,12 +5795,6 @@ declare module 'vscode' {
*/
readonly tooltip?: string;
/**
* A color for a specific
* [source control resource state](#SourceControlResourceState).
*/
readonly color?: ThemeColor;
/**
* The light theme decorations.
*/
......
......@@ -175,6 +175,7 @@ declare module 'vscode' {
export interface DecorationData {
priority?: number;
title?: string;
bubble?: boolean;
abbreviation?: string;
color?: ThemeColor;
opacity?: number;
......
......@@ -36,9 +36,13 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
onDidChange: emitter.event,
provideDecorations: (uri) => {
return this._proxy.$providerDecorations(handle, uri).then(data => {
const [weight, title, letter, opacity, themeColor] = data;
if (!data) {
return undefined;
}
const [weight, bubble, title, letter, opacity, themeColor] = data;
return {
weight: weight || 0,
bubble: bubble || false,
title,
letter,
opacity,
......
......@@ -182,7 +182,7 @@ class MainThreadSCMProvider implements ISCMProvider {
for (const [start, deleteCount, rawResources] of groupSlices) {
const resources = rawResources.map(rawResource => {
const [handle, sourceUri, icons, tooltip, strikeThrough, faded, color] = rawResource;
const [handle, sourceUri, icons, tooltip, strikeThrough, faded] = rawResource;
const icon = icons[0];
const iconDark = icons[1] || icon;
const decorations = {
......@@ -190,8 +190,7 @@ class MainThreadSCMProvider implements ISCMProvider {
iconDark: iconDark && URI.parse(iconDark),
tooltip,
strikeThrough,
faded,
color: color && color.id
faded
};
return new MainThreadSCMResource(
......
......@@ -362,8 +362,7 @@ export type SCMRawResource = [
string[] /*icons: light, dark*/,
string /*tooltip*/,
boolean /*strike through*/,
boolean /*faded*/,
{ id: string } /*ThemeColor*/
boolean /*faded*/
];
export type SCMRawResourceSplice = [
......@@ -603,7 +602,7 @@ export interface ExtHostDebugServiceShape {
}
export type DecorationData = [number, string, string, number, ThemeColor];
export type DecorationData = [number, boolean, string, string, number, ThemeColor];
export interface ExtHostDecorationsShape {
$providerDecorations(handle: number, uri: URI): TPromise<DecorationData>;
......
......@@ -41,7 +41,7 @@ export class ExtHostDecorations implements ExtHostDecorationsShape {
$providerDecorations(handle: number, uri: URI): TPromise<DecorationData> {
const provider = this._provider.get(handle);
return asWinJsPromise(token => provider.provideDecoration(uri, token)).then(data => {
return <DecorationData>[data.priority, data.title, data.abbreviation, data.opacity, data.color];
return data && <DecorationData>[data.priority, data.bubble, data.title, data.abbreviation, data.opacity, data.color];
});
}
}
......@@ -243,9 +243,8 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
const tooltip = (r.decorations && r.decorations.tooltip) || '';
const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
const faded = r.decorations && !!r.decorations.faded;
const color = r.decorations && r.decorations.color;
return [handle, sourceUri, icons, tooltip, strikeThrough, faded, color] as SCMRawResource;
return [handle, sourceUri, icons, tooltip, strikeThrough, faded] as SCMRawResource;
});
handlesToDelete.push(...this._handlesSnapshot.splice(start, deleteCount, ...handles));
......
......@@ -17,9 +17,7 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { StatusUpdater, StatusBarController } from './scmActivity';
import { FileDecorations } from './scmFileDecorations';
import { SCMViewlet } from 'vs/workbench/parts/scm/electron-browser/scmViewlet';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
class OpenSCMViewletAction extends ToggleViewletAction {
......@@ -51,9 +49,6 @@ Registry.as(WorkbenchExtensions.Workbench)
Registry.as(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(StatusBarController);
Registry.as(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(FileDecorations);
// Register Action to Open Viewlet
Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction(
new SyncActionDescriptor(OpenSCMViewletAction, VIEWLET_ID, localize('toggleSCMViewlet', "Show SCM"), {
......@@ -65,17 +60,3 @@ Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions
'View: Show SCM',
localize('view', "View")
);
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
'id': 'scm',
'order': 101,
'type': 'object',
'properties': {
'scm.fileDecorations.enabled': {
'description': localize('scm.fileDecorations.enabled', "Show source control status on files and folders"),
'type': 'boolean',
'default': true
}
}
});
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IDecorationsService, IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations';
import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource } from 'vs/workbench/services/scm/common/scm';
import URI from 'vs/base/common/uri';
import Event, { Emitter } from 'vs/base/common/event';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { localize } from 'vs/nls';
class SCMDecorationsProvider implements IDecorationsProvider {
private readonly _disposable: IDisposable;
private readonly _onDidChange = new Emitter<URI[]>();
private _data = new Map<string, ISCMResource>();
readonly label: string;
readonly onDidChange: Event<URI[]> = this._onDidChange.event;
constructor(
private readonly _provider: ISCMProvider,
private readonly _config: ISCMConfiguration
) {
this.label = this._provider.label;
this._disposable = this._provider.onDidChangeResources(this._updateGroups, this);
this._updateGroups();
}
dispose(): void {
this._disposable.dispose();
}
private _updateGroups(): void {
const uris: URI[] = [];
const newData = new Map<string, ISCMResource>();
for (const group of this._provider.resources) {
for (const resource of group.resourceCollection.resources) {
newData.set(resource.sourceUri.toString(), resource);
if (!this._data.has(resource.sourceUri.toString())) {
uris.push(resource.sourceUri); // added
}
}
}
this._data.forEach((value, key) => {
if (!newData.has(key)) {
uris.push(value.sourceUri); // removed
}
});
this._data = newData;
this._onDidChange.fire(uris);
}
provideDecorations(uri: URI): IDecorationData {
const resource = this._data.get(uri.toString());
if (!resource || !resource.decorations.color || !resource.decorations.tooltip) {
return undefined;
}
return {
bubble: true,
weight: 255 - resource.decorations.tooltip.charAt(0).toLowerCase().charCodeAt(0),
title: localize('tooltip', "{0}, {1}", resource.decorations.tooltip, this._provider.label),
color: resource.decorations.color,
letter: resource.decorations.tooltip.charAt(0)
};
}
}
interface ISCMConfiguration {
fileDecorations: {
enabled: boolean;
};
}
export class FileDecorations implements IWorkbenchContribution {
private _providers = new Map<ISCMRepository, IDisposable>();
private _configListener: IDisposable;
private _repoListeners: IDisposable[];
constructor(
@IDecorationsService private _decorationsService: IDecorationsService,
@IConfigurationService private _configurationService: IConfigurationService,
@ISCMService private _scmService: ISCMService,
) {
this._configListener = this._configurationService.onDidChangeConfiguration(e => e.affectsConfiguration('scm.fileDecorations.enabled') && this._update());
this._update();
}
getId(): string {
throw new Error('smc.SCMFileDecorations');
}
dispose(): void {
this._providers.forEach(value => dispose(value));
dispose(this._repoListeners);
dispose(this._configListener, this._configListener);
}
private _update(): void {
const config = this._configurationService.getConfiguration<ISCMConfiguration>('scm');
if (config.fileDecorations.enabled) {
this._scmService.repositories.forEach(this._onDidAddRepository, this);
this._repoListeners = [
this._scmService.onDidAddRepository(this._onDidAddRepository, this),
this._scmService.onDidRemoveRepository(this._onDidRemoveRepository, this)
];
} else {
this._repoListeners = dispose(this._repoListeners);
this._providers.forEach(value => dispose(value));
this._providers.clear();
}
}
private _onDidAddRepository(repo: ISCMRepository): void {
const provider = new SCMDecorationsProvider(repo.provider, this._configurationService.getConfiguration<ISCMConfiguration>('scm'));
const registration = this._decorationsService.registerDecorationsProvider(provider);
this._providers.set(repo, combinedDisposable([registration, provider]));
}
private _onDidRemoveRepository(repo: ISCMRepository): void {
let listener = this._providers.get(repo);
if (listener) {
this._providers.delete(repo);
listener.dispose();
}
}
}
......@@ -11,7 +11,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import Event from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Command } from 'vs/editor/common/modes';
import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry';
export interface IBaselineResourceProvider {
getBaselineResource(resource: URI): TPromise<URI>;
......@@ -25,7 +24,6 @@ export interface ISCMResourceDecorations {
tooltip?: string;
strikeThrough?: boolean;
faded?: boolean;
color?: ColorIdentifier;
}
export interface ISCMResourceSplice {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册