Переглянути джерело

Adds contributors node to repos

main
Eric Amodio 5 роки тому
джерело
коміт
3c4bb8c900
23 змінених файлів з 380 додано та 33 видалено
  1. +30
    -0
      CHANGELOG.md
  2. +14
    -1
      README.md
  3. +4
    -0
      images/dark/icon-people.svg
  4. +4
    -0
      images/light/icon-people.svg
  5. +37
    -0
      package.json
  6. +2
    -1
      src/container.ts
  7. +4
    -0
      src/git/git.ts
  8. +29
    -8
      src/git/gitService.ts
  9. +4
    -21
      src/git/models/commit.ts
  10. +17
    -0
      src/git/models/contributor.ts
  11. +2
    -0
      src/git/models/models.ts
  12. +5
    -1
      src/git/models/repository.ts
  13. +7
    -0
      src/git/models/shortlog.ts
  14. +1
    -0
      src/git/parsers/parsers.ts
  15. +37
    -0
      src/git/parsers/shortlogParser.ts
  16. +25
    -0
      src/gravatar.ts
  17. +2
    -0
      src/views/nodes.ts
  18. +66
    -0
      src/views/nodes/contributorNode.ts
  19. +41
    -0
      src/views/nodes/contributorsNode.ts
  20. +2
    -0
      src/views/nodes/repositoryNode.ts
  21. +2
    -0
      src/views/nodes/viewNode.ts
  22. +44
    -1
      src/views/viewCommands.ts
  23. +1
    -0
      src/vsls/host.ts

+ 30
- 0
CHANGELOG.md Переглянути файл

