Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Cleaning up the code and fixing some bugs #94

Merged
merged 2 commits into from
Feb 9, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions src/helpers/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,10 @@ export class Strings {
static TfExecFailedError: string = "Execution of the TFVC command line failed unexpectedly.";
static TfVersionWarning: string = "The installed version of the TF command line does not meet the minimum suggested version. You may run into errors or limitations with certain commands until you upgrade. Minimum suggested version: ";
static TfNoPendingChanges: string = "There are no matching pending changes.";

// TFVC viewlet Strings
static ExcludedGroupName: string = "Excluded changes";
static IncludedGroupName: string = "Included changes";
static MergeGroupName: string = "Merge changes";
}
/* tslint:enable:variable-name */
39 changes: 36 additions & 3 deletions src/tfvc/scm/decorationprovider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,50 @@ import { ConflictType, Status } from "./status";
import * as path from "path";

export class DecorationProvider {
private static iconsRootPath: string = path.join(path.dirname(__dirname), "..", "..", "resources", "icons");
private static _iconsRootPath: string = path.join(path.dirname(__dirname), "..", "..", "resources", "icons");

public static getDecorations(status: Status, conflictType?: ConflictType): SCMResourceDecorations {
public static getDecorations(statuses: Status[], conflictType?: ConflictType): SCMResourceDecorations {
const status: Status = this.getDominantStatus(statuses);
const light = { iconPath: DecorationProvider.getIconPath(status, "light") };
const dark = { iconPath: DecorationProvider.getIconPath(status, "dark") };

return { strikeThrough: DecorationProvider.useStrikeThrough(status, conflictType), light, dark };
}

private static getDominantStatus(statuses: Status[]) {
if (!statuses || statuses.length === 0) {
return undefined;
}

// if there's only one just return it
if (statuses.length === 1) {
return statuses[0];
}

// The most dominant types are ADD, EDIT, and DELETE
let index: number = statuses.findIndex((s) => s === Status.ADD || s === Status.EDIT || s === Status.DELETE);
if (index >= 0) {
return statuses[index];
}

// The next dominant type is RENAME
index = statuses.findIndex((s) => s === Status.RENAME);
if (index >= 0) {
return statuses[index];
}

// The next dominant type is RENAME
index = statuses.findIndex((s) => s === Status.RENAME);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this block duplicated above?

if (index >= 0) {
return statuses[index];
}

// After that, just return the first one
return statuses[0];
}

private static getIconUri(iconName: string, theme: string): Uri {
return Uri.file(path.join(DecorationProvider.iconsRootPath, theme, `${iconName}.svg`));
return Uri.file(path.join(DecorationProvider._iconsRootPath, theme, `${iconName}.svg`));
}

private static getIconPath(status: Status, theme: string): Uri | undefined {
Expand Down
129 changes: 36 additions & 93 deletions src/tfvc/scm/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,148 +4,91 @@
*--------------------------------------------------------------------------------------------*/
"use strict";

/* tslint:disable */

import { Uri, EventEmitter, Event, SCMResourceGroup, Disposable, window } from "vscode";
import { Repository } from "../repository";
import { filterEvent } from "../util";
import { Resource } from "./resource";
import { Operation } from "./operations";
import { ResourceGroup, IndexGroup, WorkingTreeGroup, MergeGroup } from "./resourcegroups";
import { ResourceGroup, IncludedGroup, ExcludedGroup, MergeGroup } from "./resourcegroups";
import { IPendingChange } from "../interfaces";
import { Status } from "./status";

export class Model {
private _disposables: Disposable[] = [];
private _repositoryRoot: string;
private _repository: Repository;
private _statusInProgress: boolean;

private _onDidChange = new EventEmitter<SCMResourceGroup[]>();
readonly onDidChange: Event<SCMResourceGroup[]> = this._onDidChange.event;
public get onDidChange(): Event<SCMResourceGroup[]> {
return this._onDidChange.event;
}

private _mergeGroup = new MergeGroup([]);
get mergeGroup(): MergeGroup { return this._mergeGroup; }
private _includedGroup = new IncludedGroup([]);
private _excludedGroup = new ExcludedGroup([]);

private _indexGroup = new IndexGroup([]);
get indexGroup(): IndexGroup { return this._indexGroup; }
public constructor(repositoryRoot: string, repository: Repository, onWorkspaceChange: Event<Uri>) {
this._repositoryRoot = repositoryRoot;
this._repository = repository;
const onNonGitChange = filterEvent(onWorkspaceChange, uri => !/\/\.tf\//.test(uri.fsPath));
onNonGitChange(this.onFileSystemChange, this, this._disposables);
this.status();
}

private _workingTreeGroup = new WorkingTreeGroup([]);
get workingTreeGroup(): WorkingTreeGroup { return this._workingTreeGroup; }
public get MergeGroup(): MergeGroup { return this._mergeGroup; }
public get IndexGroup(): IncludedGroup { return this._includedGroup; }
public get WorkingTreeGroup(): ExcludedGroup { return this._excludedGroup; }

get resources(): ResourceGroup[] {
public get Resources(): ResourceGroup[] {
const result: ResourceGroup[] = [];
if (this._mergeGroup.resources.length > 0) {
result.push(this._mergeGroup);
}
if (this._indexGroup.resources.length > 0) {
result.push(this._indexGroup);
if (this._includedGroup.resources.length > 0) {
result.push(this._includedGroup);
}
result.push(this._workingTreeGroup);
result.push(this._excludedGroup);
return result;
}

constructor(repositoryRoot: string, repository: Repository, onWorkspaceChange: Event<Uri>) {
this._repositoryRoot = repositoryRoot;
this._repository = repository;
const onNonGitChange = filterEvent(onWorkspaceChange, uri => !/\/\.tf\//.test(uri.fsPath));
onNonGitChange(this.onFileSystemChange, this, this._disposables);
this.status();
}

get repositoryRoot(): string {
return this._repositoryRoot;
}

async status(): Promise<void> {
await this.run(Operation.Status);
private async status(): Promise<void> {
await this.run(undefined);
}

private onFileSystemChange(uri: Uri): void {
this.status();
}

private async run(operation: Operation, fn: () => Promise<void> = () => Promise.resolve()): Promise<void> {
private async run(fn: () => Promise<void>): Promise<void> {
return window.withScmProgress(async () => {
//this._operations = this._operations.start(operation);
//this._onRunOperation.fire(operation);

try {
if (fn) {
await fn();
await this.update();
} finally {
//this._operations = this._operations.end(operation);
//this._onDidRunOperation.fire(operation);
} else {
Promise.resolve();
}
await this.update();
});
}

//@throttle
private async update(): Promise<void> {
const changes: IPendingChange[] = await this._repository.GetStatus();
const index: Resource[] = [];
const workingTree: Resource[] = [];
const included: Resource[] = [];
const excluded: Resource[] = [];
const merge: Resource[] = [];

changes.forEach(raw => {
const resource: Resource = new Resource(raw);
const uri = Uri.file(raw.localItem);

switch (resource.Type) {
case Status.ADD:
case Status.BRANCH:
case Status.DELETE:
case Status.EDIT:
case Status.RENAME:
case Status.UNDELETE:
return index.push(resource);
case Status.LOCK:
case Status.MERGE:
return merge.push(resource);
if (resource.HasStatus(Status.MERGE)) {
return merge.push(resource);
} else {
return included.push(resource);
}
});

this._mergeGroup = new MergeGroup(merge);
this._indexGroup = new IndexGroup(index);
this._workingTreeGroup = new WorkingTreeGroup(workingTree);

this._onDidChange.fire(this.resources);
}

/*
private onFSChange(uri: Uri): void {
const config = workspace.getConfiguration("git");
const autorefresh = config.get<boolean>("autorefresh");
if (!autorefresh) {
return;
}
if (!this.operations.isIdle()) {
return;
}
this._includedGroup = new IncludedGroup(included);
this._excludedGroup = new ExcludedGroup(excluded);

this.eventuallyUpdateWhenIdleAndWait();
this._onDidChange.fire(this.Resources);
}
//@debounce(1000)
private eventuallyUpdateWhenIdleAndWait(): void {
this.updateWhenIdleAndWait();
}
//@throttle
private async updateWhenIdleAndWait(): Promise<void> {
await this.whenIdle();
await this.status();
await new Promise(c => setTimeout(c, 5000));
}
private async whenIdle(): Promise<void> {
while (!this.operations.isIdle()) {
await eventToPromise(this.onDidRunOperation);
}
}
*/

}
/* tslint:enable */
48 changes: 0 additions & 48 deletions src/tfvc/scm/operations.ts

This file was deleted.

14 changes: 9 additions & 5 deletions src/tfvc/scm/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,26 @@
import { SCMResource, SCMResourceDecorations, Uri } from "vscode";
import { IPendingChange } from "../interfaces";
import { TfvcSCMProvider } from "../tfvcscmprovider";
import { CreateStatus, Status } from "./status";
import { GetStatuses, Status } from "./status";
import { DecorationProvider } from "./decorationprovider";

export class Resource implements SCMResource {
private _uri: Uri;
private _type: Status;
private _statuses: Status[];
private _change: IPendingChange;

constructor(change: IPendingChange) {
this._change = change;
this._uri = Uri.file(change.localItem);
this._type = CreateStatus(change.changeType);
this._statuses = GetStatuses(change.changeType);
}

public get PendingChange(): IPendingChange { return this._change; }
public get Type(): Status { return this._type; }
public get Statuses(): Status[] { return this._statuses; }

public HasStatus(status: Status): boolean {
return this._statuses.findIndex(s => s === status) >= 0;
}

/**
* This method gets a vscode file uri that represents the server path and version that the local item is based on.
Expand All @@ -37,6 +41,6 @@ export class Resource implements SCMResource {
get uri(): Uri { return this._uri; }
get decorations(): SCMResourceDecorations {
// TODO Add conflict type to the resource constructor and pass it here
return DecorationProvider.getDecorations(this._type);
return DecorationProvider.getDecorations(this._statuses);
}
}
18 changes: 9 additions & 9 deletions src/tfvc/scm/resourcegroups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,42 @@
"use strict";

import { SCMResourceGroup } from "vscode";
import { Strings } from "../../helpers/strings";
import { Resource } from "./resource";

export class ResourceGroup implements SCMResourceGroup {
get id(): string { return this._id; }
get label(): string { return this._label; }
get resources(): Resource[] { return this._resources; }

constructor(private _id: string, private _label: string, private _resources: Resource[]) {
public constructor(private _id: string,
private _label: string,
private _resources: Resource[]) {
}
}

export class MergeGroup extends ResourceGroup {
static readonly ID = "merge";

constructor(resources: Resource[]) {
//TODO localize
super(MergeGroup.ID, "Merge Changes", resources);
super(MergeGroup.ID, Strings.MergeGroupName, resources);
}
}

export class IndexGroup extends ResourceGroup {
export class IncludedGroup extends ResourceGroup {

static readonly ID = "included";

constructor(resources: Resource[]) {
//TODO localize
super(IndexGroup.ID, "Included Changes", resources);
super(IncludedGroup.ID, Strings.IncludedGroupName, resources);
}
}

export class WorkingTreeGroup extends ResourceGroup {
export class ExcludedGroup extends ResourceGroup {

static readonly ID = "excluded";

constructor(resources: Resource[]) {
//TODO localize
super(WorkingTreeGroup.ID, "Excluded Changes", resources);
super(ExcludedGroup.ID, Strings.ExcludedGroupName, resources);
}
}
Loading