Skip to content

Commit

Permalink
GitHistory implemented
Browse files Browse the repository at this point in the history
Fixed the `git diff` parser issue.
Toggle Widget with alt+h or via view menu
The list gets lazy loaded

Signed-off-by: Jan Bicker <jan.bicker@typefox.io>
  • Loading branch information
jbicker committed Feb 8, 2018
1 parent 9f12e89 commit 1fe61cf
Show file tree
Hide file tree
Showing 15 changed files with 897 additions and 52 deletions.
22 changes: 2 additions & 20 deletions packages/git/src/browser/diff/git-diff-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class GitDiffWidget extends GitBaseWidget implements StatefulWidget {
@inject(GitRepositoryProvider) protected repositoryProvider: GitRepositoryProvider,
@inject(LabelProvider) protected labelProvider: LabelProvider,
@inject(OpenerService) protected openerService: OpenerService) {
super();
super(repositoryProvider, labelProvider);
this.id = GIT_DIFF;
this.title.label = "Diff";

Expand Down Expand Up @@ -71,24 +71,6 @@ export class GitDiffWidget extends GitBaseWidget implements StatefulWidget {
}
}

protected relativePath(uri: URI | string): string {
const parsedUri = typeof uri === 'string' ? new URI(uri) : uri;
const repo = this.repositoryProvider.selectedRepository;
if (repo) {
return this.getRepositoryRelativePath(repo, parsedUri);
} else {
return this.labelProvider.getLongName(parsedUri);
}
}

protected computeCaption(fileChange: GitFileChange): string {
let result = `${this.relativePath(fileChange.uri)} - ${this.getStatusCaption(fileChange.status, true)}`;
if (fileChange.oldUri) {
result = `${this.relativePath(fileChange.oldUri)} -> ${result}`;
}
return result;
}