@ -4,6 +4,36 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
### Added
- Adds a new _Contributors_ node to each repository in the _Repositories_ view
- **Contributors** — lists the contributors in the repository, sorted by contributed commits
- Provides the avatar (if enabled), name, and email address of each contributor
- An inline toolbar provides quick access to the _Copy to Clipboard_ command
- A context menu provides access to the _Copy to Clipboard_, _Add as Co-author_, and _Refresh_ commands
- Each contributor expands to list the repository's revision (commit) history filtered by the contributor
- An inline toolbar provides quick access to the _Compare with HEAD_ (`alt-click` for _Compare with Working Tree_), _Copy Commit ID to Clipboard_ (`alt-click` for _Copy Commit Message to Clipboard_), and _Open Commit on Remote_ (if available) commands
- A context menu provides access to more common revision (commit) commands
- Each revision (commit) expands to list its set of changed files, complete with status indicators for adds, changes, renames, and deletes
- An inline toolbar provides quick access to the _Open File_, _Copy Commit ID to Clipboard_ (`alt-click` for _Copy Commit Message to Clipboard_), and _Open File on Remote_ (if available) commands
- A context menu provides access to more common file revision commands
- Adds a _Collapse All_ command to the _Repositories_ view — closes [#688](https://github.com/eamodio/vscode-gitlens/issues/688)
- Adds version links to CHANGELOG — closes [#617](https://github.com/eamodio/vscode-gitlens/issues/617) thanks to [PR #600](https://github.com/eamodio/vscode-gitlens/pull/660) by John Gee ([@shadowspawn](https://github.com/shadowspawn))
### Changed
- Updates the invite link to the [VS Code Development Community Slack](https://vscode-slack.amod.io)
- Improves the behavior of the _Open Changes with Next Revision_ (`gitlens.diffWithNext`) command when in the diff editor
- Improves the behavior of the _Open Changes with Previous Revision_ (`gitlens.diffWithPrevious`) command when in the diff editor
- Improves the behavior of the _Open Changes with Working File_ (`gitlens.diffWithWorking`) command when in the diff editor
### Fixed
- Fixes [#683](https://github.com/eamodio/vscode-gitlens/issues/683) - log.showSignature leads to stray files being displayed
- Fixes the behavior of the _Open Line Changes with Previous Revision_ (`gitlens.diffLineWithPrevious`) command to follow the line history much better
## [9.5.1] - 2019-02-13
### Added

+ 14
- 1
README.md Переглянути файл

@ -304,12 +304,24 @@ The repositories view provides the following features,
- An inline toolbar provides quick access to the _Open File_, _Copy Commit ID to Clipboard_ (`alt-click` for _Copy Commit Message to Clipboard_), and _Open File on Remote_ (if available) commands
- A context menu provides access to more common file revision commands
- **Contributors** — lists the contributors in the repository, sorted by contributed commits
- Provides the avatar (if enabled), name, and email address of each contributor
- An inline toolbar provides quick access to the _Copy to Clipboard_ command
- A context menu provides access to the _Copy to Clipboard_, _Add as Co-author_, and _Refresh_ commands
- Each contributor expands to list the repository's revision (commit) history filtered by the contributor
- An inline toolbar provides quick access to the _Compare with HEAD_ (`alt-click` for _Compare with Working Tree_), _Copy Commit ID to Clipboard_ (`alt-click` for _Copy Commit Message to Clipboard_), and _Open Commit on Remote_ (if available) commands
- A context menu provides access to more common revision (commit) commands
- Each revision (commit) expands to list its set of changed files, complete with status indicators for adds, changes, renames, and deletes
- An inline toolbar provides quick access to the _Open File_, _Copy Commit ID to Clipboard_ (`alt-click` for _Copy Commit Message to Clipboard_), and _Open File on Remote_ (if available) commands
- A context menu provides access to more common file revision commands
- **Remotes** — lists the remotes in the repository
- Provides the name of each remote, an indicator of the direction of the remote (fetch, push, both), remote service (if applicable), and repository path
- An inline toolbar provides quick access to the _Fetch_, and _Open Repository on Remote_ (if available) commands
- A context menu provides access to more common repository and remote commands
- Each remote expands list its remote branches
- Each remote expands to list its remote branches
- See the **Branches** above for additional details
- **Stashes** — lists the stashed changes in the repository
@ -888,6 +900,7 @@ A big thanks to the people that have contributed to this project:
- Matt Cooper ([@vtbassmatt](https://github.com/vtbassmatt)) — [contributions](https://github.com/eamodio/vscode-gitlens/commits?author=vtbassmatt)
- Segev Finer ([@segevfiner](https://github.com/segevfiner)) — [contributions](https://github.com/eamodio/vscode-gitlens/commits?author=segevfiner)
- Cory Forsyth ([@bantic](https://github.com/bantic)) — [contributions](https://github.com/eamodio/vscode-gitlens/commits?author=bantic)
- John Gee ([@shadowspawn](https://github.com/shadowspawn)) — [contributions](https://github.com/eamodio/vscode-gitlens/commits?author=shadowspawn)
- Geoffrey ([@g3offrey](https://github.com/g3offrey)) — [contributions](https://github.com/eamodio/vscode-gitlens/commits?author=g3offrey)
- Yukai Huang ([@Yukaii](https://github.com/Yukaii)) — [contributions](https://github.com/eamodio/vscode-gitlens/commits?author=Yukaii)
- Roy Ivy III ([@rivy](https://github.com/rivy)) — [contributions](https://github.com/eamodio/vscode-gitlens/commits?author=rivy)

+ 4
- 0
images/dark/icon-people.svg Переглянути файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 22">
<path fill="#c5c5c5" d="M16 16.5c0 .44-.45 1-1 1H8a1 1 0 0 1-1-1H1c-.54 0-1-.56-1-1 0-2.63 3-4 3-4s.23-.4 0-1c-.84-.62-1.06-.59-1-3 .06-2.42 1.37-3 2.5-3s2.44.58 2.5 3c.06 2.41-.16 2.38-1 3-.23.6 0 1 0 1s1.55.71 2.42 2.09C9.2 12.87 10 12.5 10 12.5s.23-.4 0-1c-.84-.62-1.06-.59-1-3 .06-2.42 1.37-3 2.5-3s2.44.58 2.5 3c.05 2.41-.16 2.38-1 3-.23.59 0 1 0 1s3 1.37 3 4z"/>
</svg>

+ 4
- 0
images/light/icon-people.svg Переглянути файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 22">
<path fill="#424242" d="M16 16.5c0 .44-.45 1-1 1H8a1 1 0 0 1-1-1H1c-.54 0-1-.56-1-1 0-2.63 3-4 3-4s.23-.4 0-1c-.84-.62-1.06-.59-1-3 .06-2.42 1.37-3 2.5-3s2.44.58 2.5 3c.06 2.41-.16 2.38-1 3-.23.6 0 1 0 1s1.55.71 2.42 2.09C9.2 12.87 10 12.5 10 12.5s.23-.4 0-1c-.84-.62-1.06-.59-1-3 .06-2.42 1.37-3 2.5-3s2.44.58 2.5 3c.05 2.41-.16 2.38-1 3-.23.59 0 1 0 1s3 1.37 3 4z"/>
</svg>

+ 37
- 0
package.json Переглянути файл

@ -2477,6 +2477,20 @@
}
},
{
"command": "gitlens.views.contributor.addCoauthoredBy",
"title": "Add as Co-author",
"category": "GitLens"
},
{
"command": "gitlens.views.contributor.copyToClipboard",
"title": "Copy to Clipboard",
"category": "GitLens",
"icon": {
"dark": "images/dark/icon-clipboard.svg",
"light": "images/light/icon-clipboard.svg"
}
},
{
"command": "gitlens.views.terminalCheckoutBranch",
"title": "Checkout Branch (via Terminal)",
"category": "GitLens"
@ -3256,6 +3270,14 @@
"when": "false"
},
{
"command": "gitlens.views.contributor.addCoauthoredBy",
"when": "false"
},
{
"command": "gitlens.views.contributor.copyToClipboard",
"when": "false"
},
{
"command": "gitlens.views.terminalCheckoutBranch",
"when": "false"
},
@ -4105,6 +4127,21 @@
"group": "8_gitlens_@1"
},
{
"command": "gitlens.views.contributor.copyToClipboard",
"when": "viewItem =~ /gitlens:contributor\\b/",
"group": "inline@98"
},
{
"command": "gitlens.views.contributor.copyToClipboard",
"when": "viewItem =~ /gitlens:contributor\\b/",
"group": "1_gitlens@1"
},
{
"command": "gitlens.views.contributor.addCoauthoredBy",
"when": "viewItem =~ /gitlens:contributor\\b/",
"group": "2_gitlens@1"
},
{
"command": "gitlens.openCommitInRemote",
"when": "viewItem =~ /gitlens:commit\\b/ && gitlens:hasRemotes",
"group": "inline@98"

+ 2
- 1
src/container.ts Переглянути файл

@ -6,7 +6,8 @@ import { GitCodeLensController } from './codelens/codeLensController';
import { Commands, ToggleFileBlameCommandArgs } from './commands';
import { AnnotationsToggleMode, Config, configuration, ConfigurationWillChangeEvent } from './configuration';
import { GitFileSystemProvider } from './git/fsProvider';
import { clearGravatarCache, GitService } from './git/gitService';
import { GitService } from './git/gitService';
import { clearGravatarCache } from './gravatar';
import { LineHoverController } from './hovers/lineHoverController';
import { Keyboard } from './keyboard';
import { Logger, TraceLevel } from './logger';

+ 4
- 0
src/git/git.ts Переглянути файл

@ -811,6 +811,10 @@ export class Git {
return data.length === 0 ? undefined : data.trim();
}
static shortlog(repoPath: string) {
return git<string>({ cwd: repoPath }, 'shortlog', '-sne', '--all', '--no-merges');
}
static async show<TOut extends string | Buffer>(
repoPath: string | undefined,
fileName: string,

+ 29
- 8
src/git/gitService.ts Переглянути файл

@ -6,6 +6,7 @@ import {
Disposable,
Event,
EventEmitter,
Extension,
extensions,
ProgressLocation,
Range,
@ -18,7 +19,7 @@ import {
WorkspaceFoldersChangeEvent
} from 'vscode';
// eslint-disable-next-line import/no-unresolved
import { GitExtension } from '../@types/git';
import { API as BuiltInGitApi, GitExtension } from '../@types/git';
import { configuration, RemotesConfig } from '../configuration';
import { CommandContext, DocumentSchemes, GlyphChars, setCommandContext } from '../constants';
import { Container } from '../container';
@ -40,6 +41,7 @@ import {
GitBranchParser,
GitCommit,
GitCommitType,
GitContributor,
GitDiff,
GitDiffChunkLine,
GitDiffParser,
@ -64,6 +66,7 @@ import {
} from './git';
import { GitUri } from './gitUri';
import { RemoteProviderFactory, RemoteProviders } from './remotes/factory';
import { GitShortLogParser } from './parsers/parsers';
export * from './gitUri';
export * from './models/models';
@ -1117,6 +1120,15 @@ export class GitService implements Disposable {
}
@log()
async getContributors(repoPath: string): Promise<GitContributor[]> {
if (repoPath === undefined) return [];
const data = await Git.shortlog(repoPath);
const shortlog = GitShortLogParser.parse(data, repoPath);
return shortlog === undefined ? [] : shortlog.contributors;
}
@log()
async getCurrentUser(repoPath: string) {
let user = this._userMapCache.get(repoPath);
if (user != null) return user;
@ -2218,18 +2230,27 @@ export class GitService implements Disposable {
static async initialize(): Promise<void> {
// Try to use the same git as the built-in vscode git extension
let gitPath;
const gitApi = await GitService.getBuiltInGitApi();
if (gitApi !== undefined) {
gitPath = gitApi.git.path;
}
await Git.setOrFindGitPath(gitPath || workspace.getConfiguration('git').get<string>('path'));
}
@log()
static async getBuiltInGitApi(): Promise<BuiltInGitApi | undefined> {
try {
const gitExtension = extensions.getExtension('vscode.git');
if (gitExtension !== undefined) {
const gitApi = ((gitExtension.isActive
? gitExtension.exports
: await gitExtension.activate()) as GitExtension).getAPI(1);
gitPath = gitApi.git.path;
const extension = extensions.getExtension('vscode.git') as Extension<GitExtension>;
if (extension !== undefined) {
const gitExtension = extension.isActive ? extension.exports : await extension.activate();
return gitExtension.getAPI(1);
}
}
catch {}
await Git.setOrFindGitPath(gitPath || workspace.getConfiguration('git').get<string>('path'));
return undefined;
}
static getGitPath(): string {

+ 4
- 21
src/git/models/commit.ts Переглянути файл

@ -2,17 +2,11 @@
import { Uri } from 'vscode';
import { configuration, DateStyle, GravatarDefaultStyle } from '../../configuration';
import { Container } from '../../container';
import { Dates, Strings } from '../../system';
import { Dates } from '../../system';
import { CommitFormatter } from '../formatters/formatters';
import { Git } from '../git';
import { GitUri } from '../gitUri';
const gravatarCache: Map<string, Uri> = new Map();
const missingGravatarHash = '00000000000000000000000000000000';
export function clearGravatarCache() {
gravatarCache.clear();
}
import { getGravatarUri } from '../../gravatar';
export interface GitAuthor {
name: string;
@ -180,22 +174,11 @@ export abstract class GitCommit {
}
getGravatarUri(fallback: GravatarDefaultStyle, size: number = 16): Uri {
const hash =
this.email != null && this.email.length !== 0
? Strings.md5(this.email.trim().toLowerCase(), 'hex')
: missingGravatarHash;
const key = `${hash}:${size}`;
let gravatar = gravatarCache.get(key);
if (gravatar !== undefined) return gravatar;
gravatar = Uri.parse(`https://www.gravatar.com/avatar/${hash}.jpg?s=${size}&d=${fallback}`);
gravatarCache.set(key, gravatar);
return gravatar;
return getGravatarUri(this.email, fallback, size);
}
getShortMessage() {
// eslint-disable-next-line no-template-curly-in-string
return CommitFormatter.fromTemplate('${message}', this, { truncateMessageAtNewLine: true });
}

+ 17
- 0
src/git/models/contributor.ts Переглянути файл

@ -0,0 +1,17 @@
'use strict';
import { Uri } from 'vscode';
import { GravatarDefaultStyle } from '../../configuration';
import { getGravatarUri } from '../../gravatar';
export class GitContributor {
constructor(
public readonly repoPath: string,
public readonly name: string,
public readonly email: string,
public readonly count: number
) {}
getGravatarUri(fallback: GravatarDefaultStyle, size: number = 16): Uri {
return getGravatarUri(this.email, fallback, size);
}
}

+ 2
- 0
src/git/models/models.ts Переглянути файл

@ -4,12 +4,14 @@ export * from './blame';
export * from './blameCommit';
export * from './branch';
export * from './commit';
export * from './contributor';
export * from './diff';
export * from './file';
export * from './log';
export * from './logCommit';
export * from './remote';
export * from './repository';
export * from './shortlog';
export * from './stash';
export * from './stashCommit';
export * from './status';

+ 5
- 1
src/git/models/repository.ts Переглянути файл

@ -18,7 +18,7 @@ import { configuration, RemotesConfig } from '../../configuration';
import { StarredRepositories, WorkspaceState } from '../../constants';
import { Container } from '../../container';
import { Functions, gate, log } from '../../system';
import { GitBranch, GitDiffShortStat, GitRemote, GitStash, GitStatus, GitTag } from '../git';
import { GitBranch, GitContributor, GitDiffShortStat, GitRemote, GitStash, GitStatus, GitTag } from '../git';
import { GitUri } from '../gitUri';
import { RemoteProviderFactory, RemoteProviders } from '../remotes/factory';
@ -272,6 +272,10 @@ export class Repository implements Disposable {
return Container.git.getChangedFilesCount(this.path, sha);
}
getContributors(): Promise<GitContributor[]> {
return Container.git.getContributors(this.path);
}
async getLastFetched(): Promise<number> {
const hasRemotes = await this.hasRemotes();
if (!hasRemotes || Container.vsls.isMaybeGuest) return 0;

+ 7
- 0
src/git/models/shortlog.ts Переглянути файл

@ -0,0 +1,7 @@
'use strict';
import { GitContributor } from './contributor';
export interface GitShortLog {
readonly repoPath: string;
readonly contributors: GitContributor[];
}

+ 1
- 0
src/git/parsers/parsers.ts Переглянути файл

@ -5,6 +5,7 @@ export * from './branchParser';
export * from './diffParser';
export * from './logParser';
export * from './remoteParser';
export * from './shortlogParser';
export * from './stashParser';
export * from './statusParser';
export * from './tagParser';

+ 37
- 0
src/git/parsers/shortlogParser.ts Переглянути файл

@ -0,0 +1,37 @@
'use strict';
import { GitContributor, GitShortLog } from '../git';
const shortlogRegex = /^(.*?)\t(.*?) <(.*?)>$/gm;
export class GitShortLogParser {
static parse(data: string, repoPath: string): GitShortLog | undefined {
if (!data) return undefined;
const contributors: GitContributor[] = [];
let count;
let name;
let email;
let match: RegExpExecArray | null = null;
do {
match = shortlogRegex.exec(data);
if (match == null) break;
[, count, name, email] = match;
contributors.push(
new GitContributor(
repoPath,
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
` ${name}`.substr(1),
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
` ${email}`.substr(1),
parseInt(count, 10)
)
);
} while (match != null);
if (!contributors.length) return undefined;
return { repoPath: repoPath, contributors: contributors };
}
}

+ 25
- 0
src/gravatar.ts Переглянути файл

@ -0,0 +1,25 @@
'use strict';
import { Uri } from 'vscode';
import { GravatarDefaultStyle } from './config';
import { Strings } from './system';
const gravatarCache: Map<string, Uri> = new Map();
const missingGravatarHash = '00000000000000000000000000000000';
export function clearGravatarCache() {
gravatarCache.clear();
}
export function getGravatarUri(email: string | undefined, fallback: GravatarDefaultStyle, size: number = 16): Uri {
const hash =
email != null && email.length !== 0 ? Strings.md5(email.trim().toLowerCase(), 'hex') : missingGravatarHash;
const key = `${hash}:${size}`;
let gravatar = gravatarCache.get(key);
if (gravatar !== undefined) return gravatar;
gravatar = Uri.parse(`https://www.gravatar.com/avatar/${hash}.jpg?s=${size}&d=${fallback}`);
gravatarCache.set(key, gravatar);
return gravatar;
}

+ 2
- 0
src/views/nodes.ts Переглянути файл

@ -6,6 +6,8 @@ export * from './nodes/branchNode';
export * from './nodes/branchTrackingStatusNode';
export * from './nodes/commitFileNode';
export * from './nodes/commitNode';
export * from './nodes/contributorNode';
export * from './nodes/contributorsNode';
export * from './nodes/fileHistoryNode';
export * from './nodes/fileHistoryTrackerNode';
export * from './nodes/folderNode';

+ 66
- 0
src/views/nodes/contributorNode.ts Переглянути файл

@ -0,0 +1,66 @@
'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { GitContributor, GitUri } from '../../git/gitService';
import { Iterables, Strings } from '../../system';
import { RepositoriesView } from '../repositoriesView';
import { PageableViewNode, ResourceType, ViewNode } from './viewNode';
import { Container } from '../../container';
import { MessageNode, ShowMoreNode } from './common';
import { getBranchesAndTagTipsFn, insertDateMarkers } from './helpers';
import { CommitNode } from './commitNode';
export class ContributorNode extends ViewNode<RepositoriesView> implements PageableViewNode {
readonly supportsPaging: boolean = true;
maxCount: number | undefined;
constructor(uri: GitUri, view: RepositoriesView, parent: ViewNode, public readonly contributor: GitContributor) {
super(uri, view, parent);
}
get id(): string {
return `${this._instanceId}:gitlens:repository(${this.contributor.repoPath}):contributor(${
this.contributor.name
}|${this.contributor.email}}`;
}
async getChildren(): Promise<ViewNode[]> {
const log = await Container.git.getLog(this.uri.repoPath!, {
maxCount: this.maxCount || this.view.config.defaultItemLimit,
authors: [this.contributor.name]
});
if (log === undefined) return [new MessageNode(this.view, this, 'No commits could be found.')];
const getBranchAndTagTips = await getBranchesAndTagTipsFn(this.uri.repoPath);
const children = [
...insertDateMarkers(
Iterables.map(
log.commits.values(),
c => new CommitNode(this.view, this, c, undefined, getBranchAndTagTips)
),
this
)
];
if (log.truncated) {
children.push(new ShowMoreNode(this.view, this, 'Commits'));
}
return children;
}
getTreeItem(): TreeItem {
const item = new TreeItem(this.contributor.name, TreeItemCollapsibleState.Collapsed);
item.id = this.id;
item.contextValue = ResourceType.Contributor;
item.description = this.contributor.email;
item.tooltip = `${this.contributor.name} <${this.contributor.email}>\n${Strings.pluralize(
'commit',
this.contributor.count
)}`;
if (this.view.config.avatars) {
item.iconPath = this.contributor.getGravatarUri(Container.config.defaultGravatarsStyle);
}
return item;
}
}

+ 41
- 0
src/views/nodes/contributorsNode.ts Переглянути файл

@ -0,0 +1,41 @@
'use strict';
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { GitUri, Repository } from '../../git/gitService';
import { RepositoriesView } from '../repositoriesView';
import { MessageNode } from './common';
import { ContributorNode } from './contributorNode';
import { ResourceType, ViewNode } from './viewNode';
import { Container } from '../../container';
export class ContributorsNode extends ViewNode<RepositoriesView> {
constructor(uri: GitUri, view: RepositoriesView, parent: ViewNode, public readonly repo: Repository) {
super(uri, view, parent);
}
get id(): string {
return `${this._instanceId}:gitlens:repository(${this.repo.path}):contributors`;
}
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.')];
contributors.sort((a, b) => b.count - a.count);
const children = contributors.map(c => new ContributorNode(this.uri, this.view, this, c));
return children;
}
getTreeItem(): TreeItem {
const item = new TreeItem('Contributors', TreeItemCollapsibleState.Collapsed);
item.id = this.id;
item.contextValue = ResourceType.Contributors;
item.iconPath = {
dark: Container.context.asAbsolutePath('images/dark/icon-people.svg'),
light: Container.context.asAbsolutePath('images/light/icon-people.svg')
};
return item;
}
}

+ 2
- 0
src/views/nodes/repositoryNode.ts Переглянути файл

@ -22,6 +22,7 @@ import { StashesNode } from './stashesNode';
import { StatusFilesNode } from './statusFilesNode';
import { TagsNode } from './tagsNode';
import { ResourceType, SubscribeableViewNode, ViewNode } from './viewNode';
import { ContributorsNode } from './contributorsNode';
const hasTimeRegex = /[hHm]/;
@ -78,6 +79,7 @@ export class RepositoryNode extends SubscribeableViewNode {
children.push(
new BranchesNode(this.uri, this.view, this, this.repo),
new ContributorsNode(this.uri, this.view, this, this.repo),
new RemotesNode(this.uri, this.view, this, this.repo),
new StashesNode(this.uri, this.view, this, this.repo),
new TagsNode(this.uri, this.view, this, this.repo)

+ 2
- 0
src/views/nodes/viewNode.ts Переглянути файл

@ -19,6 +19,8 @@ export enum ResourceType {
ComparePicker = 'gitlens:compare:picker',
ComparePickerWithRef = 'gitlens:compare:picker:ref',
CompareResults = 'gitlens:compare:results',
Contributor = 'gitlens:contributor',
Contributors = 'gitlens:contributors',
File = 'gitlens:file',
FileHistory = 'gitlens:history:file',
Folder = 'gitlens:folder',

+ 44
- 1
src/views/viewCommands.ts Переглянути файл

@ -1,6 +1,6 @@
'use strict';
import * as paths from 'path';
import { commands, Disposable, Terminal, TextDocumentShowOptions, Uri, window } from 'vscode';
import { commands, Disposable, env, Terminal, TextDocumentShowOptions, Uri, window } from 'vscode';
import {
Commands,
DiffWithCommandArgs,
@ -34,6 +34,8 @@ import {
ViewRefNode,
viewSupportsNodeDismissal
} from './nodes';
import { ContributorNode } from './nodes/contributorNode';
import { Strings } from '../system/string';
export interface RefreshNodeCommandArgs {
maxCount?: number;
@ -83,6 +85,9 @@ export class ViewCommands implements Disposable {
commands.registerCommand('gitlens.views.exploreRepoRevision', this.exploreRepoRevision, this);
commands.registerCommand('gitlens.views.contributor.addCoauthoredBy', this.contributorAddCoauthoredBy, this);
commands.registerCommand('gitlens.views.contributor.copyToClipboard', this.contributorCopyToClipboard, this);
commands.registerCommand('gitlens.views.openChanges', this.openChanges, this);
commands.registerCommand('gitlens.views.openChangesWithWorking', this.openChangesWithWorking, this);
commands.registerCommand('gitlens.views.openFile', this.openFile, this);
@ -139,6 +144,44 @@ export class ViewCommands implements Disposable {
this._disposable && this._disposable.dispose();
}
private async contributorAddCoauthoredBy(node: ContributorNode) {
if (!(node instanceof ContributorNode)) return;
const gitApi = await GitService.getBuiltInGitApi();
if (gitApi === undefined) return;
const repo = gitApi.repositories.find(
r => Strings.normalizePath(r.rootUri.fsPath) === node.contributor.repoPath
);
if (repo === undefined) return;
const coauthor = `${node.contributor.name}${node.contributor.email ? ` <${node.contributor.email}>` : ''}`;
const message = repo.inputBox.value;
if (message.includes(coauthor)) return;
let newlines;
if (message.includes('Co-authored-by: ')) {
newlines = '\n';
}
else if (message.length !== 0 && message[message.length - 1] === '\n') {
newlines = '\n\n';
}
else {
newlines = '\n\n\n';
}
repo.inputBox.value = `${message}${newlines}Co-authored-by: ${coauthor}`;
}
private async contributorCopyToClipboard(node: ContributorNode) {
if (!(node instanceof ContributorNode)) return;
await env.clipboard.writeText(
`${node.contributor.name}${node.contributor.email ? ` <${node.contributor.email}>` : ''}`
);
}
private fetch(node: RemoteNode | RepositoryNode) {
if (node instanceof RemoteNode) return node.fetch();
if (node instanceof RepositoryNode) return node.fetch();

+ 1
- 0
src/vsls/host.ts Переглянути файл

@ -34,6 +34,7 @@ const gitWhitelist = new Map boolean>([
['merge-base', defaultWhitelistFn],
['remote', args => args[1] === '-v' || args[1] === 'get-url'],
['rev-parse', defaultWhitelistFn],
['shortlog', defaultWhitelistFn],
['show', defaultWhitelistFn],
['show-ref', defaultWhitelistFn],
['stash', args => args[1] === 'list'],

Завантаження…
Відмінити
Зберегти