From 261b216ea863d76cb695320d067165c7c4d3d7a9 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 18 Dec 2017 18:16:20 -0500 Subject: [PATCH] Adds tags node to the view --- CHANGELOG.md | 29 +++++++++++++++++++++------- README.md | 12 ++++++++++-- images/dark/icon-tag.svg | 4 ++++ images/light/icon-tag.svg | 4 ++++ package.json | 10 ++++++++++ src/git/git.ts | 41 +++++++++++++++++++++++---------------- src/git/models/models.ts | 3 ++- src/git/models/repository.ts | 14 +++++++++----- src/git/models/tag.ts | 9 +++++++++ src/git/parsers/tagParser.ts | 15 +++++++++++++++ src/gitService.ts | 11 ++++++++++- src/views/explorerNode.ts | 4 +++- src/views/explorerNodes.ts | 4 +++- src/views/repositoryNode.ts | 6 ++++-- src/views/tagNode.ts | 46 ++++++++++++++++++++++++++++++++++++++++++++ src/views/tagsNode.ts | 36 ++++++++++++++++++++++++++++++++++ 16 files changed, 211 insertions(+), 37 deletions(-) create mode 100644 images/dark/icon-tag.svg create mode 100644 images/light/icon-tag.svg create mode 100644 src/git/models/tag.ts create mode 100644 src/git/parsers/tagParser.ts create mode 100644 src/views/tagNode.ts create mode 100644 src/views/tagsNode.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 3893573..a5df830 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,20 +6,27 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [7.0.0-beta2] - 2017-12-16 ### Added -- Adds a new `Active Repository` node to `Repository View` of the `GitLens` view -- closes [#224](https://github.com/eamodio/vscode-gitlens/issues/224) +- Adds a new `Active Repository` node to the `Repository View` of the `GitLens` view -- closes [#224](https://github.com/eamodio/vscode-gitlens/issues/224) - Automatically updates to track the repository of the active editor - Only visible if there is more than 1 repository within the workspace + +- Adds a new `Tags` node to the `Repository View` of the `GitLens` view + - Provides a list of tags + - Expand each tag to easily see its revision (commit) history + - Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes + - Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`, `Show Commit Details`, `Compare with Selected`, `Select for Compare`, `Rebase Commit (via Terminal)`, `Reset Commit (via Terminal)`, and `Refresh` commands + - Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands + - Provides a context menu on each tag with `Compare with Selected`, `Select for Compare`, and `Refresh` commands + - Provides a context menu with a `Refresh` command + - Adds [Gravatar](https://en.gravatar.com/) support to the `GitLens` view - Adds `gitlens.gitExplorer.gravatars` setting to specify whether or not to show gravatar images instead of commit (or status) icons in the `GitLens` view - Adds `gitlens.gitExplorer.gravatarsDefault` setting to specify the style of the gravatar default (fallback) images in the `GitLens` view
`identicon` - a geometric pattern
`mm` - (mystery-man) a simple, cartoon-style silhouetted outline of a person (does not vary by email hash)
`monsterid` - a monster with different colors, faces, etc
`retro` - 8-bit arcade-style pixelated faces
`robohash` - a robot with different colors, faces, etc
`wavatar` - faces with differing features and backgrounds - Adds `gitlens.resultsExplorer.gravatars` setting to specify whether or not to show gravatar images instead of commit (or status) icons in the `GitLens Results` view - Adds `gitlens.resultsExplorer.gravatarsDefault` setting to specify the style of the gravatar default (fallback) images in the `GitLens Results` view
`identicon` - a geometric pattern
`mm` - (mystery-man) a simple, cartoon-style silhouetted outline of a person (does not vary by email hash)
`monsterid` - a monster with different colors, faces, etc
`retro` - 8-bit arcade-style pixelated faces
`robohash` - a robot with different colors, faces, etc
`wavatar` - faces with differing features and backgrounds -- Adds `Select for Compare` command (`gitlens.explorers.selectForCompare`) to branch and revision (commit) nodes in the `GitLens` view to mark the base revision of a comparision -- Adds `Compare with Selected` command (`gitlens.explorers.compareWithSelected`) to branch and revision (commit) nodes in the `GitLens` view once another branch or revision (commit) node within the same repository has been selected to compare the current selection with the previously selected revision (branch or commit) -- Adds `Apply Changes` option to the commit/stash file quick pick menu -- closes [#232](https://github.com/eamodio/vscode-gitlens/issues/232) -- Adds `Show All Commits` option to the commit search quick pick menu to show all the results, if there are more than the threshold -- Adds `Show in Results` option to the commit search quick pick menu to show the results in the `GitLens Results` view -- Adds `Show in Results` option to the file history quick pick menu to show the history in the `GitLens Results` view + +- Adds `Select for Compare` command (`gitlens.explorers.selectForCompare`) to branch, remote branch, tag, and revision (commit) nodes in the `GitLens` view to mark the base reference of a comparision +- Adds `Compare with Selected` command (`gitlens.explorers.compareWithSelected`) to branch, remote branch, tag, and revision (commit) nodes in the `GitLens` view once another reference within the same repository has been selected to compare the current selection with the previously selected reference in the `GitLens Results` view - Adds an all-new, on-demand `GitLens Results` view to the Explorer activity @@ -39,6 +46,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Provides toolbar commands to `Search Commits`, `Keep Results`, `Refresh`, `Show Files in Automatic View` or `Show Files in List View` or `Show Files in Tree View`, and `Close` +- Adds `Apply Changes` option to the commit/stash file quick pick menu -- closes [#232](https://github.com/eamodio/vscode-gitlens/issues/232) +- Adds `Show All Commits` option to the commit search quick pick menu to show all the results, if there are more than the threshold +- Adds `Show in Results` option to the commit search quick pick menu to show the results in the `GitLens Results` view +- Adds `Show in Results` option to the file history quick pick menu to show the history in the `GitLens Results` view + +### Changed +- Improves startup performance a bit + ### Fixed - Fixes [#228](https://github.com/eamodio/vscode-gitlens/issues/228) - Gutter blame spills over heatmap - Fixes incorrect blame highlighting -- thanks to [PR #231](https://github.com/eamodio/vscode-gitlens/pull/231) by Alexey Vasyukov ([@notmedia](https://github.com/notmedia))! diff --git a/README.md b/README.md index dada21b..99af2da 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ While GitLens is highly customizable and provides many [configuration settings]( - Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes - Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`, `Show Commit Details`, `Compare with Selected`, `Select for Compare`, `Rebase Commit (via Terminal)`, `Reset Commit (via Terminal)`, and `Refresh` commands - Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands - - Provides a context menu on each branch with `Open Branch in Remote`, `Checkout Branch (via Terminal)`, `Create Branch (via Terminal)...`, `Delete Branch (via Terminal)`, `Rebase Branch to Remote (via Terminal)`, `Squash Branch into Commit (via Terminal)`, and `Refresh` commands + - Provides a context menu on each branch with `Open Branch in Remote`, `Compare with Selected`, `Select for Compare`, `Checkout Branch (via Terminal)`, `Create Branch (via Terminal)...`, `Delete Branch (via Terminal)`, `Rebase Branch to Remote (via Terminal)`, `Squash Branch into Commit (via Terminal)`, and `Refresh` commands - Provides a context menu with `Open Branches in Remote`, and `Refresh` commands - `Remotes` node — provides a list of remotes @@ -170,7 +170,7 @@ While GitLens is highly customizable and provides many [configuration settings]( - Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes - Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`,`Show Commit Details`, `Compare with Selected`, `Select for Compare`, and `Refresh` commands - Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, `Show File History`, and `Show Commit File Details` commands - - Provides a context menu on each remote branch with `Open Branch in Remote`, `Checkout Branch (via Terminal)`, `Create Branch (via Terminal)...`, `Delete Branch (via Terminal)`, `Squash Branch into Commit (via Terminal)`, and `Refresh` commands + - Provides a context menu on each remote branch with `Open Branch in Remote`, `Compare with Selected`, `Select for Compare`, `Checkout Branch (via Terminal)`, `Create Branch (via Terminal)...`, `Delete Branch (via Terminal)`, `Squash Branch into Commit (via Terminal)`, and `Refresh` commands - Provides a context menu on each remote with `Open Branches in Remote`, `Open Repository in Remote`, `Remove Remote (via Terminal)`, and `Refresh` commands - Provides a context menu with a `Refresh` command @@ -180,6 +180,14 @@ While GitLens is highly customizable and provides many [configuration settings]( - Provides a context menu on each stashed file with `Apply Changes`, `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, and `Show File History` commands - Provides a context menu with `Stash Changes`, and `Refresh` commands + - `Tags` node — provides a list of tags + - Expand each tag to easily see its revision (commit) history + - Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes + - Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`, `Show Commit Details`, `Compare with Selected`, `Select for Compare`, `Rebase Commit (via Terminal)`, `Reset Commit (via Terminal)`, and `Refresh` commands + - Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands + - Provides a context menu on each tag with `Compare with Selected`, `Select for Compare`, and `Refresh` commands + - Provides a context menu with a `Refresh` command + - `History View` - provides the revision history of the active file ![GitLens History view](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-git-custom-view-history.png) diff --git a/images/dark/icon-tag.svg b/images/dark/icon-tag.svg new file mode 100644 index 0000000..6c42495 --- /dev/null +++ b/images/dark/icon-tag.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/images/light/icon-tag.svg b/images/light/icon-tag.svg new file mode 100644 index 0000000..0a65404 --- /dev/null +++ b/images/light/icon-tag.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/package.json b/package.json index 6a4e0b6..323c356 100644 --- a/package.json +++ b/package.json @@ -2672,6 +2672,16 @@ "group": "8_gitlens@1" }, { + "command": "gitlens.explorers.compareWithSelected", + "when": "viewItem == gitlens:tag && gitlens:explorers:canCompare", + "group": "7_gitlens@1" + }, + { + "command": "gitlens.explorers.selectForCompare", + "when": "viewItem == gitlens:tag", + "group": "7_gitlens@2" + }, + { "command": "gitlens.gitExplorer.refreshNode", "when": "view == gitlens.gitExplorer && viewItem != gitlens:commit-file && viewItem != gitlens:stash-file && viewItem != gitlens:status-file", "group": "9_gitlens@1" diff --git a/src/git/git.ts b/src/git/git.ts index 1531f45..c9023c6 100644 --- a/src/git/git.ts +++ b/src/git/git.ts @@ -19,6 +19,7 @@ export * from './parsers/logParser'; export * from './parsers/remoteParser'; export * from './parsers/stashParser'; export * from './parsers/statusParser'; +export * from './parsers/tagParser'; export * from './remotes/provider'; let git: IGit; @@ -147,15 +148,15 @@ export class Git { return git; } - static async getVersionedFile(repoPath: string | undefined, fileName: string, branchOrSha: string) { - const data = await Git.show(repoPath, fileName, branchOrSha, { encoding: 'binary' }); + static async getVersionedFile(repoPath: string | undefined, fileName: string, ref: string) { + const data = await Git.show(repoPath, fileName, ref, { encoding: 'binary' }); if (data === undefined) return undefined; - if (Git.isStagedUncommitted(branchOrSha)) { - branchOrSha = ''; + if (Git.isStagedUncommitted(ref)) { + ref = ''; } - const suffix = Strings.truncate(Strings.sanitizeForFileSystem(Git.isSha(branchOrSha) ? Git.shortenSha(branchOrSha) : branchOrSha), 50, ''); + const suffix = Strings.truncate(Strings.sanitizeForFileSystem(Git.isSha(ref) ? Git.shortenSha(ref) : ref), 50, ''); const ext = path.extname(fileName); return new Promise((resolve, reject) => { tmp.file({ prefix: `${path.basename(fileName, ext)}-${suffix}__`, postfix: ext }, @@ -165,7 +166,7 @@ export class Git { return; } - Logger.log(`getVersionedFile[${destination}]('${repoPath}', '${fileName}', ${branchOrSha})`); + Logger.log(`getVersionedFile[${destination}]('${repoPath}', '${fileName}', ${ref})`); fs.appendFile(destination, data, { encoding: 'binary' }, err => { if (err) { reject(err); @@ -330,10 +331,10 @@ export class Git { return gitCommand({ cwd: repoPath }, ...params); } - static difftool_dirDiff(repoPath: string, tool: string, sha1: string, sha2?: string) { - const params = [`difftool`, `--dir-diff`, `--tool=${tool}`, sha1]; - if (sha2) { - params.push(sha2); + static difftool_dirDiff(repoPath: string, tool: string, ref1: string, ref2?: string) { + const params = [`difftool`, `--dir-diff`, `--tool=${tool}`, ref1]; + if (ref2) { + params.push(ref2); } return gitCommand({ cwd: repoPath }, ...params); @@ -503,18 +504,18 @@ export class Git { } } - static async show(repoPath: string | undefined, fileName: string, branchOrSha: string, options: { encoding?: string } = {}) { + static async show(repoPath: string | undefined, fileName: string, ref: string, options: { encoding?: string } = {}) { const [file, root] = Git.splitPath(fileName, repoPath); - if (Git.isStagedUncommitted(branchOrSha)) { - branchOrSha = ':'; + if (Git.isStagedUncommitted(ref)) { + ref = ':'; } - if (Git.isUncommitted(branchOrSha)) throw new Error(`sha=${branchOrSha} is uncommitted`); + if (Git.isUncommitted(ref)) throw new Error(`sha=${ref} is uncommitted`); const opts = { cwd: root, encoding: options.encoding || 'utf8', willHandleErrors: true } as GitCommandOptions; - const args = branchOrSha.endsWith(':') - ? `${branchOrSha}./${file}` - : `${branchOrSha}:./${file}`; + const args = ref.endsWith(':') + ? `${ref}./${file}` + : `${ref}:./${file}`; try { const data = await gitCommand(opts, 'show', args); @@ -573,4 +574,10 @@ export class Git { const porcelain = porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain'; return gitCommand({ cwd: root, env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' } }, 'status', porcelain, file); } + + static tag(repoPath: string) { + const params = [`tag`, `-l`]; + + return gitCommand({ cwd: repoPath }, ...params); + } } \ No newline at end of file diff --git a/src/git/models/models.ts b/src/git/models/models.ts index 1ebb99c..5de9860 100644 --- a/src/git/models/models.ts +++ b/src/git/models/models.ts @@ -10,4 +10,5 @@ export * from './remote'; export * from './repository'; export * from './stash'; export * from './stashCommit'; -export * from './status'; \ No newline at end of file +export * from './status'; +export * from './tag'; \ No newline at end of file diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 05fea1c..90e9639 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -2,7 +2,7 @@ import { Functions } from '../../system'; import { ConfigurationChangeEvent, Disposable, Event, EventEmitter, RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode'; import { configuration, IRemotesConfig } from '../../configuration'; -import { GitBranch, GitDiffShortStat, GitRemote, GitStash, GitStatus } from '../git'; +import { GitBranch, GitDiffShortStat, GitRemote, GitStash, GitStatus, GitTag } from '../git'; import { GitService, GitUri } from '../../gitService'; import { RemoteProviderFactory, RemoteProviderMap } from '../remotes/factory'; import * as _path from 'path'; @@ -237,11 +237,11 @@ export class Repository extends Disposable { return this._branch; } - async getBranches(): Promise { + getBranches(): Promise { return this.git.getBranches(this.path); } - async getChangedFilesCount(sha?: string): Promise { + getChangedFilesCount(sha?: string): Promise { return this.git.getChangedFilesCount(this.path, sha); } @@ -258,14 +258,18 @@ export class Repository extends Disposable { return this._remotes; } - async getStashList(): Promise { + getStashList(): Promise { return this.git.getStashList(this.path); } - async getStatus(): Promise { + getStatus(): Promise { return this.git.getStatusForRepo(this.path); } + getTags(): Promise { + return this.git.getTags(this.path); + } + async hasRemote(): Promise { const branch = await this.getBranch(); return branch !== undefined && branch.tracking !== undefined; diff --git a/src/git/models/tag.ts b/src/git/models/tag.ts new file mode 100644 index 0000000..62e275b --- /dev/null +++ b/src/git/models/tag.ts @@ -0,0 +1,9 @@ +'use strict'; + +export class GitTag { + + constructor( + public readonly repoPath: string, + public readonly name: string + ) { } +} \ No newline at end of file diff --git a/src/git/parsers/tagParser.ts b/src/git/parsers/tagParser.ts new file mode 100644 index 0000000..c39e6c9 --- /dev/null +++ b/src/git/parsers/tagParser.ts @@ -0,0 +1,15 @@ +'use strict'; +import { Arrays } from '../../system'; +import { GitTag } from './../git'; + +export class GitTagParser { + + static parse(data: string, repoPath: string): GitTag[] | undefined { + if (!data) return undefined; + + const tags = Arrays.filterMap(data.split('\n'), t => !!t ? new GitTag(repoPath, t) : undefined); + if (!tags.length) return undefined; + + return tags; + } +} \ No newline at end of file diff --git a/src/gitService.ts b/src/gitService.ts index 6d7da36..e0369c9 100644 --- a/src/gitService.ts +++ b/src/gitService.ts @@ -4,7 +4,7 @@ import { ConfigurationChangeEvent, Disposable, Event, EventEmitter, Range, TextD import { configuration, IConfig, IRemotesConfig } from './configuration'; import { CommandContext, DocumentSchemes, setCommandContext } from './constants'; import { RemoteProviderFactory, RemoteProviderMap } from './git/remotes/factory'; -import { 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, IGit, Repository } from './git/git'; +import { 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'; import { GitUri, IGitCommitInfo } from './git/gitUri'; import { Logger } from './logger'; import * as fs from 'fs'; @@ -1197,6 +1197,15 @@ export class GitService extends Disposable { return status; } + async getTags(repoPath: string | undefined): Promise { + if (repoPath === undefined) return []; + + Logger.log(`getTags('${repoPath}')`); + + const data = await Git.tag(repoPath); + return GitTagParser.parse(data, repoPath) || []; + } + async getVersionedFile(repoPath: string | undefined, fileName: string, sha: string | undefined) { Logger.log(`getVersionedFile('${repoPath}', '${fileName}', '${sha}')`); diff --git a/src/views/explorerNode.ts b/src/views/explorerNode.ts index e07ce36..d85eea9 100644 --- a/src/views/explorerNode.ts +++ b/src/views/explorerNode.ts @@ -48,7 +48,9 @@ export enum ResourceType { StatusFile = 'gitlens:status-file', StatusFiles = 'gitlens:status-files', StatusFileCommits = 'gitlens:status-file-commits', - StatusUpstream = 'gitlens:status-upstream' + StatusUpstream = 'gitlens:status-upstream', + Tag = 'gitlens:tag', + Tags = 'gitlens:tags' } export type Explorer = GitExplorer | ResultsExplorer; diff --git a/src/views/explorerNodes.ts b/src/views/explorerNodes.ts index ae8485c..96fca7d 100644 --- a/src/views/explorerNodes.ts +++ b/src/views/explorerNodes.ts @@ -23,4 +23,6 @@ export * from './statusFileNode'; export * from './statusFilesNode'; export * from './statusFilesResultsNode'; export * from './statusNode'; -export * from './statusUpstreamNode'; \ No newline at end of file +export * from './statusUpstreamNode'; +export * from './tagsNode'; +export * from './tagNode'; \ No newline at end of file diff --git a/src/views/repositoryNode.ts b/src/views/repositoryNode.ts index b642cc6..73cae60 100644 --- a/src/views/repositoryNode.ts +++ b/src/views/repositoryNode.ts @@ -6,10 +6,11 @@ import { GlyphChars } from '../constants'; import { ExplorerNode, ResourceType } from './explorerNode'; import { GitExplorer } from './gitExplorer'; import { GitUri, Repository, RepositoryChange, RepositoryChangeEvent } from '../gitService'; +import { Logger } from '../logger'; import { RemotesNode } from './remotesNode'; import { StatusNode } from './statusNode'; import { StashesNode } from './stashesNode'; -import { Logger } from '../logger'; +import { TagsNode } from './tagsNode'; export class RepositoryNode extends ExplorerNode { @@ -30,7 +31,8 @@ export class RepositoryNode extends ExplorerNode { new StatusNode(this.uri, this.repo, this.explorer, this.active), new BranchesNode(this.uri, this.repo, this.explorer, this.active), new RemotesNode(this.uri, this.repo, this.explorer), - new StashesNode(this.uri, this.repo, this.explorer) + new StashesNode(this.uri, this.repo, this.explorer), + new TagsNode(this.uri, this.repo, this.explorer) ]; return this.children; } diff --git a/src/views/tagNode.ts b/src/views/tagNode.ts new file mode 100644 index 0000000..79fe6b0 --- /dev/null +++ b/src/views/tagNode.ts @@ -0,0 +1,46 @@ +'use strict'; +import { Iterables } from '../system'; +import { TreeItem, TreeItemCollapsibleState } from 'vscode'; +import { CommitNode } from './commitNode'; +import { Explorer, ExplorerNode, ExplorerRefNode, MessageNode, ResourceType, ShowAllNode } from './explorerNode'; +import { GitTag, GitUri } from '../gitService'; + +export class TagNode extends ExplorerRefNode { + + readonly supportsPaging: boolean = true; + + constructor( + public readonly tag: GitTag, + uri: GitUri, + private readonly explorer: Explorer + ) { + super(uri); + } + + get ref(): string { + return this.tag.name; + } + + async getChildren(): Promise { + const log = await this.explorer.git.getLogForRepo(this.uri.repoPath!, { maxCount: this.maxCount, ref: this.tag.name }); + if (log === undefined) return [new MessageNode('No commits yet')]; + + const children: (CommitNode | ShowAllNode)[] = [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.explorer))]; + if (log.truncated) { + children.push(new ShowAllNode('Show All Commits', this, this.explorer)); + } + return children; + } + + async getTreeItem(): Promise { + const item = new TreeItem(this.tag.name, TreeItemCollapsibleState.Collapsed); + item.contextValue = ResourceType.Tag; + + item.iconPath = { + dark: this.explorer.context.asAbsolutePath(`images/dark/icon-tag.svg`), + light: this.explorer.context.asAbsolutePath(`images/light/icon-tag.svg`) + }; + + return item; + } +} diff --git a/src/views/tagsNode.ts b/src/views/tagsNode.ts new file mode 100644 index 0000000..2b5deca --- /dev/null +++ b/src/views/tagsNode.ts @@ -0,0 +1,36 @@ +'use strict'; +import { TreeItem, TreeItemCollapsibleState } from 'vscode'; +import { Explorer, ExplorerNode, MessageNode, ResourceType } from './explorerNode'; +import { GitUri, Repository } from '../gitService'; +import { TagNode } from './tagNode'; + +export class TagsNode extends ExplorerNode { + + constructor( + uri: GitUri, + private readonly repo: Repository, + private readonly explorer: Explorer + ) { + super(uri); + } + + async getChildren(): Promise { + const tags = await this.repo.getTags(); + if (tags.length === 0) return [new MessageNode('No tags yet')]; + + tags.sort((a, b) => a.name.localeCompare(b.name)); + return [...tags.map(t => new TagNode(t, this.uri, this.explorer))]; + } + + async getTreeItem(): Promise { + const item = new TreeItem(`Tags`, TreeItemCollapsibleState.Collapsed); + item.contextValue = ResourceType.Tags; + + item.iconPath = { + dark: this.explorer.context.asAbsolutePath('images/dark/icon-tag.svg'), + light: this.explorer.context.asAbsolutePath('images/light/icon-tag.svg') + }; + + return item; + } + }