提交 8932f62a 编写于 作者: J Johannes Rieken
上级 b67b5e8e
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { window, workspace, Uri, Disposable, Event, EventEmitter, Decoration, DecorationProvider, ThemeColor } from 'vscode';
import { window, workspace, Uri, Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, ThemeColor } from 'vscode';
import * as path from 'path';
import { Repository, GitResourceGroup } from './repository';
import { Model } from './model';
......@@ -11,16 +11,16 @@ import { debounce } from './decorators';
import { filterEvent, dispose, anyEvent, fireEvent, PromiseSource } from './util';
import { GitErrorCodes, Status } from './api/git';
class GitIgnoreDecorationProvider implements DecorationProvider {
class GitIgnoreDecorationProvider implements FileDecorationProvider {
private static Decoration: Decoration = { priority: 3, color: new ThemeColor('gitDecoration.ignoredResourceForeground') };
private static Decoration: FileDecoration = { priority: 3, color: new ThemeColor('gitDecoration.ignoredResourceForeground') };
readonly onDidChangeDecorations: Event<Uri[]>;
private queue = new Map<string, { repository: Repository; queue: Map<string, PromiseSource<Decoration | undefined>>; }>();
readonly onDidChange: Event<Uri[]>;
private queue = new Map<string, { repository: Repository; queue: Map<string, PromiseSource<FileDecoration | undefined>>; }>();
private disposables: Disposable[] = [];
constructor(private model: Model) {
this.onDidChangeDecorations = fireEvent(anyEvent<any>(
this.onDidChange = fireEvent(anyEvent<any>(
filterEvent(workspace.onDidSaveTextDocument, e => /\.gitignore$|\.git\/info\/exclude$/.test(e.uri.path)),
model.onDidOpenRepository,
model.onDidCloseRepository
......@@ -29,7 +29,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider {
this.disposables.push(window.registerDecorationProvider(this));
}
async provideDecoration(uri: Uri): Promise<Decoration | undefined> {
async provideFileDecoration(uri: Uri): Promise<FileDecoration | undefined> {
const repository = this.model.getRepository(uri);
if (!repository) {
......@@ -39,7 +39,7 @@ class GitIgnoreDecorationProvider implements DecorationProvider {
let queueItem = this.queue.get(repository.root);
if (!queueItem) {
queueItem = { repository, queue: new Map<string, PromiseSource<Decoration | undefined>>() };
queueItem = { repository, queue: new Map<string, PromiseSource<FileDecoration | undefined>>() };
this.queue.set(repository.root, queueItem);
}
......@@ -84,19 +84,19 @@ class GitIgnoreDecorationProvider implements DecorationProvider {
}
}
class GitDecorationProvider implements DecorationProvider {
class GitDecorationProvider implements FileDecorationProvider {
private static SubmoduleDecorationData: Decoration = {
title: 'Submodule',
letter: 'S',
private static SubmoduleDecorationData: FileDecoration = {
tooltip: 'Submodule',
badge: 'S',
color: new ThemeColor('gitDecoration.submoduleResourceForeground')
};
private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
readonly onDidChangeDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
readonly onDidChange: Event<Uri[]> = this._onDidChangeDecorations.event;
private disposables: Disposable[] = [];
private decorations = new Map<string, Decoration>();
private decorations = new Map<string, FileDecoration>();
constructor(private repository: Repository) {
this.disposables.push(
......@@ -106,7 +106,7 @@ class GitDecorationProvider implements DecorationProvider {
}
private onDidRunGitStatus(): void {
let newDecorations = new Map<string, Decoration>();
let newDecorations = new Map<string, FileDecoration>();
this.collectSubmoduleDecorationData(newDecorations);
this.collectDecorationData(this.repository.indexGroup, newDecorations);
......@@ -119,7 +119,7 @@ class GitDecorationProvider implements DecorationProvider {
this._onDidChangeDecorations.fire([...uris.values()].map(value => Uri.parse(value, true)));
}
private collectDecorationData(group: GitResourceGroup, bucket: Map<string, Decoration>): void {
private collectDecorationData(group: GitResourceGroup, bucket: Map<string, FileDecoration>): void {
for (const r of group.resourceStates) {
const decoration = r.resourceDecoration;
......@@ -134,13 +134,13 @@ class GitDecorationProvider implements DecorationProvider {
}
}
private collectSubmoduleDecorationData(bucket: Map<string, Decoration>): void {
private collectSubmoduleDecorationData(bucket: Map<string, FileDecoration>): void {
for (const submodule of this.repository.submodules) {
bucket.set(Uri.file(path.join(this.repository.root, submodule.path)).toString(), GitDecorationProvider.SubmoduleDecorationData);
}
}
provideDecoration(uri: Uri): Decoration | undefined {
provideFileDecoration(uri: Uri): FileDecoration | undefined {
return this.decorations.get(uri.toString());
}
......
......@@ -5,7 +5,7 @@
import * as fs from 'fs';
import * as path from 'path';
import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, Decoration } from 'vscode';
import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, FileDecoration } from 'vscode';
import * as nls from 'vscode-nls';
import { Branch, Change, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status, CommitOptions, BranchQuery } from './api/git';
import { AutoFetcher } from './autofetch';
......@@ -253,11 +253,11 @@ export class Resource implements SourceControlResourceState {
}
}
get resourceDecoration(): Decoration {
get resourceDecoration(): FileDecoration {
return {
bubble: this.type !== Status.DELETED && this.type !== Status.INDEX_DELETED,
title: this.tooltip,
letter: this.letter,
propagte: this.type !== Status.DELETED && this.type !== Status.INDEX_DELETED,
tooltip: this.tooltip,
badge: this.letter,
color: this.color,
priority: this.priority
};
......
......@@ -717,23 +717,18 @@ declare module 'vscode' {
//#region file-decorations: https://github.com/microsoft/vscode/issues/54938
// TODO@jrieken FileDecoration, FileDecorationProvider etc.
// TODO@jrieken Add selector notion to limit decorations to a view.
// TODO@jrieken Rename `Decoration.letter` to `short` so that it could be used for coverage et al.
// TODO@jrieken priority -> DecorationSeverity.INFO,WARN,ERROR
// TODO@jrieken title -> tooltip
// TODO@jrieken bubble -> propagte
export class Decoration {
export class FileDecoration {
/**
* A letter that represents this decoration.
* A very short string that represents this decoration.
*/
letter?: string;
badge?: string;
/**
* The human-readable title for this decoration.
* A human-readable tooltip for this decoration.
*/
title?: string;
tooltip?: string;
/**
* The color of this decoration.
......@@ -747,46 +742,45 @@ declare module 'vscode' {
/**
* A flag expressing that this decoration should be
* propagted to its parents.
* propagated to its parents.
*/
bubble?: boolean;
propagte?: boolean;
/**
* Creates a new decoration.
*
* @param letter A letter that represents the decoration.
* @param title The title of the decoration.
* @param badge A letter that represents the decoration.
* @param tooltip The tooltip of the decoration.
* @param color The color of the decoration.
*/
constructor(letter?: string, title?: string, color?: ThemeColor);
constructor(badge?: string, tooltip?: string, color?: ThemeColor);
}
/**
* The decoration provider interfaces defines the contract between extensions and
* file decorations.
*/
export interface DecorationProvider {
export interface FileDecorationProvider {
/**
* An event to signal decorations for one or many files have changed.
*
* @see [EventEmitter](#EventEmitter
*/
onDidChangeDecorations: Event<undefined | Uri | Uri[]>;
onDidChange: Event<undefined | Uri | Uri[]>;
/**
* Provide decorations for a given uri.
*
*
* @param uri The uri of the file to provide a decoration for.
* @param token A cancellation token.
* @returns A decoration or a thenable that resolves to such.
*/
provideDecoration(uri: Uri, token: CancellationToken): ProviderResult<Decoration>;
provideFileDecoration(uri: Uri, token: CancellationToken): ProviderResult<FileDecoration>;
}
export namespace window {
export function registerDecorationProvider(provider: DecorationProvider): Disposable;
export function registerDecorationProvider(provider: FileDecorationProvider): Disposable;
}
//#endregion
......
......@@ -605,7 +605,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider | vscode.CustomReadonlyEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean } = {}) => {
return extHostCustomEditors.registerCustomEditorProvider(extension, viewType, provider, options);
},
registerDecorationProvider(provider: vscode.DecorationProvider) {
registerDecorationProvider(provider: vscode.FileDecorationProvider) {
checkProposedApiEnabled(extension);
return extHostDecorations.registerDecorationProvider(provider, extension.identifier);
},
......@@ -1138,7 +1138,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
CallHierarchyItem: extHostTypes.CallHierarchyItem,
DebugConsoleMode: extHostTypes.DebugConsoleMode,
DebugConfigurationProviderTriggerKind: extHostTypes.DebugConfigurationProviderTriggerKind,
Decoration: extHostTypes.Decoration,
FileDecoration: extHostTypes.FileDecoration,
UIKind: UIKind,
ColorThemeKind: extHostTypes.ColorThemeKind,
TimelineItem: extHostTypes.TimelineItem,
......
......@@ -6,7 +6,7 @@
import type * as vscode from 'vscode';
import { URI } from 'vs/base/common/uri';
import { MainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData, DecorationRequest, DecorationReply } from 'vs/workbench/api/common/extHost.protocol';
import { Disposable, Decoration } from 'vs/workbench/api/common/extHostTypes';
import { Disposable, FileDecoration } from 'vs/workbench/api/common/extHostTypes';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
......@@ -15,7 +15,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { asArray } from 'vs/base/common/arrays';
interface ProviderData {
provider: vscode.DecorationProvider;
provider: vscode.FileDecorationProvider;
extensionId: ExtensionIdentifier;
}
......@@ -34,12 +34,12 @@ export class ExtHostDecorations implements ExtHostDecorationsShape {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadDecorations);
}
registerDecorationProvider(provider: vscode.DecorationProvider, extensionId: ExtensionIdentifier): vscode.Disposable {
registerDecorationProvider(provider: vscode.FileDecorationProvider, extensionId: ExtensionIdentifier): vscode.Disposable {
const handle = ExtHostDecorations._handlePool++;
this._provider.set(handle, { provider, extensionId });
this._proxy.$registerDecorationProvider(handle, extensionId.value);
const listener = provider.onDidChangeDecorations(e => {
const listener = provider.onDidChange(e => {
this._proxy.$onDidChange(handle, !e || (Array.isArray(e) && e.length > 250)
? null
: asArray(e));
......@@ -65,13 +65,13 @@ export class ExtHostDecorations implements ExtHostDecorationsShape {
await Promise.all(requests.map(async request => {
try {
const { uri, id } = request;
const data = await Promise.resolve(provider.provideDecoration(URI.revive(uri), token));
const data = await Promise.resolve(provider.provideFileDecoration(URI.revive(uri), token));
if (!data) {
return;
}
try {
Decoration.validate(data);
result[id] = <DecorationData>[data.priority, data.bubble, data.title, data.letter, data.color];
FileDecoration.validate(data);
result[id] = <DecorationData>[data.priority, data.propagte, data.tooltip, data.badge, data.color];
} catch (e) {
this._logService.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`);
}
......
......@@ -2729,22 +2729,29 @@ export enum ExtensionKind {
Workspace = 2
}
export class Decoration {
export class FileDecoration {
static validate(d: Decoration): void {
if (d.letter && d.letter.length !== 1) {
static validate(d: FileDecoration): void {
if (d.badge && d.badge.length !== 1) {
throw new Error(`The 'letter'-property must be undefined or a single character`);
}
if (!d.bubble && !d.color && !d.letter && !d.priority && !d.title) {
if (!d.color && !d.badge && !d.tooltip) {
throw new Error(`The decoration is empty`);
}
}
letter?: string;
title?: string;
badge?: string;
tooltip?: string;
color?: vscode.ThemeColor;
priority?: number;
bubble?: boolean;
propagate?: boolean;
constructor(badge?: string, tooltip?: string, color?: ThemeColor) {
this.badge = badge;
this.tooltip = tooltip;
this.color = color;
}
}
//#region Theming
......
......@@ -48,8 +48,8 @@ suite('ExtHostDecorations', function () {
// never returns
extHostDecorations.registerDecorationProvider({
onDidChangeDecorations: Event.None,
provideDecoration() {
onDidChange: Event.None,
provideFileDecoration() {
calledA = true;
return new Promise(() => { });
}
......@@ -57,10 +57,10 @@ suite('ExtHostDecorations', function () {
// always returns
extHostDecorations.registerDecorationProvider({
onDidChangeDecorations: Event.None,
provideDecoration() {
onDidChange: Event.None,
provideFileDecoration() {
calledB = true;
return new Promise(resolve => resolve({ letter: 'H', title: 'Hello' }));
return new Promise(resolve => resolve({ badge: 'H', tooltip: 'Hello' }));
}
}, nullExtensionDescription.identifier);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册