storeState(): object {
const { fileChangeNodes, options } = this;
return {
Expand Down Expand Up @@ -143,7 +125,7 @@ export class GitDiffWidget extends GitBaseWidget implements StatefulWidget {
const fileChangeElement: h.Child = this.renderGitItem(fileChange);
files.push(fileChangeElement);
}
return h.div({ className: "commitFileListContainer" }, ...files);
return h.div({ className: "listContainer" }, ...files);
}

protected renderGitItem(change: GitFileChangeNode): h.Child {
Expand Down
33 changes: 27 additions & 6 deletions packages/git/src/browser/git-base-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@
*/

import { VirtualWidget } from "@theia/core/lib/browser";
import { GitFileStatus, Repository } from '../common';
import { GitFileStatus, Repository, GitFileChange } from '../common';
import URI from "@theia/core/lib/common/uri";
import { GitRepositoryProvider } from "./git-repository-provider";
import { LabelProvider } from "@theia/core/lib/browser/label-provider";

export class GitBaseWidget extends VirtualWidget {

constructor(
protected readonly repositoryProvider: GitRepositoryProvider,
protected readonly labelProvider: LabelProvider) {
super();
}

protected getStatusCaption(status: GitFileStatus, staged: boolean): string {
switch (status) {
case GitFileStatus.New: return staged ? 'Added' : 'Unstaged';
Expand All @@ -23,13 +31,26 @@ export class GitBaseWidget extends VirtualWidget {
return '';
}

/**
* Returns the repository relative path of the given uri.
* @param repository
* @param uri
*/
protected getRepositoryRelativePath(repository: Repository, uri: URI) {
const repositoryUri = new URI(repository.localUri);
return uri.toString().substr(repositoryUri.toString().length + 1);
}

protected relativePath(uri: URI | string): string {
const parsedUri = typeof uri === 'string' ? new URI(uri) : uri;
const repo = this.repositoryProvider.selectedRepository;
if (repo) {
return this.getRepositoryRelativePath(repo, parsedUri);
} else {
return this.labelProvider.getLongName(parsedUri);
}
}

protected computeCaption(fileChange: GitFileChange): string {
let result = `${this.relativePath(fileChange.uri)} - ${this.getStatusCaption(fileChange.status, true)}`;
if (fileChange.oldUri) {
result = `${this.relativePath(fileChange.oldUri)} -> ${result}`;
}
return result;
}
}
2 changes: 2 additions & 0 deletions packages/git/src/browser/git-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { Git, GitPath } from '../common/git';
import { ContainerModule } from 'inversify';
import { bindGitDiffModule } from './diff/git-diff-frontend-module';
import { bindGitHistoryModule } from './history/git-history-frontend-module';
import { WebSocketConnectionProvider, FrontendApplicationContribution, WidgetFactory } from '@theia/core/lib/browser';
import { GitCommandHandlers } from './git-command';
import { CommandContribution, MenuContribution, ResourceResolver } from "@theia/core/lib/common";
Expand All @@ -26,6 +27,7 @@ import '../../src/browser/style/index.css';

export default new ContainerModule(bind => {
bindGitDiffModule(bind);
bindGitHistoryModule(bind);
bind(GitWatcherServerProxy).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, GitWatcherPath)).inSingletonScope();
bind(GitWatcherServer).to(ReconnectingGitWatcherServer).inSingletonScope();
bind(GitWatcher).toSelf().inSingletonScope();
Expand Down
11 changes: 9 additions & 2 deletions packages/git/src/browser/git-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ export interface GitFileChangeNode extends GitFileChange {
readonly description: string;
readonly caption?: string;
readonly extraIconClassName?: string;
readonly commitSha?: string;
selected?: boolean;
}

export namespace GitFileChangeNode {
export function is(node: any): node is GitFileChangeNode {
return 'uri' in node && 'status' in node && 'description' in node && 'label' in node && 'icon' in node;
}
}

@injectable()
Expand All @@ -53,7 +61,7 @@ export class GitWidget extends GitBaseWidget {
@inject(LabelProvider) protected readonly labelProvider: LabelProvider,
@inject(CommandService) protected readonly commandService: CommandService,
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService) {
super();
super(repositoryProvider, labelProvider);
this.id = 'theia-gitContainer';
this.title.label = 'Git';

Expand Down Expand Up @@ -384,5 +392,4 @@ export class GitWidget extends GitBaseWidget {
const message = error instanceof Error ? error.message : error;
this.messageService.error(message);
}

}
21 changes: 21 additions & 0 deletions packages/git/src/browser/history/git-history-commit-uri.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2018 TypeFox and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import URI from "@theia/core/lib/common/uri";

export namespace GitDiffCommitUri {
export const scheme = 'git-diff-commit';
export function toUri(commitName: string): URI {
return new URI('').withScheme(scheme).withFragment(commitName);
}
export function toCommitName(uri: URI): string {
if (uri.scheme === scheme) {
return uri.fragment;
}
throw new Error('The given uri is not an commit URI, uri: ' + uri);
}
}
84 changes: 84 additions & 0 deletions packages/git/src/browser/history/git-history-contribution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2018 TypeFox and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { MenuModelRegistry, CommandRegistry, Command, SelectionService } from "@theia/core";
import { AbstractViewContribution } from "@theia/core/lib/browser";
import { injectable, inject } from "inversify";
import { NAVIGATOR_CONTEXT_MENU } from "@theia/navigator/lib/browser/navigator-menu";
import { UriCommandHandler, FileSystemCommandHandler } from "@theia/workspace/lib/browser/workspace-commands";
import { GitHistoryWidget } from './git-history-widget';
import { Git } from "../../common";

export namespace GitHistoryCommands {
export const OPEN_FILE_HISTORY: Command = {
id: 'git-history:open-file-history',
label: 'Git History'
};
export const OPEN_BRANCH_HISTORY: Command = {
id: 'git-history:open-branch-history'
};
}

export const GIT_HISTORY = 'git-history';
export const GIT_HISTORY_MAX_COUNT = 100;
@injectable()
export class GitHistoryContribution extends AbstractViewContribution<GitHistoryWidget> {

constructor(
@inject(SelectionService) protected readonly selectionService: SelectionService) {
super({
widgetId: GIT_HISTORY,
widgetName: 'Git History',
defaultWidgetOptions: {
area: 'left',
rank: 400
},
toggleCommandId: GitHistoryCommands.OPEN_BRANCH_HISTORY.id,
toggleKeybinding: 'alt+h'
});
}

registerMenus(menus: MenuModelRegistry): void {
menus.registerMenuAction([...NAVIGATOR_CONTEXT_MENU, '5_history'], {
commandId: GitHistoryCommands.OPEN_FILE_HISTORY.id
});

super.registerMenus(menus);
}

registerCommands(commands: CommandRegistry): void {
commands.registerCommand(GitHistoryCommands.OPEN_FILE_HISTORY, this.newFileHandler({
execute: async uri => {
const options: Git.Options.Log = {
uri: uri.toString(),
maxCount: GIT_HISTORY_MAX_COUNT
};
this.showWidget(options);
}
}));
commands.registerCommand(GitHistoryCommands.OPEN_BRANCH_HISTORY, {
execute: () => {
this.showWidget({
maxCount: GIT_HISTORY_MAX_COUNT
});
}
});
}

async showWidget(options?: Git.Options.Log) {
const widget = await this.widget;
await widget.setContent(options);
this.openView({
toggle: true,
activate: true
});
}

protected newFileHandler(handler: UriCommandHandler): FileSystemCommandHandler {
return new FileSystemCommandHandler(this.selectionService, handler);
}
}
31 changes: 31 additions & 0 deletions packages/git/src/browser/history/git-history-frontend-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2018 TypeFox and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { GitHistoryContribution, GIT_HISTORY } from "./git-history-contribution";
import { interfaces } from "inversify";
import { CommandContribution, MenuContribution, KeybindingContribution } from "@theia/core";
import { WidgetFactory } from "@theia/core/lib/browser";
import { GitHistoryWidget } from "./git-history-widget";

import '../../../src/browser/style/history.css';

export function bindGitHistoryModule(bind: interfaces.Bind) {

bind(GitHistoryWidget).toSelf();
bind(WidgetFactory).toDynamicValue(ctx => ({
id: GIT_HISTORY,
createWidget: () => ctx.container.get<GitHistoryWidget>(GitHistoryWidget)
}));

bind(GitHistoryContribution).toSelf().inSingletonScope();
for (const identifier of [CommandContribution, MenuContribution, KeybindingContribution]) {
bind(identifier).toDynamicValue(ctx =>
ctx.container.get(GitHistoryContribution)
).inSingletonScope();
}

}
Loading

0 comments on commit 1fe61cf

Please sign in to comment.