Skip to content

Commit 9f131c1

Browse files
committed
more submodule support, diff colorization
1 parent 0cd53b2 commit 9f131c1

10 files changed

Lines changed: 455 additions & 61 deletions

File tree

extensions/git/src/commands.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,33 @@ export class CommandCenter {
169169
}
170170

171171
private async _openResource(resource: Resource, preview?: boolean, preserveFocus?: boolean, preserveSelection?: boolean): Promise<void> {
172-
const stat = await new Promise<Stats>((c, e) => lstat(resource.resourceUri.fsPath, (err, stat) => err ? e(err) : c(stat)));
172+
let stat: Stats | undefined;
173173

174-
if (stat.isDirectory()) {
175-
return;
174+
try {
175+
stat = await new Promise<Stats>((c, e) => lstat(resource.resourceUri.fsPath, (err, stat) => err ? e(err) : c(stat)));
176+
} catch (err) {
177+
// noop
176178
}
177179

178-
const left = await this.getLeftResource(resource);
179-
const right = await this.getRightResource(resource);
180+
let left: Uri | undefined;
181+
let right: Uri | undefined;
182+
183+
if (stat && stat.isDirectory()) {
184+
outer:
185+
for (const repository of this.model.repositories) {
186+
for (const submodule of repository.submodules) {
187+
const submodulePath = path.join(repository.root, submodule.path);
188+
189+
if (submodulePath === resource.resourceUri.fsPath) {
190+
right = toGitUri(Uri.file(submodulePath), resource.resourceGroupType === ResourceGroupType.Index ? 'index' : 'wt', { submoduleOf: repository.root });
191+
break outer;
192+
}
193+
}
194+
}
195+
} else {
196+
left = await this.getLeftResource(resource);
197+
right = await this.getRightResource(resource);
198+
}
180199

181200
const title = this.getTitle(resource);
182201

@@ -1697,7 +1716,7 @@ export class CommandCenter {
16971716
const isSingleResource = arg instanceof Uri;
16981717

16991718
const groups = resources.reduce((result, resource) => {
1700-
const repository = this.model.getRepository(resource);
1719+
const repository = this.model.getRepository(resource, true);
17011720

17021721
if (!repository) {
17031722
console.warn('Could not find git repository for ', resource);

extensions/git/src/contentProvider.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export class GitContentProvider {
5252
return;
5353
}
5454

55-
this._onDidChange.fire(toGitUri(uri, '', true));
55+
this._onDidChange.fire(toGitUri(uri, '', { replaceFileExtension: true }));
5656
}
5757

5858
@debounce(1100)
@@ -83,6 +83,18 @@ export class GitContentProvider {
8383
}
8484

8585
async provideTextDocumentContent(uri: Uri): Promise<string> {
86+
let { path, ref, submoduleOf } = fromGitUri(uri);
87+
88+
if (submoduleOf) {
89+
const repository = this.model.getRepository(submoduleOf);
90+
91+
if (!repository) {
92+
return '';
93+
}
94+
95+
return await repository.diff(path, { cached: ref === 'index' });
96+
}
97+
8698
const repository = this.model.getRepository(uri);
8799

88100
if (!repository) {
@@ -95,8 +107,6 @@ export class GitContentProvider {
95107

96108
this.cache[cacheKey] = cacheValue;
97109

98-
let { path, ref } = fromGitUri(uri);
99-
100110
if (ref === '~') {
101111
const fileUri = Uri.file(path);
102112
const uriString = fileUri.toString();

extensions/git/src/git.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,10 @@ export function parseGitmodules(raw: string): Submodule[] {
597597
return result;
598598
}
599599

600+
export interface DiffOptions {
601+
cached?: boolean;
602+
}
603+
600604
export class Repository {
601605

602606
constructor(
@@ -735,6 +739,19 @@ export class Repository {
735739
}
736740
}
737741

742+
async diff(path: string, options: DiffOptions = {}): Promise<string> {
743+
const args = ['diff'];
744+
745+
if (options.cached) {
746+
args.push('--cached');
747+
}
748+
749+
args.push('--', path);
750+
751+
const result = await this.run(args);
752+
return result.stdout;
753+
}
754+
738755
async add(paths: string[]): Promise<void> {
739756
const args = ['add', '-A', '--'];
740757

extensions/git/src/model.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -265,19 +265,19 @@ export class Model {
265265

266266
getRepository(sourceControl: SourceControl): Repository | undefined;
267267
getRepository(resourceGroup: SourceControlResourceGroup): Repository | undefined;
268-
getRepository(path: string): Repository | undefined;
269-
getRepository(resource: Uri): Repository | undefined;
270-
getRepository(hint: any): Repository | undefined {
271-
const liveRepository = this.getOpenRepository(hint);
268+
getRepository(path: string, possibleSubmoduleRoot?: boolean): Repository | undefined;
269+
getRepository(resource: Uri, possibleSubmoduleRoot?: boolean): Repository | undefined;
270+
getRepository(hint: any, possibleSubmoduleRoot?: boolean): Repository | undefined {
271+
const liveRepository = this.getOpenRepository(hint, possibleSubmoduleRoot);
272272
return liveRepository && liveRepository.repository;
273273
}
274274

275275
private getOpenRepository(repository: Repository): OpenRepository | undefined;
276276
private getOpenRepository(sourceControl: SourceControl): OpenRepository | undefined;
277277
private getOpenRepository(resourceGroup: SourceControlResourceGroup): OpenRepository | undefined;
278-
private getOpenRepository(path: string): OpenRepository | undefined;
279-
private getOpenRepository(resource: Uri): OpenRepository | undefined;
280-
private getOpenRepository(hint: any): OpenRepository | undefined {
278+
private getOpenRepository(path: string, possibleSubmoduleRoot?: boolean): OpenRepository | undefined;
279+
private getOpenRepository(resource: Uri, possibleSubmoduleRoot?: boolean): OpenRepository | undefined;
280+
private getOpenRepository(hint: any, possibleSubmoduleRoot?: boolean): OpenRepository | undefined {
281281
if (!hint) {
282282
return undefined;
283283
}
@@ -295,15 +295,21 @@ export class Model {
295295

296296
outer:
297297
for (const liveRepository of this.openRepositories.sort((a, b) => b.repository.root.length - a.repository.root.length)) {
298+
if (possibleSubmoduleRoot && liveRepository.repository.root === resourcePath) {
299+
continue;
300+
}
301+
298302
if (!isDescendant(liveRepository.repository.root, resourcePath)) {
299303
continue;
300304
}
301305

302-
for (const submodule of liveRepository.repository.submodules) {
303-
const submoduleRoot = path.join(liveRepository.repository.root, submodule.path);
306+
if (!possibleSubmoduleRoot) {
307+
for (const submodule of liveRepository.repository.submodules) {
308+
const submoduleRoot = path.join(liveRepository.repository.root, submodule.path);
304309

305-
if (isDescendant(submoduleRoot, resourcePath)) {
306-
continue outer;
310+
if (isDescendant(submoduleRoot, resourcePath)) {
311+
continue outer;
312+
}
307313
}
308314
}
309315

extensions/git/src/repository.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
'use strict';
77

88
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento } from 'vscode';
9-
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError, Submodule } from './git';
9+
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError, Submodule, DiffOptions } from './git';
1010
import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent } from './util';
1111
import { memoize, throttle, debounce } from './decorators';
1212
import { toGitUri } from './uri';
@@ -280,6 +280,7 @@ export class Resource implements SourceControlResourceState {
280280

281281
export enum Operation {
282282
Status = 'Status',
283+
Diff = 'Diff',
283284
Add = 'Add',
284285
RevertFiles = 'RevertFiles',
285286
Commit = 'Commit',
@@ -557,7 +558,7 @@ export class Repository implements Disposable {
557558
return;
558559
}
559560

560-
return toGitUri(uri, '', true);
561+
return toGitUri(uri, '', { replaceFileExtension: true });
561562
}
562563

563564
private async updateCommitTemplate(): Promise<void> {
@@ -573,6 +574,10 @@ export class Repository implements Disposable {
573574
await this.run(Operation.Status);
574575
}
575576

577+
diff(path: string, options: DiffOptions = {}): Promise<string> {
578+
return this.run(Operation.Diff, () => this.repository.diff(path, options));
579+
}
580+
576581
async add(resources: Uri[]): Promise<void> {
577582
await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.fsPath)));
578583
}

extensions/git/src/uri.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,45 @@
77

88
import { Uri } from 'vscode';
99

10-
export function fromGitUri(uri: Uri): { path: string; ref: string; } {
10+
export interface GitUriParams {
11+
path: string;
12+
ref: string;
13+
submoduleOf?: string;
14+
}
15+
16+
export function fromGitUri(uri: Uri): GitUriParams {
1117
return JSON.parse(uri.query);
1218
}
1319

20+
export interface GitUriOptions {
21+
replaceFileExtension?: boolean;
22+
submoduleOf?: string;
23+
}
24+
1425
// As a mitigation for extensions like ESLint showing warnings and errors
1526
// for git URIs, let's change the file extension of these uris to .git,
1627
// when `replaceFileExtension` is true.
17-
export function toGitUri(uri: Uri, ref: string, replaceFileExtension = false): Uri {
28+
export function toGitUri(uri: Uri, ref: string, options: GitUriOptions = {}): Uri {
29+
const params: GitUriParams = {
30+
path: uri.fsPath,
31+
ref
32+
};
33+
34+
if (options.submoduleOf) {
35+
params.submoduleOf = options.submoduleOf;
36+
}
37+
38+
let path = uri.path;
39+
40+
if (options.replaceFileExtension) {
41+
path = path + `${path}.git`;
42+
} else if (options.submoduleOf) {
43+
path = path + `${path}.diff`;
44+
}
45+
1846
return uri.with({
1947
scheme: 'git',
20-
path: replaceFileExtension ? `${uri.path}.git` : uri.path,
21-
query: JSON.stringify({
22-
path: uri.fsPath,
23-
ref
24-
})
48+
path,
49+
query: JSON.stringify(params)
2550
});
2651
}
Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,42 @@
11
// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS:
2-
[{
3-
"name": "textmate/git.tmbundle",
4-
"version": "0.0.0",
5-
"license": "MIT",
6-
"repositoryURL": "https://github.com/textmate/git.tmbundle",
7-
"licenseDetail": [
8-
"Copyright (c) 2008 Tim Harper",
9-
"",
10-
"Permission is hereby granted, free of charge, to any person obtaining",
11-
"a copy of this software and associated documentation files (the\"",
12-
"Software\"), to deal in the Software without restriction, including",
13-
"without limitation the rights to use, copy, modify, merge, publish,",
14-
"distribute, sublicense, and/or sell copies of the Software, and to",
15-
"permit persons to whom the Software is furnished to do so, subject to",
16-
"the following conditions:",
17-
"",
18-
"The above copyright notice and this permission notice shall be",
19-
"included in all copies or substantial portions of the Software.",
20-
"",
21-
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,",
22-
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF",
23-
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND",
24-
"NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE",
25-
"LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION",
26-
"OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION",
27-
"WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
28-
]
29-
}]
2+
[
3+
{
4+
"name": "textmate/git.tmbundle",
5+
"version": "0.0.0",
6+
"license": "MIT",
7+
"repositoryURL": "https://github.com/textmate/git.tmbundle",
8+
"licenseDetail": [
9+
"Copyright (c) 2008 Tim Harper",
10+
"",
11+
"Permission is hereby granted, free of charge, to any person obtaining",
12+
"a copy of this software and associated documentation files (the\"",
13+
"Software\"), to deal in the Software without restriction, including",
14+
"without limitation the rights to use, copy, modify, merge, publish,",
15+
"distribute, sublicense, and/or sell copies of the Software, and to",
16+
"permit persons to whom the Software is furnished to do so, subject to",
17+
"the following conditions:",
18+
"",
19+
"The above copyright notice and this permission notice shall be",
20+
"included in all copies or substantial portions of the Software.",
21+
"",
22+
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,",
23+
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF",
24+
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND",
25+
"NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE",
26+
"LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION",
27+
"OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION",
28+
"WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
29+
]
30+
},
31+
{
32+
"name": "textmate/diff.tmbundle",
33+
"version": "0.0.0",
34+
"repositoryURL": "https://github.com/textmate/diff.tmbundle",
35+
"licenseDetail": [
36+
"Permission to copy, use, modify, sell and distribute this",
37+
"software is granted. This software is provided \"as is\" without",
38+
"express or implied warranty, and with no claim as to its",
39+
"suitability for any purpose."
40+
]
41+
}
42+
]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"comments": {
3+
"lineComment": "#",
4+
"blockComment": [ "#", " " ]
5+
},
6+
"brackets": [
7+
["{", "}"],
8+
["[", "]"],
9+
["(", ")"]
10+
]
11+
}

extensions/gitsyntax/package.json

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@
3737
"git-rebase-todo"
3838
],
3939
"configuration": "./git-rebase.language-configuration.json"
40+
},
41+
{
42+
"id": "diff",
43+
"aliases": [
44+
"Diff",
45+
"diff"
46+
],
47+
"extensions": [
48+
".patch",
49+
".diff",
50+
".rej"
51+
],
52+
"configuration": "./diff.language-configuration.json"
4053
}
4154
],
4255
"grammars": [
@@ -49,12 +62,19 @@
4962
"language": "git-rebase",
5063
"scopeName": "text.git-rebase",
5164
"path": "./syntaxes/git-rebase.tmLanguage.json"
65+
},
66+
{
67+
"language": "diff",
68+
"scopeName": "source.diff",
69+
"path": "./syntaxes/diff.tmLanguage"
5270
}
5371
],
5472
"configurationDefaults": {
55-
"[git-commit]": {
56-
"editor.rulers": [72]
57-
}
58-
}
73+
"[git-commit]": {
74+
"editor.rulers": [
75+
72
76+
]
77+
}
78+
}
5979
}
6080
}

0 commit comments

Comments
 (0)