Skip to content

Commit fe52312

Browse files
committed
Adds ability to close (hide) repositories in the GitLens explorer
1 parent 4dc5ce9 commit fe52312

File tree

11 files changed

+186
-114
lines changed

11 files changed

+186
-114
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
77
## [Unreleased]
88
### Added
99
- Adds (re-adds) support for handling single files — closes [#321](https://github.com/eamodio/vscode-gitlens/issues/321)
10+
- Adds *Close Repository* (`gitlens.explorers.closeRepository`) command to repository and repository status nodes in the *GitLens* explorer — closes (hides) the repository in the *GitLens* explorer
1011

1112
### Fixed
1213
- Fixes [#384](https://github.com/eamodio/vscode-gitlens/issues/384) - Absolute dates not always honored in GitLens Results explorer

package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,11 @@
15941594
"title": "Apply Changes",
15951595
"category": "GitLens"
15961596
},
1597+
{
1598+
"command": "gitlens.explorers.closeRepository",
1599+
"title": "Close Repository",
1600+
"category": "GitLens"
1601+
},
15971602
{
15981603
"command": "gitlens.explorers.compareAncestryWithWorking",
15991604
"title": "Compare Ancestry with Working Tree",
@@ -2150,6 +2155,10 @@
21502155
"command": "gitlens.explorers.applyChanges",
21512156
"when": "false"
21522157
},
2158+
{
2159+
"command": "gitlens.explorers.closeRepository",
2160+
"when": "false"
2161+
},
21532162
{
21542163
"command": "gitlens.explorers.compareAncestryWithWorking",
21552164
"when": "false"
@@ -2888,6 +2897,11 @@
28882897
"when": "viewItem == gitlens:status && gitlens:hasRemotes",
28892898
"group": "1_gitlens@1"
28902899
},
2900+
{
2901+
"command": "gitlens.explorers.closeRepository",
2902+
"when": "viewItem == gitlens:status",
2903+
"group": "8_gitlens@1"
2904+
},
28912905
{
28922906
"command": "gitlens.openBranchesInRemote",
28932907
"when": "viewItem == gitlens:remote",
@@ -2908,6 +2922,11 @@
29082922
"when": "viewItem == gitlens:repository && gitlens:hasRemotes",
29092923
"group": "1_gitlens@1"
29102924
},
2925+
{
2926+
"command": "gitlens.explorers.closeRepository",
2927+
"when": "viewItem == gitlens:repository",
2928+
"group": "8_gitlens@1"
2929+
},
29112930
{
29122931
"command": "gitlens.resultsExplorer.swapComparision",
29132932
"when": "viewItem == gitlens:results:comparison",

src/git/models/repository.ts

Lines changed: 69 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as _path from 'path';
1010

1111
export enum RepositoryChange {
1212
Config = 'config',
13+
Closed = 'closed',
1314
// FileSystem = 'file-system',
1415
Remotes = 'remotes',
1516
Repository = 'repository',
@@ -83,8 +84,9 @@ export class Repository extends Disposable {
8384
public readonly folder: WorkspaceFolder,
8485
public readonly path: string,
8586
public readonly root: boolean,
86-
private readonly onAnyRepositoryChanged: (repo: Repository) => void,
87-
suspended: boolean
87+
private readonly onAnyRepositoryChanged: (repo: Repository, reason: RepositoryChange) => void,
88+
suspended: boolean,
89+
closed: boolean = false
8890
) {
8991
super(() => this.dispose());
9092

@@ -103,7 +105,9 @@ export class Repository extends Disposable {
103105
this.normalizedPath = (this.path.endsWith('/') ? this.path : `${this.path}/`).toLowerCase();
104106

105107
this._suspended = suspended;
108+
this._closed = closed;
106109

110+
// TODO: createFileSystemWatcher doesn't work unless the folder is part of the workspaceFolders
107111
const watcher = workspace.createFileSystemWatcher(new RelativePattern(folder, '{**/.git/config,**/.git/index,**/.git/HEAD,**/.git/refs/stash,**/.git/refs/heads/**,**/.git/refs/remotes/**,**/.git/refs/tags/**,**/.gitignore}'));
108112
this._disposable = Disposable.from(
109113
watcher,
@@ -178,59 +182,21 @@ export class Repository extends Disposable {
178182
return;
179183
}
180184

181-
this.onAnyRepositoryChanged(this);
185+
this.onAnyRepositoryChanged(this, RepositoryChange.Repository);
182186
this.fireChange(RepositoryChange.Repository);
183187
}
184188

185-
private fireChange(...reasons: RepositoryChange[]) {
186-
if (this._fireChangeDebounced === undefined) {
187-
this._fireChangeDebounced = Functions.debounce(this.fireChangeCore, 250);
188-
}
189-
190-
if (this._pendingChanges.repo === undefined) {
191-
this._pendingChanges.repo = new RepositoryChangeEvent(this);
192-
}
193-
194-
const e = this._pendingChanges.repo;
195-
196-
for (const reason of reasons) {
197-
if (!e.changes.includes(reason)) {
198-
e.changes.push(reason);
199-
}
200-
}
201-
202-
if (this._suspended) return;
203-
204-
this._fireChangeDebounced(e);
205-
}
206-
207-
private fireChangeCore(e: RepositoryChangeEvent) {
208-
this._pendingChanges.repo = undefined;
209-
210-
this._onDidChange.fire(e);
189+
private _closed: boolean = false;
190+
get closed(): boolean {
191+
return this._closed;
211192
}
212-
213-
private fireFileSystemChange(uri: Uri) {
214-
if (this._fireFileSystemChangeDebounced === undefined) {
215-
this._fireFileSystemChangeDebounced = Functions.debounce(this.fireFileSystemChangeCore, 2500);
193+
set closed(value: boolean) {
194+
const changed = this._closed !== value;
195+
this._closed = value;
196+
if (changed) {
197+
this.onAnyRepositoryChanged(this, RepositoryChange.Closed);
198+
this.fireChange(RepositoryChange.Closed);
216199
}
217-
218-
if (this._pendingChanges.fs === undefined) {
219-
this._pendingChanges.fs = { repository: this, uris: [] };
220-
}
221-
222-
const e = this._pendingChanges.fs;
223-
e.uris.push(uri);
224-
225-
if (this._suspended) return;
226-
227-
this._fireFileSystemChangeDebounced(e);
228-
}
229-
230-
private fireFileSystemChangeCore(e: RepositoryFileSystemChangeEvent) {
231-
this._pendingChanges.fs = undefined;
232-
233-
this._onDidChangeFileSystem.fire(e);
234200
}
235201

236202
containsUri(uri: Uri) {
@@ -313,6 +279,7 @@ export class Repository extends Disposable {
313279
this._fsWatchCounter++;
314280
if (this._fsWatcherDisposable !== undefined) return;
315281

282+
// TODO: createFileSystemWatcher doesn't work unless the folder is part of the workspaceFolders
316283
const watcher = workspace.createFileSystemWatcher(new RelativePattern(this.folder, `**`));
317284
this._fsWatcherDisposable = Disposable.from(
318285
watcher,
@@ -333,4 +300,56 @@ export class Repository extends Disposable {
333300
suspend() {
334301
this._suspended = true;
335302
}
303+
304+
private fireChange(...reasons: RepositoryChange[]) {
305+
if (this._fireChangeDebounced === undefined) {
306+
this._fireChangeDebounced = Functions.debounce(this.fireChangeCore, 250);
307+
}
308+
309+
if (this._pendingChanges.repo === undefined) {
310+
this._pendingChanges.repo = new RepositoryChangeEvent(this);
311+
}
312+
313+
const e = this._pendingChanges.repo;
314+
315+
for (const reason of reasons) {
316+
if (!e.changes.includes(reason)) {
317+
e.changes.push(reason);
318+
}
319+
}
320+
321+
if (this._suspended) return;
322+
323+
this._fireChangeDebounced(e);
324+
}
325+
326+
private fireChangeCore(e: RepositoryChangeEvent) {
327+
this._pendingChanges.repo = undefined;
328+
329+
this._onDidChange.fire(e);
330+
}
331+
332+
private fireFileSystemChange(uri: Uri) {
333+
if (this._fireFileSystemChangeDebounced === undefined) {
334+
this._fireFileSystemChangeDebounced = Functions.debounce(this.fireFileSystemChangeCore, 2500);
335+
}
336+
337+
if (this._pendingChanges.fs === undefined) {
338+
this._pendingChanges.fs = { repository: this, uris: [] };
339+
}
340+
341+
const e = this._pendingChanges.fs;
342+
e.uris.push(uri);
343+
344+
if (this._suspended) return;
345+
346+
this._fireFileSystemChangeDebounced(e);
347+
}
348+
349+
private fireFileSystemChangeCore(e: RepositoryFileSystemChangeEvent) {
350+
this._pendingChanges.fs = undefined;
351+
352+
this._onDidChangeFileSystem.fire(e);
353+
}
354+
336355
}

src/gitService.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { configuration, IRemotesConfig } from './configuration';
55
import { CommandContext, DocumentSchemes, setCommandContext } from './constants';
66
import { Container } from './container';
77
import { RemoteProviderFactory, RemoteProviderMap } from './git/remotes/factory';
8-
import { CommitFormatting, Git, GitAuthor, GitBlame, GitBlameCommit, GitBlameLine, GitBlameLines, GitBlameParser, GitBranch, GitBranchParser, GitCommit, GitCommitType, GitDiff, GitDiffChunkLine, GitDiffParser, GitDiffShortStat, GitLog, GitLogCommit, GitLogParser, GitRemote, GitRemoteParser, GitStash, GitStashParser, GitStatus, GitStatusFile, GitStatusParser, GitTag, GitTagParser, IGit, Repository } from './git/git';
8+
import { CommitFormatting, Git, GitAuthor, GitBlame, GitBlameCommit, GitBlameLine, GitBlameLines, GitBlameParser, GitBranch, GitBranchParser, GitCommit, GitCommitType, GitDiff, GitDiffChunkLine, GitDiffParser, GitDiffShortStat, GitLog, GitLogCommit, GitLogParser, GitRemote, GitRemoteParser, GitStash, GitStashParser, GitStatus, GitStatusFile, GitStatusParser, GitTag, GitTagParser, IGit, Repository, RepositoryChange } from './git/git';
99
import { CachedBlame, CachedDiff, CachedLog, GitDocumentState, TrackedDocument } from './trackers/gitDocumentTracker';
1010
import { GitUri, IGitCommitInfo } from './git/gitUri';
1111
import { Logger } from './logger';
@@ -75,8 +75,17 @@ export class GitService extends Disposable {
7575
return Container.config.advanced.caching.enabled;
7676
}
7777

78-
private onAnyRepositoryChanged(repo: Repository) {
78+
private onAnyRepositoryChanged(repo: Repository, reason: RepositoryChange) {
7979
this._trackedCache.clear();
80+
81+
if (reason === RepositoryChange.Closed) {
82+
// Send a notification that the repositories changed
83+
setImmediate(async () => {
84+
await this.updateContext(this._repositoryTree);
85+
86+
this.fireRepositoriesChanged();
87+
});
88+
}
8089
}
8190

8291
private onConfigurationChanged(e: ConfigurationChangeEvent) {
@@ -1248,9 +1257,13 @@ export class GitService extends Disposable {
12481257
return Container.git.getActiveRepoPath(editor);
12491258
}
12501259

1251-
async getRepositories(): Promise<Iterable<Repository>> {
1260+
async getRepositories(predicate?: (repo: Repository) => boolean): Promise<Iterable<Repository>> {
12521261
const repositoryTree = await this.getRepositoryTree();
1253-
return repositoryTree.values();
1262+
1263+
const values = repositoryTree.values();
1264+
return predicate !== undefined
1265+
? Iterables.filter(values, predicate)
1266+
: values;
12541267
}
12551268

12561269
private async getRepositoryTree(): Promise<TernarySearchTree<Repository>> {

src/system/iterable.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
'use strict';
22

33
export namespace Iterables {
4-
export function count<T>(source: Iterable<T> | IterableIterator<T>): number {
4+
export function count<T>(source: Iterable<T> | IterableIterator<T>, predicate?: (item: T) => boolean): number {
55
let count = 0;
66
let next: IteratorResult<T>;
77

88
while (true) {
99
next = (source as IterableIterator<T>).next();
1010
if (next.done) break;
1111

12-
count++;
12+
if (predicate === undefined || predicate(next.value)) {
13+
count++;
14+
}
1315
}
1416

1517
return count;

0 commit comments

Comments
 (0)