Procházet zdrojové kódy

Reworks reveal for the new views (wip)

main
Eric Amodio před 4 roky
rodič
revize
a5fd211f21
31 změnil soubory, kde provedl 856 přidání a 449 odebrání
  1. +12
    -19
      README.md
  2. +4
    -4
      package.json
  3. +3
    -3
      src/commands/git/stash.ts
  4. +98
    -1
      src/commands/gitCommands.actions.ts
  5. +1
    -1
      src/commands/quickCommand.buttons.ts
  6. +31
    -30
      src/commands/quickCommand.steps.ts
  7. +2
    -2
      src/commands/showQuickCommit.ts
  8. +4
    -7
      src/quickpicks/quickPicksItems.ts
  9. +2
    -2
      src/statusbar/statusBarController.ts
  10. +75
    -111
      src/views/branchesView.ts
  11. +74
    -66
      src/views/commitsView.ts
  12. +63
    -23
      src/views/contributorsView.ts
  13. +6
    -4
      src/views/nodes/branchNode.ts
  14. +6
    -5
      src/views/nodes/branchTrackingStatusNode.ts
  15. +2
    -1
      src/views/nodes/branchesNode.ts
  16. +4
    -3
      src/views/nodes/contributorNode.ts
  17. +18
    -7
      src/views/nodes/contributorsNode.ts
  18. +1
    -0
      src/views/nodes/fileHistoryNode.ts
  19. +1
    -0
      src/views/nodes/lineHistoryNode.ts
  20. +17
    -4
      src/views/nodes/remotesNode.ts
  21. +16
    -4
      src/views/nodes/stashesNode.ts
  22. +4
    -3
      src/views/nodes/tagNode.ts
  23. +36
    -23
      src/views/nodes/tagsNode.ts
  24. +4
    -6
      src/views/nodes/viewNode.ts
  25. +175
    -43
      src/views/remotesView.ts
  26. +3
    -3
      src/views/repositoriesView.ts
  27. +119
    -31
      src/views/stashesView.ts
  28. +62
    -37
      src/views/tagsView.ts
  29. +10
    -3
      src/views/viewBase.ts
  30. +2
    -2
      src/webviews/apps/settings/partials/code-lens.html
  31. +1
    -1
      src/webviews/apps/settings/partials/status-bar.html

+ 12
- 19
README.md Zobrazit soubor

