more submodule support, diff colorization

This commit is contained in:
Joao Moreno
2017-12-13 16:21:12 +01:00
parent 0cd53b2d9b
commit 9f131c1762
10 changed files with 455 additions and 61 deletions

View File

@@ -169,14 +169,33 @@ export class CommandCenter {
}
private async _openResource(resource: Resource, preview?: boolean, preserveFocus?: boolean, preserveSelection?: boolean): Promise<void> {
const stat = await new Promise<Stats>((c, e) => lstat(resource.resourceUri.fsPath, (err, stat) => err ? e(err) : c(stat)));
let stat: Stats | undefined;
if (stat.isDirectory()) {
return;
try {
stat = await new Promise<Stats>((c, e) => lstat(resource.resourceUri.fsPath, (err, stat) => err ? e(err) : c(stat)));
} catch (err) {
// noop
}
const left = await this.getLeftResource(resource);
const right = await this.getRightResource(resource);
let left: Uri | undefined;
let right: Uri | undefined;
if (stat && stat.isDirectory()) {
outer:
for (const repository of this.model.repositories) {
for (const submodule of repository.submodules) {
const submodulePath = path.join(repository.root, submodule.path);
if (submodulePath === resource.resourceUri.fsPath) {
right = toGitUri(Uri.file(submodulePath), resource.resourceGroupType === ResourceGroupType.Index ? 'index' : 'wt', { submoduleOf: repository.root });
break outer;
}
}
}
} else {
left = await this.getLeftResource(resource);
right = await this.getRightResource(resource);
}
const title = this.getTitle(resource);
@@ -1697,7 +1716,7 @@ export class CommandCenter {
const isSingleResource = arg instanceof Uri;
const groups = resources.reduce((result, resource) => {
const repository = this.model.getRepository(resource);
const repository = this.model.getRepository(resource, true);
if (!repository) {
console.warn('Could not find git repository for ', resource);

View File

@@ -52,7 +52,7 @@ export class GitContentProvider {
return;
}
this._onDidChange.fire(toGitUri(uri, '', true));
this._onDidChange.fire(toGitUri(uri, '', { replaceFileExtension: true }));
}
@debounce(1100)
@@ -83,6 +83,18 @@ export class GitContentProvider {
}
async provideTextDocumentContent(uri: Uri): Promise<string> {
let { path, ref, submoduleOf } = fromGitUri(uri);
if (submoduleOf) {
const repository = this.model.getRepository(submoduleOf);
if (!repository) {
return '';
}
return await repository.diff(path, { cached: ref === 'index' });
}
const repository = this.model.getRepository(uri);
if (!repository) {
@@ -95,8 +107,6 @@ export class GitContentProvider {
this.cache[cacheKey] = cacheValue;
let { path, ref } = fromGitUri(uri);
if (ref === '~') {
const fileUri = Uri.file(path);
const uriString = fileUri.toString();

View File

@@ -597,6 +597,10 @@ export function parseGitmodules(raw: string): Submodule[] {
return result;
}
export interface DiffOptions {
cached?: boolean;
}
export class Repository {
constructor(
@@ -735,6 +739,19 @@ export class Repository {
}
}
async diff(path: string, options: DiffOptions = {}): Promise<string> {
const args = ['diff'];
if (options.cached) {
args.push('--cached');
}
args.push('--', path);
const result = await this.run(args);
return result.stdout;
}
async add(paths: string[]): Promise<void> {
const args = ['add', '-A', '--'];

View File

@@ -265,19 +265,19 @@ export class Model {
getRepository(sourceControl: SourceControl): Repository | undefined;
getRepository(resourceGroup: SourceControlResourceGroup): Repository | undefined;
getRepository(path: string): Repository | undefined;
getRepository(resource: Uri): Repository | undefined;
getRepository(hint: any): Repository | undefined {
const liveRepository = this.getOpenRepository(hint);
getRepository(path: string, possibleSubmoduleRoot?: boolean): Repository | undefined;
getRepository(resource: Uri, possibleSubmoduleRoot?: boolean): Repository | undefined;
getRepository(hint: any, possibleSubmoduleRoot?: boolean): Repository | undefined {
const liveRepository = this.getOpenRepository(hint, possibleSubmoduleRoot);
return liveRepository && liveRepository.repository;
}
private getOpenRepository(repository: Repository): OpenRepository | undefined;
private getOpenRepository(sourceControl: SourceControl): OpenRepository | undefined;
private getOpenRepository(resourceGroup: SourceControlResourceGroup): OpenRepository | undefined;
private getOpenRepository(path: string): OpenRepository | undefined;
private getOpenRepository(resource: Uri): OpenRepository | undefined;
private getOpenRepository(hint: any): OpenRepository | undefined {
private getOpenRepository(path: string, possibleSubmoduleRoot?: boolean): OpenRepository | undefined;
private getOpenRepository(resource: Uri, possibleSubmoduleRoot?: boolean): OpenRepository | undefined;
private getOpenRepository(hint: any, possibleSubmoduleRoot?: boolean): OpenRepository | undefined {
if (!hint) {
return undefined;
}
@@ -295,15 +295,21 @@ export class Model {
outer:
for (const liveRepository of this.openRepositories.sort((a, b) => b.repository.root.length - a.repository.root.length)) {
if (possibleSubmoduleRoot && liveRepository.repository.root === resourcePath) {
continue;
}
if (!isDescendant(liveRepository.repository.root, resourcePath)) {
continue;
}
for (const submodule of liveRepository.repository.submodules) {
const submoduleRoot = path.join(liveRepository.repository.root, submodule.path);
if (!possibleSubmoduleRoot) {
for (const submodule of liveRepository.repository.submodules) {
const submoduleRoot = path.join(liveRepository.repository.root, submodule.path);
if (isDescendant(submoduleRoot, resourcePath)) {
continue outer;
if (isDescendant(submoduleRoot, resourcePath)) {
continue outer;
}
}
}

View File

@@ -6,7 +6,7 @@
'use strict';
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento } from 'vscode';
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError, Submodule } from './git';
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError, Submodule, DiffOptions } from './git';
import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent } from './util';
import { memoize, throttle, debounce } from './decorators';
import { toGitUri } from './uri';
@@ -280,6 +280,7 @@ export class Resource implements SourceControlResourceState {
export enum Operation {
Status = 'Status',
Diff = 'Diff',
Add = 'Add',
RevertFiles = 'RevertFiles',
Commit = 'Commit',
@@ -557,7 +558,7 @@ export class Repository implements Disposable {
return;
}
return toGitUri(uri, '', true);
return toGitUri(uri, '', { replaceFileExtension: true });
}
private async updateCommitTemplate(): Promise<void> {
@@ -573,6 +574,10 @@ export class Repository implements Disposable {
await this.run(Operation.Status);
}
diff(path: string, options: DiffOptions = {}): Promise<string> {
return this.run(Operation.Diff, () => this.repository.diff(path, options));
}
async add(resources: Uri[]): Promise<void> {
await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.fsPath)));
}

View File

@@ -7,20 +7,45 @@
import { Uri } from 'vscode';
export function fromGitUri(uri: Uri): { path: string; ref: string; } {
export interface GitUriParams {
path: string;
ref: string;
submoduleOf?: string;
}
export function fromGitUri(uri: Uri): GitUriParams {
return JSON.parse(uri.query);
}
export interface GitUriOptions {
replaceFileExtension?: boolean;
submoduleOf?: string;
}
// As a mitigation for extensions like ESLint showing warnings and errors
// for git URIs, let's change the file extension of these uris to .git,
// when `replaceFileExtension` is true.
export function toGitUri(uri: Uri, ref: string, replaceFileExtension = false): Uri {
export function toGitUri(uri: Uri, ref: string, options: GitUriOptions = {}): Uri {
const params: GitUriParams = {
path: uri.fsPath,
ref
};
if (options.submoduleOf) {
params.submoduleOf = options.submoduleOf;
}
let path = uri.path;
if (options.replaceFileExtension) {
path = path + `${path}.git`;
} else if (options.submoduleOf) {
path = path + `${path}.diff`;
}
return uri.with({
scheme: 'git',
path: replaceFileExtension ? `${uri.path}.git` : uri.path,
query: JSON.stringify({
path: uri.fsPath,
ref
})
path,
query: JSON.stringify(params)
});
}