@ -20,17 +20,10 @@
While GitLens is generously offered to everyone free of charge, if you find it useful, please consider [**sponsoring**](https://gitlens.amod.io/#sponsor) it. Also please [write a review](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#review-details 'Write a review'), [star me on GitHub](https://github.com/eamodio/vscode-gitlens 'Star me on GitHub'), and [follow me on Twitter](https://twitter.com/eamodio 'Follow me on Twitter')
# What's new in GitLens 10
- Adds all-new iconography to better match VS Code's new visual style
- Adds an all-new Welcome experience with a simple quick setup of common GitLens features
- Adds a new and improved interactive Settings editor experience
- Adds a new and improved _Git Commands_ experience
- Adds an all-new commit search experience — complete with ability to match on more than one search pattern
- Adds a _Reveal Commit in Repositories View_ command to reveal the current commit in the _Repositories_ view
- Adds a _Show Commits within Selection in Search Commits View_ command to show all the commits within the current selection in the _Search Commits_ view
- Adds new actions options to the Git Code Lens
- Adds ability to sort branches and tags in quick pick menus and views
# What's new in GitLens 11
TBD
- And much more
See the [release notes](https://github.com/eamodio/vscode-gitlens/blob/master/CHANGELOG.md 'Open Release Notes') for the full set of changes
@ -767,19 +760,19 @@ See also [View Settings](#view-settings- 'Jump to the View settings')
See also [View Settings](#view-settings- 'Jump to the View settings')
| Name | Description |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gitlens.views.fileHistory.avatars` | Specifies whether to show avatar images instead of status icons in the _File History_ view |
| `gitlens.views.fileHistory.enabled` | Specifies whether to show the _File History_ view |
| Name | Description |
| ----------------------------------- | ------------------------------------------------------------------------------------------ |
| `gitlens.views.fileHistory.avatars` | Specifies whether to show avatar images instead of status icons in the _File History_ view |
| `gitlens.views.fileHistory.enabled` | Specifies whether to show the _File History_ view |
### Line History View Settings [#](#line-history-view-settings- 'Line History View Settings')
See also [View Settings](#view-settings- 'Jump to the View settings')
| Name | Description |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gitlens.views.lineHistory.avatars` | Specifies whether to show avatar images instead of status icons in the _Line History_ view |
| `gitlens.views.lineHistory.enabled` | Specifies whether to show the _Line History_ view |
| Name | Description |
| ----------------------------------- | ------------------------------------------------------------------------------------------ |
| `gitlens.views.lineHistory.avatars` | Specifies whether to show avatar images instead of status icons in the _Line History_ view |
| `gitlens.views.lineHistory.enabled` | Specifies whether to show the _Line History_ view |
### Search View Settings [#](#search-view-settings- 'Search View Settings')

+ 4
- 4
package.json Zobrazit soubor

@ -264,7 +264,7 @@
"enumDescriptions": [
"Toggles file blame annotations",
"Compares the current committed file with the previous commit",
"Reveals the commit in the Repositories view",
"Reveals the commit in the side bar",
"Shows the commits within the range in the Search Commits view",
"Shows a commit details quick pick",
"Shows a commit file details quick pick",
@ -317,7 +317,7 @@
"enumDescriptions": [
"Toggles file blame annotations",
"Compares the current committed file with the previous commit",
"Reveals the commit in the Repositories view",
"Reveals the commit in the side bar",
"Shows the commit in the Search Commits view",
"Shows a commit details quick pick",
"Shows a commit file details quick pick",
@ -1423,7 +1423,7 @@
"Compares the current line commit with the previous",
"Compares the current line commit with the working tree",
"Toggles Git code lens",
"Reveals the commit in the Repositories view",
"Reveals the commit in the side bar",
"Shows the commit in the Search Commits view",
"Shows a commit details quick pick",
"Shows a commit file details quick pick",
@ -2585,7 +2585,7 @@
},
{
"command": "gitlens.revealCommitInView",
"title": "Reveal Commit in Repositories View",
"title": "Reveal Commit in Side BSar",
"category": "GitLens"
},
{

+ 3
- 3
src/commands/git/stash.ts Zobrazit soubor

@ -4,7 +4,7 @@ import { GlyphChars } from '../../constants';
import { Container } from '../../container';
import { GitReference, GitStashCommit, GitStashReference, Repository } from '../../git/git';
import { GitUri } from '../../git/gitUri';
import { GitCommandsCommand } from '../gitCommands';
import { GitActions, GitCommandsCommand } from '../gitCommands';
import {
appendReposToTitle,
PartialStepState,
@ -353,7 +353,7 @@ export class StashGitCommand extends QuickCommand {
additionalButtons: [QuickCommandButtons.RevealInView],
onDidClickButton: (quickpick, button) => {
if (button === QuickCommandButtons.RevealInView) {
void Container.repositoriesView.revealStash(state.reference, {
void GitActions.Stash.reveal(state.reference, {
select: true,
expand: true,
});
@ -412,7 +412,7 @@ export class StashGitCommand extends QuickCommand {
additionalButtons: [QuickCommandButtons.RevealInView],
onDidClickButton: (quickpick, button) => {
if (button === QuickCommandButtons.RevealInView) {
void Container.repositoriesView.revealStash(state.reference, {
void GitActions.Stash.reveal(state.reference, {
select: true,
expand: true,
});

+ 98
- 1
src/commands/gitCommands.actions.ts Zobrazit soubor

@ -11,7 +11,7 @@ import {
GitCommandsCommandArgs,
OpenWorkingFileCommandArgs,
} from '../commands';
import { FileAnnotationType } from '../configuration';
import { configuration, FileAnnotationType } from '../configuration';
import { Container } from '../container';
import {
GitBranchReference,
@ -19,6 +19,7 @@ import {
GitFile,
GitLogCommit,
GitReference,
GitRemote,
GitRevision,
GitRevisionReference,
GitStashReference,
@ -132,6 +133,28 @@ export namespace GitActions {
},
});
}
export async function reveal(
branch: GitBranchReference,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
if (configuration.get('views', 'repositories', 'enabled')) {
return Container.repositoriesView.revealBranch(branch, options);
}
let node;
if (!branch.remote) {
node = await Container.branchesView.revealBranch(branch, options);
} else {
node = await Container.remotesView.revealBranch(branch, options);
}
return node;
}
}
export namespace Commit {
@ -641,6 +664,32 @@ export namespace GitActions {
fileName: typeof file === 'string' ? file : file.fileName,
}));
}
export async function reveal(
commit: GitRevisionReference,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
if (configuration.get('views', 'repositories', 'enabled')) {
return Container.repositoriesView.revealCommit(commit, options);
}
// TODO@eamodio stop duplicate notifications
let node = await Container.commitsView.revealCommit(commit, options);
if (node != null) return node;
node = await Container.branchesView.revealCommit(commit, options);
if (node != null) return node;
node = await Container.remotesView.revealCommit(commit, options);
if (node != null) return node;
return undefined;
}
}
export namespace Contributor {
@ -679,6 +728,22 @@ export namespace GitActions {
},
});
}
export async function reveal(
tag: GitTagReference,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
if (configuration.get('views', 'repositories', 'enabled')) {
return Container.repositoriesView.revealTag(tag, options);
}
const node = await Container.tagsView.revealTag(tag, options);
return node;
}
}
export namespace Remote {
@ -720,6 +785,22 @@ export namespace GitActions {
export async function prune(repo: string | Repository, remote: string) {
void (await Container.git.pruneRemote(typeof repo === 'string' ? repo : repo.path, remote));
}
export async function reveal(
remote: GitRemote,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
// if (configuration.get('views', 'repositories', 'enabled')) {
// return Container.repositoriesView.revealRemote(remote, options);
// }
const node = await Container.remotesView.revealRemote(remote, options);
return node;
}
}
export namespace Stash {
@ -756,5 +837,21 @@ export namespace GitActions {
},
});
}
export async function reveal(
stash: GitStashReference,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
if (configuration.get('views', 'repositories', 'enabled')) {
return Container.repositoriesView.revealStash(stash, options);
}
const node = await Container.stashesView.revealStash(stash, options);
return node;
}
}
}

+ 1
- 1
src/commands/quickCommand.buttons.ts Zobrazit soubor

@ -99,7 +99,7 @@ export namespace QuickCommandButtons {
export const RevealInView: QuickInputButton = {
iconPath: new ThemeIcon('eye'),
tooltip: 'Reveal in Repositories View',
tooltip: 'Reveal in Side Bar',
};
export const ShowInView: QuickInputButton = {

+ 31
- 30
src/commands/quickCommand.steps.ts Zobrazit soubor

@ -73,6 +73,7 @@ import {
} from '../quickpicks';
import { Arrays, Iterables, Strings } from '../system';
import { GitUri } from '../git/gitUri';
import { GitActions } from './gitCommands.actions';
export function appendReposToTitle<
State extends { repo: Repository } | { repos: Repository[] },
@ -382,7 +383,7 @@ export async function* pickBranchStep<
return;
}
void Container.repositoriesView.revealBranch(quickpick.activeItems[0].item, {
void GitActions.Branch.reveal(quickpick.activeItems[0].item, {
select: true,
expand: true,
});
@ -392,7 +393,7 @@ export async function* pickBranchStep<
onDidPressKey: async quickpick => {
if (quickpick.activeItems.length === 0) return;
await Container.repositoriesView.revealBranch(quickpick.activeItems[0].item, {
await GitActions.Branch.reveal(quickpick.activeItems[0].item, {
select: true,
focus: false,
expand: true,
@ -447,7 +448,7 @@ export async function* pickBranchesStep<
return;
}
void Container.repositoriesView.revealBranch(quickpick.activeItems[0].item, {
void GitActions.Branch.reveal(quickpick.activeItems[0].item, {
select: true,
expand: true,
});
@ -457,7 +458,7 @@ export async function* pickBranchesStep<
onDidPressKey: async quickpick => {
if (quickpick.activeItems.length === 0) return;
await Container.repositoriesView.revealBranch(quickpick.activeItems[0].item, {
await GitActions.Branch.reveal(quickpick.activeItems[0].item, {
select: true,
focus: false,
expand: true,
@ -558,11 +559,11 @@ export async function* pickBranchOrTagStep<
const item = quickpick.activeItems[0].item;
if (GitReference.isBranch(item)) {
void Container.repositoriesView.revealBranch(item, { select: true, expand: true });
void GitActions.Branch.reveal(item, { select: true, expand: true });
} else if (GitReference.isTag(item)) {
void Container.repositoriesView.revealTag(item, { select: true, expand: true });
void GitActions.Tag.reveal(item, { select: true, expand: true });
} else if (GitReference.isRevision(item)) {
void Container.repositoriesView.revealCommit(item, { select: true, expand: true });
void GitActions.Commit.reveal(item, { select: true, expand: true });
}
}
},
@ -572,11 +573,11 @@ export async function* pickBranchOrTagStep<
const item = quickpick.activeItems[0].item;
if (GitReference.isBranch(item)) {
void Container.repositoriesView.revealBranch(item, { select: true, focus: false, expand: true });
void GitActions.Branch.reveal(item, { select: true, focus: false, expand: true });
} else if (GitReference.isTag(item)) {
void Container.repositoriesView.revealTag(item, { select: true, focus: false, expand: true });
void GitActions.Tag.reveal(item, { select: true, focus: false, expand: true });
} else if (GitReference.isRevision(item)) {
void Container.repositoriesView.revealCommit(item, { select: true, focus: false, expand: true });
void GitActions.Commit.reveal(item, { select: true, focus: false, expand: true });
}
},
onValidateValue: getValidateGitReferenceFn(state.repo),
@ -674,11 +675,11 @@ export async function* pickBranchOrTagStepMultiRepo<
const item = quickpick.activeItems[0].item;
if (GitReference.isBranch(item)) {
void Container.repositoriesView.revealBranch(item, { select: true, expand: true });
void GitActions.Branch.reveal(item, { select: true, expand: true });
} else if (GitReference.isTag(item)) {
void Container.repositoriesView.revealTag(item, { select: true, expand: true });
void GitActions.Tag.reveal(item, { select: true, expand: true });
} else if (GitReference.isRevision(item)) {
void Container.repositoriesView.revealCommit(item, { select: true, expand: true });
void GitActions.Commit.reveal(item, { select: true, expand: true });
}
}
},
@ -688,11 +689,11 @@ export async function* pickBranchOrTagStepMultiRepo<
const item = quickpick.activeItems[0].item;
if (GitReference.isBranch(item)) {
void Container.repositoriesView.revealBranch(item, { select: true, focus: false, expand: true });
void GitActions.Branch.reveal(item, { select: true, focus: false, expand: true });
} else if (GitReference.isTag(item)) {
void Container.repositoriesView.revealTag(item, { select: true, focus: false, expand: true });
void GitActions.Tag.reveal(item, { select: true, focus: false, expand: true });
} else if (GitReference.isRevision(item)) {
void Container.repositoriesView.revealCommit(item, { select: true, focus: false, expand: true });
void GitActions.Commit.reveal(item, { select: true, focus: false, expand: true });
}
},
onValidateValue: getValidateGitReferenceFn(state.repos),
@ -778,7 +779,7 @@ export function* pickCommitStep<
if (quickpick.activeItems.length === 0 || log == null) return;
if (button === QuickCommandButtons.RevealInView) {
void Container.repositoriesView.revealCommit(quickpick.activeItems[0].item, {
void GitActions.Commit.reveal(quickpick.activeItems[0].item, {
select: true,
focus: false,
expand: true,
@ -809,7 +810,7 @@ export function* pickCommitStep<
if (quickpick.activeItems.length === 0) return;
if (key === 'ctrl+right') {
await Container.repositoriesView.revealCommit(quickpick.activeItems[0].item, {
await GitActions.Commit.reveal(quickpick.activeItems[0].item, {
select: true,
focus: false,
expand: true,
@ -897,7 +898,7 @@ export function* pickCommitsStep<
if (quickpick.activeItems.length === 0 || log == null) return;
if (button === QuickCommandButtons.RevealInView) {
void Container.repositoriesView.revealCommit(quickpick.activeItems[0].item, {
void GitActions.Commit.reveal(quickpick.activeItems[0].item, {
select: true,
focus: false,
expand: true,
@ -928,7 +929,7 @@ export function* pickCommitsStep<
if (quickpick.activeItems.length === 0) return;
if (key === 'ctrl+right') {
await Container.repositoriesView.revealCommit(quickpick.activeItems[0].item, {
await GitActions.Commit.reveal(quickpick.activeItems[0].item, {
select: true,
focus: false,
expand: true,
@ -1146,7 +1147,7 @@ export function* pickStashStep<
expand: true,
});
} else {
void Container.repositoriesView.revealStash(quickpick.activeItems[0].item, {
void GitActions.Stash.reveal(quickpick.activeItems[0].item, {
select: true,
focus: false,
expand: true,
@ -1179,7 +1180,7 @@ export function* pickStashStep<
onDidPressKey: async quickpick => {
if (quickpick.activeItems.length === 0) return;
await Container.repositoriesView.revealStash(quickpick.activeItems[0].item, {
await GitActions.Stash.reveal(quickpick.activeItems[0].item, {
select: true,
focus: false,
expand: true,
@ -1234,7 +1235,7 @@ export async function* pickTagsStep<
return;
}
void Container.repositoriesView.revealTag(quickpick.activeItems[0].item, {
void GitActions.Tag.reveal(quickpick.activeItems[0].item, {
select: true,
expand: true,
});
@ -1244,7 +1245,7 @@ export async function* pickTagsStep<
onDidPressKey: async quickpick => {
if (quickpick.activeItems.length === 0) return;
await Container.repositoriesView.revealTag(quickpick.activeItems[0].item, {
await GitActions.Tag.reveal(quickpick.activeItems[0].item, {
select: true,
focus: false,
expand: true,
@ -1299,13 +1300,13 @@ export async function* showCommitOrStashStep<
if (button === QuickCommandButtons.RevealInView) {
if (GitReference.isStash(state.reference)) {
void Container.repositoriesView.revealStash(state.reference, {
void GitActions.Stash.reveal(state.reference, {
select: true,
focus: false,
expand: true,
});
} else {
void Container.repositoriesView.revealCommit(state.reference, {
void GitActions.Commit.reveal(state.reference, {
select: true,
focus: false,
expand: true,
@ -1506,13 +1507,13 @@ export async function* showCommitOrStashFilesStep<
if (button === QuickCommandButtons.RevealInView) {
if (GitReference.isStash(state.reference)) {
void Container.repositoriesView.revealStash(state.reference, {
void GitActions.Stash.reveal(state.reference, {
select: true,
focus: false,
expand: true,
});
} else {
void Container.repositoriesView.revealCommit(state.reference, {
void GitActions.Commit.reveal(state.reference, {
select: true,
focus: false,
expand: true,
@ -1578,13 +1579,13 @@ export async function* showCommitOrStashFileStep<
if (button === QuickCommandButtons.RevealInView) {
if (GitReference.isStash(state.reference)) {
void Container.repositoriesView.revealStash(state.reference, {
void GitActions.Stash.reveal(state.reference, {
select: true,
focus: false,
expand: true,
});
} else {
void Container.repositoriesView.revealCommit(state.reference, {
void GitActions.Commit.reveal(state.reference, {
select: true,
focus: false,
expand: true,

+ 2
- 2
src/commands/showQuickCommit.ts Zobrazit soubor

@ -10,7 +10,7 @@ import {
} from './common';
import { Container } from '../container';
import { GitCommit, GitLog, GitLogCommit } from '../git/git';
import { executeGitCommand } from './gitCommands';
import { executeGitCommand, GitActions } from './gitCommands';
import { GitUri } from '../git/gitUri';
import { Logger } from '../logger';
import { Messages } from '../messages';
@ -137,7 +137,7 @@ export class ShowQuickCommitCommand extends ActiveEditorCachedCommand {
}
if (args.revealInView) {
void (await Container.repositoriesView.revealCommit(args.commit, {
void (await GitActions.Commit.reveal(args.commit, {
select: true,
focus: true,
expand: true,

+ 4
- 7
src/quickpicks/quickPicksItems.ts Zobrazit soubor

@ -1,10 +1,9 @@
'use strict';
import { commands, QuickPickItem } from 'vscode';
import { Commands } from '../commands';
import { Commands, GitActions } from '../commands';
import { Container } from '../container';
import { GitReference, GitRevisionReference, GitStashCommit, SearchPattern } from '../git/git';
import { Keys } from '../keyboard';
import { GlyphChars } from '../constants';
declare module 'vscode' {
interface QuickPickItem {
@ -207,9 +206,7 @@ export class RevealInRepositoriesViewQuickPickItem extends CommandQuickPickItem
private readonly reference: GitRevisionReference,
item: QuickPickItem = {
label: `$(eye) Reveal ${GitReference.isStash(reference) ? 'Stash' : 'Commit'}`,
description: `in Repositories view ${
GitReference.isStash(reference) ? '' : `${GlyphChars.Dash} this can take a while`
}`,
description: GitReference.isStash(reference) ? '' : 'can take a while',
},
) {
super(item, undefined, undefined);
@ -217,13 +214,13 @@ export class RevealInRepositoriesViewQuickPickItem extends CommandQuickPickItem
async execute(options?: { preserveFocus?: boolean; preview?: boolean }): Promise<void> {
if (GitStashCommit.is(this.reference)) {
void (await Container.repositoriesView.revealStash(this.reference, {
void (await GitActions.Stash.reveal(this.reference, {
select: true,
focus: !(options?.preserveFocus ?? false),
expand: true,
}));
} else {
void (await Container.repositoriesView.revealCommit(this.reference, {
void (await GitActions.Commit.reveal(this.reference, {
select: true,
focus: !(options?.preserveFocus ?? false),
expand: true,

+ 2
- 2
src/statusbar/statusBarController.ts Zobrazit soubor

@ -152,10 +152,10 @@ export class StatusBarController implements Disposable {
this._blameStatusBarItem.tooltip = 'Toggle Git CodeLens';
break;
case StatusBarCommand.RevealCommitInView:
this._blameStatusBarItem.tooltip = 'Reveal Commit in Repositories View';
this._blameStatusBarItem.tooltip = 'Reveal Commit in the Side Bar';
break;
case StatusBarCommand.ShowCommitsInView:
this._blameStatusBarItem.tooltip = 'Show Commit in Repositories View';
this._blameStatusBarItem.tooltip = 'Show Commit in Search Commits View';
break;
case StatusBarCommand.ShowQuickCommitDetails:
this._blameStatusBarItem.tooltip = 'Show Commit';

+ 75
- 111
src/views/branchesView.ts Zobrazit soubor

@ -11,7 +11,6 @@ import {
import { BranchesViewConfig, configuration, ViewBranchesLayout, ViewFilesLayout } from '../configuration';
import { Container } from '../container';
import {
GitBranch,
GitBranchReference,
GitLogCommit,
GitReference,
@ -27,9 +26,6 @@ import {
BranchOrTagFolderNode,
ContextValues,
MessageNode,
RemoteNode,
RemotesNode,
RepositoriesNode,
RepositoryNode,
SubscribeableViewNode,
unknownGitUri,
@ -39,6 +35,7 @@ import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
export class BranchesRepositoryNode extends SubscribeableViewNode<BranchesView> {
protected splatted = true;
private child: BranchesNode | undefined;
constructor(
@ -46,32 +43,48 @@ export class BranchesRepositoryNode extends SubscribeableViewNode
view: BranchesView,
parent: ViewNode,
public readonly repo: Repository,
private readonly root: boolean,
splatted: boolean,
) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
async getChildren(): Promise<ViewNode[]> {
void this.ensureSubscription();
if (this.child == null) {
this.child = new BranchesNode(this.uri, this.view, this, this.repo);
void this.ensureSubscription();
}
return this.child.getChildren();
}
getTreeItem(): TreeItem {
this.splatted = false;
void this.ensureSubscription();
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
void this.ensureSubscription();
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
@ -105,14 +118,15 @@ export class BranchesRepositoryNode extends SubscribeableViewNode
e.changed(RepositoryChange.Remotes)
) {
void this.triggerChange(true);
if (this.root) {
void this.parent?.triggerChange(true);
}
// if (this.root) {
// void this.parent?.triggerChange(true);
// }
}
}
}
export class BranchesViewNode extends ViewNode<BranchesView> {
protected splatted = true;
private children: BranchesRepositoryNode[] | undefined;
constructor(view: BranchesView) {
@ -120,22 +134,17 @@ export class BranchesViewNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
if (this.children != null) {
for (const child of this.children) {
child.dispose?.();
}
this.children = undefined;
if (this.children == null) {
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No branches could be found.')];
const splat = repositories.length === 1;
this.children = repositories.map(
r => new BranchesRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, splat),
);
}
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No branches could be found.')];
const root = repositories.length === 1;
this.children = repositories.map(
r => new BranchesRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, root),
);
if (root) {
if (this.children.length === 1) {
const [child] = this.children;
const branches = await child.repo.getBranches({ filter: b => !b.remote });
@ -143,6 +152,7 @@ export class BranchesViewNode extends ViewNode {
return child.getChildren();
}
return this.children;
}
@ -150,6 +160,25 @@ export class BranchesViewNode extends ViewNode {
const item = new TreeItem('Branches', TreeItemCollapsibleState.Expanded);
return item;
}
async getSplattedChild() {
if (this.children == null) {
await this.getChildren();
}
return this.children?.length === 1 ? this.children[0] : undefined;
}
@gate()
@debug()
refresh(reset: boolean = false) {
if (reset && this.children != null) {
for (const child of this.children) {
child.dispose();
}
this.children = undefined;
}
}
}
export class BranchesView extends ViewBase<BranchesViewNode, BranchesViewConfig> {
@ -218,45 +247,17 @@ export class BranchesView extends ViewBase
}
findBranch(branch: GitBranchReference, token?: CancellationToken) {
const repoNodeId = RepositoryNode.getId(branch.repoPath);
if (branch.remote) return undefined;
if (branch.remote) {
return this.findNode((n: any) => n.branch !== undefined && n.branch.ref === branch.ref, {
allowPaging: true,
maxDepth: 6,
canTraverse: n => {
// Only search for branch nodes in the same repo within BranchesNode
if (n instanceof RepositoriesNode) return true;
if (n instanceof RemoteNode) {
if (!n.id.startsWith(repoNodeId)) return false;
return branch.remote && n.remote.name === GitBranch.getRemote(branch.name); //branch.getRemoteName();
}
if (
n instanceof RepositoryNode ||
n instanceof BranchesNode ||
n instanceof RemotesNode ||
n instanceof BranchOrTagFolderNode
) {
return n.id.startsWith(repoNodeId);
}
return false;
},
token: token,
});
}
const repoNodeId = RepositoryNode.getId(branch.repoPath);
return this.findNode((n: any) => n.branch !== undefined && n.branch.ref === branch.ref, {
return this.findNode((n: any) => n.branch?.ref === branch.ref, {
allowPaging: true,
maxDepth: 5,
maxDepth: 4,
canTraverse: n => {
// Only search for branch nodes in the same repo within BranchesNode
if (n instanceof RepositoriesNode) return true;
if (n instanceof BranchesViewNode) return true;
if (n instanceof RepositoryNode || n instanceof BranchesNode || n instanceof BranchOrTagFolderNode) {
if (n instanceof BranchesRepositoryNode || n instanceof BranchOrTagFolderNode) {
return n.id.startsWith(repoNodeId);
}
@ -270,59 +271,22 @@ export class BranchesView extends ViewBase
const repoNodeId = RepositoryNode.getId(commit.repoPath);
// Get all the branches the commit is on
let branches = await Container.git.getCommitBranches(commit.repoPath, commit.ref);
if (branches.length !== 0) {
return this.findNode((n: any) => n.commit !== undefined && n.commit.ref === commit.ref, {
allowPaging: true,
maxDepth: 6,
canTraverse: async n => {
// Only search for commit nodes in the same repo within BranchNodes
if (n instanceof RepositoriesNode) return true;
if (n instanceof BranchNode) {
if (n.id.startsWith(repoNodeId) && branches.includes(n.branch.name)) {
await n.showMore({ until: commit.ref });
return true;
}
}
if (
n instanceof RepositoryNode ||
n instanceof BranchesNode ||
n instanceof BranchOrTagFolderNode
) {
return n.id.startsWith(repoNodeId);
}
return false;
},
token: token,
});
}
// If we didn't find the commit on any local branches, check remote branches
branches = await Container.git.getCommitBranches(commit.repoPath, commit.ref, { remotes: true });
const branches = await Container.git.getCommitBranches(commit.repoPath, commit.ref);
if (branches.length === 0) return undefined;
const remotes = branches.map(b => b.split('/', 1)[0]);
return this.findNode((n: any) => n.commit !== undefined && n.commit.ref === commit.ref, {
return this.findNode((n: any) => n.commit?.ref === commit.ref, {
allowPaging: true,
maxDepth: 8,
canTraverse: n => {
// Only search for commit nodes in the same repo within BranchNodes
if (n instanceof RepositoriesNode) return true;
if (n instanceof RemoteNode) {
return n.id.startsWith(repoNodeId) && remotes.includes(n.remote.name);
}
maxDepth: 5,
canTraverse: async n => {
if (n instanceof BranchesViewNode) return true;
if (n instanceof BranchNode) {
return n.id.startsWith(repoNodeId) && branches.includes(n.branch.name);
if (n instanceof BranchesRepositoryNode || n instanceof BranchOrTagFolderNode) {
return n.id.startsWith(repoNodeId);
}
if (n instanceof RepositoryNode || n instanceof RemotesNode || n instanceof BranchOrTagFolderNode) {
return n.id.startsWith(repoNodeId);
if (n instanceof BranchNode && branches.includes(n.branch.name)) {
await n.showMore({ until: commit.ref });
return true;
}
return false;
@ -343,12 +307,12 @@ export class BranchesView extends ViewBase
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing ${GitReference.toString(branch, { icon: false })} in the Repositories view...`,
title: `Revealing ${GitReference.toString(branch, { icon: false })} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findBranch(branch, token);
if (node === undefined) return node;
if (node == null) return undefined;
await this.ensureRevealNode(node, options);
@ -369,12 +333,12 @@ export class BranchesView extends ViewBase
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing ${GitReference.toString(commit, { icon: false })} in the Repositories view...`,
title: `Revealing ${GitReference.toString(commit, { icon: false })} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findCommit(commit, token);
if (node === undefined) return node;
if (node == null) return undefined;
await this.ensureRevealNode(node, options);

+ 74
- 66
src/views/commitsView.ts Zobrazit soubor

@ -21,15 +21,10 @@ import {
} from '../git/git';
import { GitUri } from '../git/gitUri';
import {
BranchesNode,
BranchNode,
BranchOrTagFolderNode,
CompareBranchNode,
ContextValues,
MessageNode,
RemoteNode,
RemotesNode,
RepositoriesNode,
RepositoryNode,
SubscribeableViewNode,
unknownGitUri,
@ -37,13 +32,20 @@ import {
} from './nodes';
import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
import { BranchTrackingStatusNode } from './nodes/branchTrackingStatusNode';
export class CommitsRepositoryNode extends SubscribeableViewNode<CommitsView> {
private children: (BranchNode | CompareBranchNode)[] | undefined;
protected splatted = true;
private children: (BranchNode | CompareBranchNode)[] | undefined;
constructor(uri: GitUri, view: CommitsView, parent: ViewNode, public readonly repo: Repository) {
constructor(uri: GitUri, view: CommitsView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
async getChildren(): Promise<ViewNode[]> {
@ -92,6 +94,14 @@ export class CommitsRepositoryNode extends SubscribeableViewNode {
return item;
}
async getSplattedChild() {
if (this.children == null) {
await this.getChildren();
}
return this.children?.[0];
}
@gate()
@debug()
async refresh(reset: boolean = false) {
@ -135,6 +145,7 @@ export class CommitsRepositoryNode extends SubscribeableViewNode {
}
export class CommitsViewNode extends ViewNode<CommitsView> {
protected splatted = true;
private children: CommitsRepositoryNode[] | undefined;
constructor(view: CommitsView) {
@ -142,19 +153,15 @@ export class CommitsViewNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
if (this.children != null) {
for (const child of this.children) {
child.dispose();
}
this.children = undefined;
}
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No commits could be found.')];
if (this.children == null) {
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No commits could be found.')];
this.children = repositories.map(
r => new CommitsRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r),
);
const splat = repositories.length === 1;
this.children = repositories.map(
r => new CommitsRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, splat),
);
}
if (this.children.length === 1) {
const [child] = this.children;
@ -169,6 +176,7 @@ export class CommitsViewNode extends ViewNode {
return child.getChildren();
}
return this.children;
}
@ -176,6 +184,25 @@ export class CommitsViewNode extends ViewNode {
const item = new TreeItem('Commits', TreeItemCollapsibleState.Expanded);
return item;
}
async getSplattedChild() {
if (this.children == null) {
await this.getChildren();
}
return this.children?.length === 1 ? this.children[0] : undefined;
}
@gate()
@debug()
refresh(reset: boolean = false) {
if (reset && this.children != null) {
for (const child of this.children) {
child.dispose();
}
this.children = undefined;
}
}
}
export class CommitsView extends ViewBase<CommitsViewNode, CommitsViewConfig> {
@ -235,59 +262,40 @@ export class CommitsView extends ViewBase {
async findCommit(commit: GitLogCommit | { repoPath: string; ref: string }, token?: CancellationToken) {
const repoNodeId = RepositoryNode.getId(commit.repoPath);
// Get all the branches the commit is on
let branches = await Container.git.getCommitBranches(commit.repoPath, commit.ref);
if (branches.length !== 0) {
return this.findNode((n: any) => n.commit !== undefined && n.commit.ref === commit.ref, {
allowPaging: true,
maxDepth: 6,
canTraverse: async n => {
// Only search for commit nodes in the same repo within BranchNodes
if (n instanceof RepositoriesNode) return true;
if (n instanceof BranchNode) {
if (n.id.startsWith(repoNodeId) && branches.includes(n.branch.name)) {
await n.showMore({ until: commit.ref });
return true;
}
}
if (
n instanceof RepositoryNode ||
n instanceof BranchesNode ||
n instanceof BranchOrTagFolderNode
) {
return n.id.startsWith(repoNodeId);
}
return false;
},
token: token,
});
}
// If we didn't find the commit on any local branches, check remote branches
branches = await Container.git.getCommitBranches(commit.repoPath, commit.ref, { remotes: true });
if (branches.length === 0) return undefined;
const branch = await Container.git.getBranch(commit.repoPath);
if (branch == null) return undefined;
const remotes = branches.map(b => b.split('/', 1)[0]);
// Get all the branches the commit is on
const branches = await Container.git.getCommitBranches(commit.repoPath, commit.ref);
if (branches.length === 0 || !branches.includes(branch.name)) return undefined;
return this.findNode((n: any) => n.commit !== undefined && n.commit.ref === commit.ref, {
return this.findNode((n: any) => n.commit?.ref === commit.ref, {
allowPaging: true,
maxDepth: 8,
canTraverse: n => {
// Only search for commit nodes in the same repo within BranchNodes
if (n instanceof RepositoriesNode) return true;
maxDepth: 2,
canTraverse: async n => {
if (n instanceof CommitsViewNode) {
let node: ViewNode | undefined = await n.getSplattedChild?.();
if (node instanceof CommitsRepositoryNode) {
node = await node.getSplattedChild?.();
if (node instanceof BranchNode) {
await node.showMore({ until: commit.ref });
}
}
if (n instanceof RemoteNode) {
return n.id.startsWith(repoNodeId) && remotes.includes(n.remote.name);
return true;
}
if (n instanceof BranchNode) {
return n.id.startsWith(repoNodeId) && branches.includes(n.branch.name);
if (n instanceof CommitsRepositoryNode) {
if (n.id.startsWith(repoNodeId)) {
const node = await n.getSplattedChild?.();
if (node instanceof BranchNode) {
await node.showMore({ until: commit.ref });
return true;
}
}
}
if (n instanceof RepositoryNode || n instanceof RemotesNode || n instanceof BranchOrTagFolderNode) {
if (n instanceof BranchTrackingStatusNode) {
return n.id.startsWith(repoNodeId);
}
@ -309,12 +317,12 @@ export class CommitsView extends ViewBase {
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing ${GitReference.toString(commit, { icon: false })} in the Repositories view...`,
title: `Revealing ${GitReference.toString(commit, { icon: false })} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findCommit(commit, token);
if (node === undefined) return node;
if (node == null) return undefined;
await this.ensureRevealNode(node, options);

+ 63
- 23
src/views/contributorsView.ts Zobrazit soubor

@ -4,11 +4,20 @@ import { configuration, ContributorsViewConfig, ViewFilesLayout } from '../confi
import { Container } from '../container';
import { Repository, RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { GitUri } from '../git/gitUri';
import { ContextValues, ContributorsNode, MessageNode, SubscribeableViewNode, unknownGitUri, ViewNode } from './nodes';
import {
ContextValues,
ContributorsNode,
MessageNode,
RepositoryNode,
SubscribeableViewNode,
unknownGitUri,
ViewNode,
} from './nodes';
import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
export class ContributorsRepositoryNode extends SubscribeableViewNode<ContributorsView> {
protected splatted = true;
private child: ContributorsNode | undefined;
constructor(
@ -16,32 +25,47 @@ export class ContributorsRepositoryNode extends SubscribeableViewNode
view: ContributorsView,
parent: ViewNode,
public readonly repo: Repository,
private readonly root: boolean,
splatted: boolean,
) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
async getChildren(): Promise<ViewNode[]> {
void this.ensureSubscription();
if (this.child == null) {
this.child = new ContributorsNode(this.uri, this.view, this, this.repo);
void this.ensureSubscription();
}
return this.child.getChildren();
}
getTreeItem(): TreeItem {
void this.ensureSubscription();
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
void this.ensureSubscription();
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
@ -71,14 +95,15 @@ export class ContributorsRepositoryNode extends SubscribeableViewNode
if (e.changed(RepositoryChange.Config) || e.changed(RepositoryChange.Heads)) {
void this.triggerChange(true);
if (this.root) {
void this.parent?.triggerChange(true);
}
// if (this.root) {
// void this.parent?.triggerChange(true);
// }
}
}
}
export class ContributorsViewNode extends ViewNode<ContributorsView> {
protected splatted = true;
private children: ContributorsRepositoryNode[] | undefined;
constructor(view: ContributorsView) {
@ -86,22 +111,17 @@ export class ContributorsViewNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
if (this.children != null) {
for (const child of this.children) {
child.dispose?.();
}
this.children = undefined;
if (this.children == null) {
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No contributors could be found.')];
const splat = repositories.length === 1;
this.children = repositories.map(
r => new ContributorsRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, splat),
);
}
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No contributors could be found.')];
const root = repositories.length === 1;
this.children = repositories.map(
r => new ContributorsRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, root),
);
if (root) {
if (this.children.length === 1) {
const [child] = this.children;
const contributors = await child.repo.getContributors();
@ -109,6 +129,7 @@ export class ContributorsViewNode extends ViewNode {
return child.getChildren();
}
return this.children;
}
@ -116,6 +137,25 @@ export class ContributorsViewNode extends ViewNode {
const item = new TreeItem('Contributors', TreeItemCollapsibleState.Expanded);
return item;
}
async getSplattedChild() {
if (this.children == null) {
await this.getChildren();
}
return this.children?.length === 1 ? this.children[0] : undefined;
}
@gate()
@debug()
refresh(reset: boolean = false) {
if (reset && this.children != null) {
for (const child of this.children) {
child.dispose();
}
this.children = undefined;
}
}
}
export class ContributorsView extends ViewBase<ContributorsViewNode, ContributorsViewConfig> {

+ 6
- 4
src/views/nodes/branchNode.ts Zobrazit soubor

@ -96,7 +96,7 @@ export class BranchNode
}
async getChildren(): Promise<ViewNode[]> {
if (this._children === undefined) {
if (this._children == null) {
const children = [];
if (this.options.showTracking && this.branch.tracking) {
const status = {
@ -120,7 +120,7 @@ export class BranchNode
}
const log = await this.getLog();
if (log === undefined) return [new MessageNode(this.view, this, 'No commits could be found.')];
if (log == null) return [new MessageNode(this.view, this, 'No commits could be found.')];
const getBranchAndTagTips = await Container.git.getBranchesAndTagsTipsFn(
this.uri.repoPath,
@ -267,7 +267,7 @@ export class BranchNode
private _log: GitLog | undefined;
private async getLog() {
if (this._log === undefined) {
if (this._log == null) {
this._log = await Container.git.getLog(this.uri.repoPath!, {
limit: this.limit ?? this.view.config.defaultItemLimit,
ref: this.ref.ref,
@ -284,13 +284,15 @@ export class BranchNode
limit: number | undefined = this.view.getNodeLastKnownLimit(this);
async showMore(limit?: number | { until?: any }) {
let log = await this.getLog();
if (log === undefined || !log.hasMore) return;
if (log == null || !log.hasMore) return;
log = await log.more?.(limit ?? this.view.config.pageItemLimit);
if (this._log === log) return;
this._log = log;
this.limit = log?.count;
this._children = undefined;
void this.triggerChange(false);
}
}

+ 6
- 5
src/views/nodes/branchTrackingStatusNode.ts Zobrazit soubor

@ -62,16 +62,16 @@ export class BranchTrackingStatusNode extends ViewNode implement
async getChildren(): Promise<ViewNode[]> {
const log = await this.getLog();
if (log === undefined) return [];
if (log == null) return [];
let children;
if (this.ahead) {
// Since the last commit when we are looking 'ahead' can have no previous (because of the range given) -- look it up
const commits = [...log.commits.values()];
const commit = commits[commits.length - 1];
if (commit.previousSha === undefined) {
if (commit.previousSha == null) {
const previousLog = await Container.git.getLog(this.uri.repoPath!, { limit: 2, ref: commit.sha });
if (previousLog !== undefined) {
if (previousLog != null) {
commits[commits.length - 1] = Iterables.first(previousLog.commits.values());
}
}
@ -154,7 +154,7 @@ export class BranchTrackingStatusNode extends ViewNode implement
private _log: GitLog | undefined;
private async getLog() {
if (this._log === undefined) {
if (this._log == null) {
const range = this.ahead
? GitRevision.createRange(this.status.upstream, this.status.ref)
: GitRevision.createRange(this.status.ref, this.status.upstream);
@ -175,13 +175,14 @@ export class BranchTrackingStatusNode extends ViewNode implement
limit: number | undefined = this.view.getNodeLastKnownLimit(this);
async showMore(limit?: number | { until?: any }) {
let log = await this.getLog();
if (log === undefined || !log.hasMore) return;
if (log == null || !log.hasMore) return;
log = await log.more?.(limit ?? this.view.config.pageItemLimit);
if (this._log === log) return;
this._log = log;
this.limit = log?.count;
void this.triggerChange(false);
}
}

+ 2
- 1
src/views/nodes/branchesNode.ts Zobrazit soubor

@ -35,7 +35,7 @@ export class BranchesNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
if (this._children === undefined) {
if (this._children == null) {
const branches = await this.repo.getBranches({
// only show local branches
filter: b => !b.remote,
@ -71,6 +71,7 @@ export class BranchesNode extends ViewNode {
);
this._children = root.getChildren();
}
return this._children;
}

+ 4
- 3
src/views/nodes/contributorNode.ts Zobrazit soubor

@ -40,7 +40,7 @@ export class ContributorNode extends ViewNode
async getChildren(): Promise<ViewNode[]> {
const log = await this.getLog();
if (log === undefined) return [new MessageNode(this.view, this, 'No commits could be found.')];
if (log == null) return [new MessageNode(this.view, this, 'No commits could be found.')];
const getBranchAndTagTips = await Container.git.getBranchesAndTagsTipsFn(this.uri.repoPath);
const children = [
@ -96,7 +96,7 @@ export class ContributorNode extends ViewNode
private _log: GitLog | undefined;
private async getLog() {
if (this._log === undefined) {
if (this._log == null) {
this._log = await Container.git.getLog(this.uri.repoPath!, {
limit: this.limit ?? this.view.config.defaultItemLimit,
authors: [`^${this.contributor.name} <${this.contributor.email}>$`],
@ -113,13 +113,14 @@ export class ContributorNode extends ViewNode
limit: number | undefined = this.view.getNodeLastKnownLimit(this);
async showMore(limit?: number | { until?: any }) {
let log = await this.getLog();
if (log === undefined || !log.hasMore) return;
if (log == null || !log.hasMore) return;
log = await log.more?.(limit ?? this.view.config.pageItemLimit);
if (this._log === log) return;
this._log = log;
this.limit = log?.count;
void this.triggerChange(false);
}
}

+ 18
- 7
src/views/nodes/contributorsNode.ts Zobrazit soubor

@ -8,7 +8,7 @@ import { GitContributor, Repository } from '../../git/git';
import { GitUri } from '../../git/gitUri';
import { RepositoryNode } from './repositoryNode';
import { RepositoriesView } from '../repositoriesView';
import { debug, timeout } from '../../system';
import { debug, gate, timeout } from '../../system';
import { ContextValues, ViewNode } from './viewNode';
export class ContributorsNode extends ViewNode<ContributorsView | RepositoriesView> {
@ -17,6 +17,8 @@ export class ContributorsNode extends ViewNode
return `${RepositoryNode.getId(repoPath)}${this.key}`;
}
private _children: ViewNode[] | undefined;
constructor(
uri: GitUri,
view: ContributorsView | RepositoriesView,
@ -31,14 +33,17 @@ export class ContributorsNode extends ViewNode
}
async getChildren(): Promise<ViewNode[]> {
const contributors = await this.repo.getContributors();
if (contributors.length === 0) return [new MessageNode(this.view, this, 'No contributors could be found.')];
if (this._children == null) {
const contributors = await this.repo.getContributors();
if (contributors.length === 0) return [new MessageNode(this.view, this, 'No contributors could be found.')];
GitContributor.sort(contributors);
const presenceMap = await this.maybeGetPresenceMap(contributors).catch(() => undefined);
GitContributor.sort(contributors);
const presenceMap = await this.maybeGetPresenceMap(contributors).catch(() => undefined);
this._children = contributors.map(c => new ContributorNode(this.uri, this.view, this, c, presenceMap));
}
const children = contributors.map(c => new ContributorNode(this.uri, this.view, this, c, presenceMap));
return children;
return this._children;
}
getTreeItem(): TreeItem {
@ -49,6 +54,12 @@ export class ContributorsNode extends ViewNode
return item;
}
@gate()
@debug()
refresh() {
this._children = undefined;
}
@debug({ args: false })
@timeout(250)
private async maybeGetPresenceMap(contributors: GitContributor[]) {

+ 1
- 0
src/views/nodes/fileHistoryNode.ts Zobrazit soubor

@ -183,6 +183,7 @@ export class FileHistoryNode extends SubscribeableViewNode implements PageableVi
this._log = log;
this.limit = log?.count;
// Needs to force if splatted, since the parent node will cancel the refresh (since it thinks nothing changed)
void this.triggerChange(false, this.splatted);
}

+ 1
- 0
src/views/nodes/lineHistoryNode.ts Zobrazit soubor

@ -312,6 +312,7 @@ export class LineHistoryNode extends SubscribeableViewNode implements PageableVi
this._log = log;
this.limit = log?.count;
// Needs to force if splatted, since the parent node will cancel the refresh (since it thinks nothing changed)
void this.triggerChange(false, this.splatted);
}

+ 17
- 4
src/views/nodes/remotesNode.ts Zobrazit soubor

@ -9,6 +9,7 @@ import { RemotesView } from '../remotesView';
import { RepositoriesView } from '../repositoriesView';
import { RepositoryNode } from './repositoryNode';
import { ContextValues, ViewNode } from './viewNode';
import { debug, gate } from '../../system';
export class RemotesNode extends ViewNode<RemotesView | RepositoriesView> {
static key = ':remotes';
@ -16,6 +17,8 @@ export class RemotesNode extends ViewNode {
return `${RepositoryNode.getId(repoPath)}${this.key}`;
}
private _children: ViewNode[] | undefined;
constructor(uri: GitUri, view: RemotesView | RepositoriesView, parent: ViewNode, public readonly repo: Repository) {
super(uri, view, parent);
}
@ -25,12 +28,16 @@ export class RemotesNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
const remotes = await this.repo.getRemotes({ sort: true });
if (remotes === undefined || remotes.length === 0) {
return [new MessageNode(this.view, this, 'No remotes could be found')];
if (this._children == null) {
const remotes = await this.repo.getRemotes({ sort: true });
if (remotes == null || remotes.length === 0) {
return [new MessageNode(this.view, this, 'No remotes could be found')];
}
this._children = remotes.map(r => new RemoteNode(this.uri, this.view, this, r, this.repo));
}
return remotes.map(r => new RemoteNode(this.uri, this.view, this, r, this.repo));
return this._children;
}
getTreeItem(): TreeItem {
@ -45,4 +52,10 @@ export class RemotesNode extends ViewNode {
return item;
}
@gate()
@debug()
refresh() {
this._children = undefined;
}
}

+ 16
- 4
src/views/nodes/stashesNode.ts Zobrazit soubor

@ -8,7 +8,7 @@ import { RepositoriesView } from '../repositoriesView';
import { RepositoryNode } from './repositoryNode';
import { StashesView } from '../stashesView';
import { StashNode } from './stashNode';
import { Iterables } from '../../system';
import { debug, gate, Iterables } from '../../system';
import { ContextValues, ViewNode } from './viewNode';
export class StashesNode extends ViewNode<StashesView | RepositoriesView> {
@ -17,6 +17,8 @@ export class StashesNode extends ViewNode {
return `${RepositoryNode.getId(repoPath)}${this.key}`;
}
private _children: ViewNode[] | undefined;
constructor(uri: GitUri, view: StashesView | RepositoriesView, parent: ViewNode, public readonly repo: Repository) {
super(uri, view, parent);
}
@ -26,10 +28,14 @@ export class StashesNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
const stash = await this.repo.getStash();
if (stash === undefined) return [new MessageNode(this.view, this, 'No stashes could be found.')];
if (this._children == null) {
const stash = await this.repo.getStash();
if (stash === undefined) return [new MessageNode(this.view, this, 'No stashes could be found.')];
this._children = [...Iterables.map(stash.commits.values(), c => new StashNode(this.view, this, c))];
}
return [...Iterables.map(stash.commits.values(), c => new StashNode(this.view, this, c))];
return this._children;
}
getTreeItem(): TreeItem {
@ -44,4 +50,10 @@ export class StashesNode extends ViewNode {
return item;
}
@gate()
@debug()
refresh() {
this._children = undefined;
}
}

+ 4
- 3
src/views/nodes/tagNode.ts Zobrazit soubor

@ -43,7 +43,7 @@ export class TagNode extends ViewRefNode
async getChildren(): Promise<ViewNode[]> {
const log = await this.getLog();
if (log === undefined) return [new MessageNode(this.view, this, 'No commits could be found.')];
if (log == null) return [new MessageNode(this.view, this, 'No commits could be found.')];
const getBranchAndTagTips = await Container.git.getBranchesAndTagsTipsFn(this.uri.repoPath, this.tag.name);
const children = [
@ -94,7 +94,7 @@ export class TagNode extends ViewRefNode
private _log: GitLog | undefined;
private async getLog() {
if (this._log === undefined) {
if (this._log == null) {
this._log = await Container.git.getLog(this.uri.repoPath!, {
limit: this.limit ?? this.view.config.defaultItemLimit,
ref: this.tag.name,
@ -111,13 +111,14 @@ export class TagNode extends ViewRefNode
limit: number | undefined = this.view.getNodeLastKnownLimit(this);
async showMore(limit?: number | { until?: any }) {
let log = await this.getLog();
if (log === undefined || !log.hasMore) return;
if (log == null || !log.hasMore) return;
log = await log.more?.(limit ?? this.view.config.pageItemLimit);
if (this._log === log) return;
this._log = log;
this.limit = log?.count;
void this.triggerChange(false);
}
}

+ 36
- 23
src/views/nodes/tagsNode.ts Zobrazit soubor

@ -7,7 +7,7 @@ import { Repository } from '../../git/git';
import { GitUri } from '../../git/gitUri';
import { RepositoriesView } from '../repositoriesView';
import { RepositoryNode } from './repositoryNode';
import { Arrays } from '../../system';
import { Arrays, debug, gate } from '../../system';
import { TagNode } from './tagNode';
import { TagsView } from '../tagsView';
import { ContextValues, ViewNode } from './viewNode';
@ -18,6 +18,8 @@ export class TagsNode extends ViewNode {
return `${RepositoryNode.getId(repoPath)}${this.key}`;
}
private _children: ViewNode[] | undefined;
constructor(uri: GitUri, view: TagsView | RepositoriesView, parent: ViewNode, public readonly repo: Repository) {
super(uri, view, parent);
}
@ -27,31 +29,36 @@ export class TagsNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
const tags = await this.repo.getTags({ sort: true });
if (tags.length === 0) return [new MessageNode(this.view, this, 'No tags could be found.')];
if (this._children == null) {
const tags = await this.repo.getTags({ sort: true });
if (tags.length === 0) return [new MessageNode(this.view, this, 'No tags could be found.')];
const tagNodes = tags.map(
t => new TagNode(GitUri.fromRepoPath(this.uri.repoPath!, t.ref), this.view, this, t),
);
if (this.view.config.branches.layout === ViewBranchesLayout.List) return tagNodes;
const tagNodes = tags.map(t => new TagNode(GitUri.fromRepoPath(this.uri.repoPath!, t.ref), this.view, this, t));
if (this.view.config.branches.layout === ViewBranchesLayout.List) return tagNodes;
const hierarchy = Arrays.makeHierarchical(
tagNodes,
n => n.tag.name.split('/'),
(...paths) => paths.join('/'),
this.view.config.files.compact,
);
const hierarchy = Arrays.makeHierarchical(
tagNodes,
n => n.tag.name.split('/'),
(...paths) => paths.join('/'),
this.view.config.files.compact,
);
const root = new BranchOrTagFolderNode(
this.view,
this,
'tag',
this.repo.path,
'',
undefined,
hierarchy,
'tags',
);
this._children = root.getChildren();
}
const root = new BranchOrTagFolderNode(
this.view,
this,
'tag',
this.repo.path,
'',
undefined,
hierarchy,
'tags',
);
const children = root.getChildren();
return children;
return this._children;
}
getTreeItem(): TreeItem {
@ -61,4 +68,10 @@ export class TagsNode extends ViewNode {
item.iconPath = new ThemeIcon('tag');
return item;
}
@gate()
@debug()
refresh() {
this._children = undefined;
}
}

+ 4
- 6
src/views/nodes/viewNode.ts Zobrazit soubor

@ -84,12 +84,8 @@ export abstract class ViewNode {
abstract getChildren(): ViewNode[] | Promise<ViewNode[]>;
getParent(): ViewNode | undefined {
// If this node has been splatted (e.g. not shown itself, but its children are), then return its grandparent
if (this.splatted) {
return this.parent?.getParent() ?? this.parent;
}
return this.parent;
// If this node's parent has been splatted (e.g. not shown itself, but its children are), then return its grandparent
return this.parent?.splatted ? this.parent?.getParent() : this.parent;
}
abstract getTreeItem(): TreeItem | Promise<TreeItem>;
@ -110,6 +106,8 @@ export abstract class ViewNode {
return this.view.refreshNode(this, reset, force);
}
getSplattedChild?(): Promise<ViewNode | undefined>;
}
export abstract class ViewRefNode<

+ 175
- 43
src/views/remotesView.ts Zobrazit soubor

@ -13,20 +13,22 @@ import { Container } from '../container';
import {
GitBranch,
GitBranchReference,
GitLogCommit,
GitReference,
GitRemote,
GitRevisionReference,
Repository,
RepositoryChange,
RepositoryChangeEvent,
} from '../git/git';
import { GitUri } from '../git/gitUri';
import {
BranchesNode,
BranchNode,
BranchOrTagFolderNode,
ContextValues,
MessageNode,
RemoteNode,
RemotesNode,
RepositoriesNode,
RepositoryNode,
SubscribeableViewNode,
unknownGitUri,
@ -36,39 +38,50 @@ import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
export class RemotesRepositoryNode extends SubscribeableViewNode<RemotesView> {
protected splatted = true;
private child: RemotesNode | undefined;
constructor(
uri: GitUri,
view: RemotesView,
parent: ViewNode,
public readonly repo: Repository,
private readonly root: boolean,
) {
constructor(uri: GitUri, view: RemotesView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
async getChildren(): Promise<ViewNode[]> {
void this.ensureSubscription();
if (this.child == null) {
this.child = new RemotesNode(this.uri, this.view, this, this.repo);
void this.ensureSubscription();
}
return this.child.getChildren();
}
getTreeItem(): TreeItem {
this.splatted = false;
void this.ensureSubscription();
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
void this.ensureSubscription();
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
@ -98,14 +111,15 @@ export class RemotesRepositoryNode extends SubscribeableViewNode {
if (e.changed(RepositoryChange.Config) || e.changed(RepositoryChange.Remotes)) {
void this.triggerChange(true);
if (this.root) {
void this.parent?.triggerChange(true);
}
// if (this.root) {
// void this.parent?.triggerChange(true);
// }
}
}
}
export class RemotesViewNode extends ViewNode<RemotesView> {
protected splatted = true;
private children: RemotesRepositoryNode[] | undefined;
constructor(view: RemotesView) {
@ -113,22 +127,17 @@ export class RemotesViewNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
if (this.children != null) {
for (const child of this.children) {
child.dispose?.();
}
this.children = undefined;
if (this.children == null) {
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No remotes could be found.')];
const splat = repositories.length === 1;
this.children = repositories.map(
r => new RemotesRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, splat),
);
}
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No remotes could be found.')];
const root = repositories.length === 1;
this.children = repositories.map(
r => new RemotesRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, root),
);
if (root) {
if (this.children.length === 1) {
const [child] = this.children;
const remotes = await child.repo.getRemotes();
@ -136,6 +145,7 @@ export class RemotesViewNode extends ViewNode {
return child.getChildren();
}
return this.children;
}
@ -143,6 +153,25 @@ export class RemotesViewNode extends ViewNode {
const item = new TreeItem('Remotes', TreeItemCollapsibleState.Expanded);
return item;
}
async getSplattedChild() {
if (this.children == null) {
await this.getChildren();
}
return this.children?.length === 1 ? this.children[0] : undefined;
}
@gate()
@debug()
refresh(reset: boolean = false) {
if (reset && this.children != null) {
for (const child of this.children) {
child.dispose();
}
this.children = undefined;
}
}
}
export class RemotesView extends ViewBase<RemotesViewNode, RemotesViewConfig> {
@ -215,25 +244,75 @@ export class RemotesView extends ViewBase {
const repoNodeId = RepositoryNode.getId(branch.repoPath);
return this.findNode((n: any) => n.branch !== undefined && n.branch.ref === branch.ref, {
return this.findNode((n: any) => n.branch?.ref === branch.ref, {
allowPaging: true,
maxDepth: 6,
maxDepth: 5,
canTraverse: n => {
// Only search for branch nodes in the same repo within BranchesNode
if (n instanceof RepositoriesNode) return true;
if (n instanceof RemotesViewNode) return true;
if (n instanceof RemotesRepositoryNode || n instanceof BranchOrTagFolderNode) {
return n.id.startsWith(repoNodeId);
}
if (n instanceof RemoteNode) {
if (!n.id.startsWith(repoNodeId)) return false;
return branch.remote && n.remote.name === GitBranch.getRemote(branch.name); //branch.getRemoteName();
return n.remote.name === GitBranch.getRemote(branch.name);
}
return false;
},
token: token,
});
}
async findCommit(commit: GitLogCommit | { repoPath: string; ref: string }, token?: CancellationToken) {
const repoNodeId = RepositoryNode.getId(commit.repoPath);
// Get all the remote branches the commit is on
const branches = await Container.git.getCommitBranches(commit.repoPath, commit.ref, { remotes: true });
if (branches.length === 0) return undefined;
const remotes = branches.map(b => b.split('/', 1)[0]);
return this.findNode((n: any) => n.commit !== undefined && n.commit.ref === commit.ref, {
allowPaging: true,
maxDepth: 6,
canTraverse: n => {
if (n instanceof RemotesViewNode) return true;
if (n instanceof RemotesRepositoryNode || n instanceof BranchOrTagFolderNode) {
return n.id.startsWith(repoNodeId);
}
if (n instanceof RemoteNode) {
return n.id.startsWith(repoNodeId) && remotes.includes(n.remote.name);
}
if (n instanceof BranchNode) {
return n.id.startsWith(repoNodeId) && branches.includes(n.branch.name);
}
if (n instanceof RepositoryNode || n instanceof RemotesNode || n instanceof BranchOrTagFolderNode) {
return n.id.startsWith(repoNodeId);
}
if (
n instanceof RepositoryNode ||
n instanceof BranchesNode ||
n instanceof RemotesNode ||
n instanceof BranchOrTagFolderNode
) {
return false;
},
token: token,
});
}
findRemote(remote: GitRemote, token?: CancellationToken) {
const repoNodeId = RepositoryNode.getId(remote.repoPath);
return this.findNode((n: any) => n.remote?.name === remote.name, {
allowPaging: true,
maxDepth: 2,
canTraverse: n => {
if (n instanceof RemotesViewNode) return true;
if (n instanceof RemotesRepositoryNode) {
return n.id.startsWith(repoNodeId);
}
@ -255,12 +334,12 @@ export class RemotesView extends ViewBase {
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing ${GitReference.toString(branch, { icon: false })} in the Repositories view...`,
title: `Revealing ${GitReference.toString(branch, { icon: false })} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findBranch(branch, token);
if (node === undefined) return node;
if (node == null) return undefined;
await this.ensureRevealNode(node, options);
@ -268,6 +347,59 @@ export class RemotesView extends ViewBase {
},
);
}
@gate(() => '')
async revealCommit(
commit: GitRevisionReference,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing ${GitReference.toString(commit, { icon: false })} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findCommit(commit, token);
if (node == null) return undefined;
await this.ensureRevealNode(node, options);
return node;
},
);
}
@gate(() => '')
revealRemote(
remote: GitRemote,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing remote ${remote.name} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findRemote(remote, token);
if (node == null) return undefined;
await this.ensureRevealNode(node, options);
return node;
},
);
}
private setLayout(layout: ViewBranchesLayout) {
return configuration.updateEffective('views', this.configKey, 'branches', 'layout', layout);
}

+ 3
- 3
src/views/repositoriesView.ts Zobrazit soubor

@ -300,7 +300,7 @@ export class RepositoriesView extends ViewBase
},
async (progress, token) => {
const node = await this.findBranch(branch, token);
if (node === undefined) return node;
if (node == null) return undefined;
await this.ensureRevealNode(node, options);
@ -358,7 +358,7 @@ export class RepositoriesView extends ViewBase
},
async (progress, token) => {
const node = await this.findCommit(commit, token);
if (node === undefined) return node;
if (node == null) return undefined;
await this.ensureRevealNode(node, options);
@ -474,7 +474,7 @@ export class RepositoriesView extends ViewBase
},
async (progress, token) => {
const node = await this.findTag(tag, token);
if (node === undefined) return node;
if (node == null) return undefined;
await this.ensureRevealNode(node, options);

+ 119
- 31
src/views/stashesView.ts Zobrazit soubor

@ -1,47 +1,75 @@
'use strict';
import { commands, ConfigurationChangeEvent, TreeItem, TreeItemCollapsibleState } from 'vscode';
import {
CancellationToken,
commands,
ConfigurationChangeEvent,
ProgressLocation,
TreeItem,
TreeItemCollapsibleState,
window,
} from 'vscode';
import { configuration, StashesViewConfig, ViewFilesLayout } from '../configuration';
import { Container } from '../container';
import { Repository, RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { GitReference, GitStashReference, Repository, RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { GitUri } from '../git/gitUri';
import { ContextValues, MessageNode, StashesNode, SubscribeableViewNode, unknownGitUri, ViewNode } from './nodes';
import {
ContextValues,
MessageNode,
RepositoryNode,
StashesNode,
StashNode,
SubscribeableViewNode,
unknownGitUri,
ViewNode,
} from './nodes';
import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
export class StashesRepositoryNode extends SubscribeableViewNode<StashesView> {
protected splatted = true;
private child: StashesNode | undefined;
constructor(
uri: GitUri,
view: StashesView,
parent: ViewNode,
public readonly repo: Repository,
private readonly root: boolean,
) {
constructor(uri: GitUri, view: StashesView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
async getChildren(): Promise<ViewNode[]> {
void this.ensureSubscription();
if (this.child == null) {
this.child = new StashesNode(this.uri, this.view, this, this.repo);
void this.ensureSubscription();
}
return this.child.getChildren();
}
getTreeItem(): TreeItem {
this.splatted = false;
void this.ensureSubscription();
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
void this.ensureSubscription();
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
@ -71,14 +99,15 @@ export class StashesRepositoryNode extends SubscribeableViewNode {
if (e.changed(RepositoryChange.Config) || e.changed(RepositoryChange.Heads)) {
void this.triggerChange(true);
if (this.root) {
void this.parent?.triggerChange(true);
}
// if (this.root) {
// void this.parent?.triggerChange(true);
// }
}
}
}
export class StashesViewNode extends ViewNode<StashesView> {
protected splatted = true;
private children: StashesRepositoryNode[] | undefined;
constructor(view: StashesView) {
@ -86,22 +115,17 @@ export class StashesViewNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
if (this.children != null) {
for (const child of this.children) {
child.dispose?.();
}
this.children = undefined;
}
if (this.children == null) {
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No stashes could be found.')];
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No stashes could be found.')];
const root = repositories.length === 1;
this.children = repositories.map(
r => new StashesRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, root),
);
const splat = repositories.length === 1;
this.children = repositories.map(
r => new StashesRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, splat),
);
}
if (root) {
if (this.children.length === 1) {
const [child] = this.children;
const stash = await child.repo.getStash();
@ -109,6 +133,7 @@ export class StashesViewNode extends ViewNode {
return child.getChildren();
}
return this.children;
}
@ -116,6 +141,25 @@ export class StashesViewNode extends ViewNode {
const item = new TreeItem('Stashes', TreeItemCollapsibleState.Expanded);
return item;
}
async getSplattedChild() {
if (this.children == null) {
await this.getChildren();
}
return this.children?.length === 1 ? this.children[0] : undefined;
}
@gate()
@debug()
refresh(reset: boolean = false) {
if (reset && this.children != null) {
for (const child of this.children) {
child.dispose();
}
this.children = undefined;
}
}
}
export class StashesView extends ViewBase<StashesViewNode, StashesViewConfig> {
@ -172,6 +216,50 @@ export class StashesView extends ViewBase {
return true;
}
findStash(stash: GitStashReference, token?: CancellationToken) {
const repoNodeId = RepositoryNode.getId(stash.repoPath);
return this.findNode(StashNode.getId(stash.repoPath, stash.ref), {
maxDepth: 2,
canTraverse: n => {
if (n instanceof StashesViewNode) return true;
if (n instanceof StashesRepositoryNode) {
return n.id.startsWith(repoNodeId);
}
return false;
},
token: token,
});
}
@gate(() => '')
async revealStash(
stash: GitStashReference,
options?: {
select?: boolean;
focus?: boolean;
expand?: boolean | number;
},
) {
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing ${GitReference.toString(stash, { icon: false })} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findStash(stash, token);
if (node == null) return undefined;
await this.ensureRevealNode(node, options);
return node;
},
);
}
private setFilesLayout(layout: ViewFilesLayout) {
return configuration.updateEffective('views', this.configKey, 'files', 'layout', layout);
}

+ 62
- 37
src/views/tagsView.ts Zobrazit soubor

@ -13,10 +13,8 @@ import { Container } from '../container';
import { GitReference, GitTagReference, Repository, RepositoryChange, RepositoryChangeEvent } from '../git/git';
import { GitUri } from '../git/gitUri';
import {
BranchOrTagFolderNode,
ContextValues,
MessageNode,
RepositoriesNode,
RepositoryNode,
SubscribeableViewNode,
TagsNode,
@ -25,41 +23,53 @@ import {
} from './nodes';
import { debug, gate } from '../system';
import { ViewBase } from './viewBase';
import { BranchOrTagFolderNode } from './nodes/branchOrTagFolderNode';
export class TagsRepositoryNode extends SubscribeableViewNode<TagsView> {
protected splatted = true;
private child: TagsNode | undefined;
constructor(
uri: GitUri,
view: TagsView,
parent: ViewNode,
public readonly repo: Repository,
private readonly root: boolean,
) {
constructor(uri: GitUri, view: TagsView, parent: ViewNode, public readonly repo: Repository, splatted: boolean) {
super(uri, view, parent);
this.splatted = splatted;
}
get id(): string {
return RepositoryNode.getId(this.repo.path);
}
async getChildren(): Promise<ViewNode[]> {
void this.ensureSubscription();
if (this.child == null) {
this.child = new TagsNode(this.uri, this.view, this, this.repo);
void this.ensureSubscription();
}
return this.child.getChildren();
}
getTreeItem(): TreeItem {
this.splatted = false;
void this.ensureSubscription();
const item = new TreeItem(
this.repo.formattedName ?? this.uri.repoPath ?? '',
TreeItemCollapsibleState.Expanded,
);
item.contextValue = ContextValues.RepositoryFolder;
void this.ensureSubscription();
return item;
}
async getSplattedChild() {
if (this.child == null) {
await this.getChildren();
}
return this.child;
}
@gate()
@debug()
async refresh(reset: boolean = false) {
@ -89,14 +99,15 @@ export class TagsRepositoryNode extends SubscribeableViewNode {
if (e.changed(RepositoryChange.Config) || e.changed(RepositoryChange.Tags)) {
void this.triggerChange(true);
if (this.root) {
void this.parent?.triggerChange(true);
}
// if (this.root) {
// void this.parent?.triggerChange(true);
// }
}
}
}
export class TagsViewNode extends ViewNode<TagsView> {
protected splatted = true;
private children: TagsRepositoryNode[] | undefined;
constructor(view: TagsView) {
@ -104,22 +115,17 @@ export class TagsViewNode extends ViewNode {
}
async getChildren(): Promise<ViewNode[]> {
if (this.children != null) {
for (const child of this.children) {
child.dispose?.();
}
this.children = undefined;
if (this.children == null) {
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No tags could be found.')];
const splat = repositories.length === 1;
this.children = repositories.map(
r => new TagsRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, splat),
);
}
const repositories = await Container.git.getOrderedRepositories();
if (repositories.length === 0) return [new MessageNode(this.view, this, 'No tags could be found.')];
const root = repositories.length === 1;
this.children = repositories.map(
r => new TagsRepositoryNode(GitUri.fromRepoPath(r.path), this.view, this, r, root),
);
if (root) {
if (this.children.length === 1) {
const [child] = this.children;
const tags = await child.repo.getTags();
@ -127,6 +133,7 @@ export class TagsViewNode extends ViewNode {
return child.getChildren();
}
return this.children;
}
@ -134,6 +141,25 @@ export class TagsViewNode extends ViewNode {
const item = new TreeItem('Tags', TreeItemCollapsibleState.Expanded);
return item;
}
async getSplattedChild() {
if (this.children == null) {
await this.getChildren();
}
return this.children?.length === 1 ? this.children[0] : undefined;
}
@gate()
@debug()
refresh(reset: boolean = false) {
if (reset && this.children != null) {
for (const child of this.children) {
child.dispose();
}
this.children = undefined;
}
}
}
export class TagsView extends ViewBase<TagsViewNode, TagsViewConfig> {
@ -204,14 +230,13 @@ export class TagsView extends ViewBase {
findTag(tag: GitTagReference, token?: CancellationToken) {
const repoNodeId = RepositoryNode.getId(tag.repoPath);
return this.findNode((n: any) => n.tag !== undefined && n.tag.ref === tag.ref, {
return this.findNode((n: any) => n.tag?.ref === tag.ref, {
allowPaging: true,
maxDepth: 5,
maxDepth: 2,
canTraverse: n => {
// Only search for tag nodes in the same repo within TagsNode
if (n instanceof RepositoriesNode) return true;
if (n instanceof TagsViewNode) return true;
if (n instanceof RepositoryNode || n instanceof TagsNode || n instanceof BranchOrTagFolderNode) {
if (n instanceof TagsRepositoryNode || n instanceof BranchOrTagFolderNode) {
return n.id.startsWith(repoNodeId);
}
@ -233,12 +258,12 @@ export class TagsView extends ViewBase {
return window.withProgress(
{
location: ProgressLocation.Notification,
title: `Revealing ${GitReference.toString(tag, { icon: false })} in the Repositories view...`,
title: `Revealing ${GitReference.toString(tag, { icon: false })} in the side bar...`,
cancellable: true,
},
async (progress, token) => {
const node = await this.findTag(tag, token);
if (node === undefined) return node;
if (node == null) return undefined;
await this.ensureRevealNode(node, options);

+ 10
- 3
src/views/viewBase.ts Zobrazit soubor

@ -395,7 +395,11 @@ export abstract class ViewBase<
children = await node.getChildren();
if (children.length === 0) continue;
if (PageableViewNode.is(node)) {
while (node != null && !PageableViewNode.is(node)) {
node = await node.getSplattedChild?.();
}
if (node != null && PageableViewNode.is(node)) {
let child = children.find(predicate);
if (child != null) return child;
@ -442,11 +446,14 @@ export abstract class ViewBase<
const nodes: ViewNode[] = [];
let parent: ViewNode | undefined = node;
while (parent !== undefined) {
while (parent != null) {
nodes.push(parent);
parent = parent.getParent();
}
nodes.pop();
if (nodes.length > 1) {
nodes.pop();
}
for (const n of nodes.reverse()) {
try {

+ 2
- 2
src/webviews/apps/settings/partials/code-lens.html Zobrazit soubor

@ -73,7 +73,7 @@
opens changes with the previous revision
</option>
<option value="gitlens.revealCommitInView">
reveals the commit in the Repositories view
reveals the commit in the side bar
</option>
<option value="gitlens.showCommitsInView">
shows the commit in the Search Commits view
@ -138,7 +138,7 @@
opens changes with the previous revision
</option>
<option value="gitlens.revealCommitInView">
reveals the commit in the Repositories view
reveals the commit in the side bar
</option>
<option value="gitlens.showCommitsInView">
shows the commits within the range in the Search Commits view

+ 1
- 1
src/webviews/apps/settings/partials/status-bar.html Zobrazit soubor

@ -64,7 +64,7 @@
opens line changes with the working file
</option>
<option value="gitlens.revealCommitInView">
reveals the commit in the Repositories view
reveals the commit in the side bar
</option>
<option value="gitlens.showCommitsInView">
shows the commit in the Search Commits view

Načítá se…
Zrušit
Uložit