Skip to content

Commit 12e0336

Browse files
authored
Merge pull request #9 from hansu/1-add-author-filter
1 add author filter
2 parents a78953c + bfa4973 commit 12e0336

File tree

8 files changed

+127
-21
lines changed

8 files changed

+127
-21
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
coverage
22
media
33
node_modules
4+
node_modules_
45
out
56
*.vsix

src/dataSource.ts

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as vscode from 'vscode';
66
import { AskpassEnvironment, AskpassManager } from './askpass/askpassManager';
77
import { getConfig } from './config';
88
import { Logger } from './logger';
9-
import { CommitOrdering, DateType, DeepWriteable, ErrorInfo, ErrorInfoExtensionPrefix, GitCommit, GitCommitDetails, GitCommitStash, GitConfigLocation, GitFileChange, GitFileStatus, GitPushBranchMode, GitRepoConfig, GitRepoConfigBranches, GitResetMode, GitSignature, GitSignatureStatus, GitStash, GitTagDetails, MergeActionOn, RebaseActionOn, SquashMessageFormat, TagType, Writeable } from './types';
9+
import {ActionedUser, CommitOrdering, DateType, DeepWriteable, ErrorInfo, ErrorInfoExtensionPrefix, GitCommit, GitCommitDetails, GitCommitStash, GitConfigLocation, GitFileChange, GitFileStatus, GitPushBranchMode, GitRepoConfig, GitRepoConfigBranches, GitResetMode, GitSignature, GitSignatureStatus, GitStash, GitTagDetails, MergeActionOn, RebaseActionOn, SquashMessageFormat, TagType, Writeable } from './types';
1010
import { GitExecutable, GitVersionRequirement, UNABLE_TO_FIND_GIT_MSG, UNCOMMITTED, abbrevCommit, constructIncompatibleGitVersionMessage, doesVersionMeetRequirement, getPathFromStr, getPathFromUri, openGitTerminal, pathWithTrailingSlash, realpath, resolveSpawnOutput, showErrorMessage } from './utils';
1111
import { Disposable } from './utils/disposable';
1212
import { Event } from './utils/event';
@@ -140,12 +140,12 @@ export class DataSource extends Disposable {
140140
this.getRemotes(repo),
141141
showStashes ? this.getStashes(repo) : Promise.resolve([])
142142
]).then((results) => {
143+
/* eslint no-console: "error" */
143144
return { branches: results[0].branches, head: results[0].head, remotes: results[1], stashes: results[2], error: null };
144145
}).catch((errorMessage) => {
145146
return { branches: [], head: null, remotes: [], stashes: [], error: errorMessage };
146147
});
147148
}
148-
149149
/**
150150
* Get the commits in a repository.
151151
* @param repo The path of the repository.
@@ -161,10 +161,10 @@ export class DataSource extends Disposable {
161161
* @param stashes An array of all stashes in the repository.
162162
* @returns The commits in the repository.
163163
*/
164-
public getCommits(repo: string, branches: ReadonlyArray<string> | null, maxCommits: number, showTags: boolean, showRemoteBranches: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, commitOrdering: CommitOrdering, remotes: ReadonlyArray<string>, hideRemotes: ReadonlyArray<string>, stashes: ReadonlyArray<GitStash>): Promise<GitCommitData> {
164+
public getCommits(repo: string, branches: ReadonlyArray<string> | null, authors: ReadonlyArray<string> | null, maxCommits: number, showTags: boolean, showRemoteBranches: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, commitOrdering: CommitOrdering, remotes: ReadonlyArray<string>, hideRemotes: ReadonlyArray<string>, stashes: ReadonlyArray<GitStash>): Promise<GitCommitData> {
165165
const config = getConfig();
166166
return Promise.all([
167-
this.getLog(repo, branches, maxCommits + 1, showTags && config.showCommitsOnlyReferencedByTags, showRemoteBranches, includeCommitsMentionedByReflogs, onlyFollowFirstParent, commitOrdering, remotes, hideRemotes, stashes),
167+
this.getLog(repo, branches, authors, maxCommits + 1, showTags && config.showCommitsOnlyReferencedByTags, showRemoteBranches, includeCommitsMentionedByReflogs, onlyFollowFirstParent, commitOrdering, remotes, hideRemotes, stashes),
168168
this.getRefs(repo, showRemoteBranches, config.showRemoteHeads, hideRemotes).then((refData: GitRefData) => refData, (errorMessage: string) => errorMessage)
169169
]).then(async (results) => {
170170
let commits: GitCommitRecord[] = results[0], refData: GitRefData | string = results[1], i;
@@ -282,9 +282,10 @@ export class DataSource extends Disposable {
282282
return Promise.all([
283283
this.getConfigList(repo),
284284
this.getConfigList(repo, GitConfigLocation.Local),
285-
this.getConfigList(repo, GitConfigLocation.Global)
285+
this.getConfigList(repo, GitConfigLocation.Global),
286+
this.getAuthorList(repo)
286287
]).then((results) => {
287-
const consolidatedConfigs = results[0], localConfigs = results[1], globalConfigs = results[2];
288+
const consolidatedConfigs = results[0], localConfigs = results[1], globalConfigs = results[2], authors = results[3];
288289

289290
const branches: GitRepoConfigBranches = {};
290291
Object.keys(localConfigs).forEach((key) => {
@@ -304,10 +305,10 @@ export class DataSource extends Disposable {
304305
}
305306
}
306307
});
307-
308308
return {
309309
config: {
310310
branches: branches,
311+
authors,
311312
diffTool: getConfigValue(consolidatedConfigs, GitConfigKey.DiffTool),
312313
guiDiffTool: getConfigValue(consolidatedConfigs, GitConfigKey.DiffGuiTool),
313314
pushDefault: getConfigValue(consolidatedConfigs, GitConfigKey.RemotePushDefault),
@@ -334,7 +335,53 @@ export class DataSource extends Disposable {
334335
});
335336
}
336337

337-
338+
private async getAuthorList(repo: string): Promise<ActionedUser[]> {
339+
const args = ['shortlog', '-e', '-s', '-n', 'HEAD'];
340+
const dict = new Set<string>();
341+
const result = await this.spawnGit(args, repo, (authors) => {
342+
return authors.split(/\r?\n/g)
343+
.map(line => line.trim())
344+
.filter(line => line.trim().length > 0)
345+
.map(line => line.substring(line.indexOf('\t') + 1))
346+
.map(line => {
347+
const indexOfEmailSeparator = line.indexOf('<');
348+
if (indexOfEmailSeparator === -1) {
349+
return {
350+
name: line.trim(),
351+
email: ''
352+
};
353+
} else {
354+
const nameParts = line.split('<');
355+
const name = nameParts.shift()!.trim();
356+
const email = nameParts[0].substring(0, nameParts[0].length - 1).trim();
357+
return {
358+
name,
359+
email
360+
};
361+
}
362+
})
363+
.filter(item => {
364+
if (dict.has(item.name)) {
365+
return false;
366+
}
367+
dict.add(item.name);
368+
return true;
369+
})
370+
.sort((a, b) => (a.name > b.name ? 1 : -1));
371+
}).catch((errorMessage) => {
372+
if (typeof errorMessage === 'string') {
373+
const message = errorMessage.toLowerCase();
374+
if (message.startsWith('fatal: unable to read config file') && message.endsWith('no such file or directory')) {
375+
// If the Git command failed due to the configuration file not existing, return an empty list instead of throwing the exception
376+
return {};
377+
}
378+
} else {
379+
errorMessage = 'An unexpected error occurred while spawning the Git child process.';
380+
}
381+
throw errorMessage;
382+
}) as Promise<ActionedUser[]>;
383+
return result;
384+
}
338385
/* Get Data Methods - Commit Details View */
339386

340387
/**
@@ -1496,11 +1543,16 @@ export class DataSource extends Disposable {
14961543
* @param stashes An array of all stashes in the repository.
14971544
* @returns An array of commits.
14981545
*/
1499-
private getLog(repo: string, branches: ReadonlyArray<string> | null, num: number, includeTags: boolean, includeRemotes: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, order: CommitOrdering, remotes: ReadonlyArray<string>, hideRemotes: ReadonlyArray<string>, stashes: ReadonlyArray<GitStash>) {
1546+
private getLog(repo: string, branches: ReadonlyArray<string> | null, authors: ReadonlyArray<string> | null, num: number, includeTags: boolean, includeRemotes: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, order: CommitOrdering, remotes: ReadonlyArray<string>, hideRemotes: ReadonlyArray<string>, stashes: ReadonlyArray<GitStash>) {
15001547
const args = ['-c', 'log.showSignature=false', 'log', '--max-count=' + num, '--format=' + this.gitFormatLog, '--' + order + '-order'];
15011548
if (onlyFollowFirstParent) {
15021549
args.push('--first-parent');
15031550
}
1551+
if(authors !== null) {
1552+
for (let i = 0; i < authors.length; i++) {
1553+
args.push(`--author=${authors[i]}`);
1554+
}
1555+
}
15041556
if (branches !== null) {
15051557
for (let i = 0; i < branches.length; i++) {
15061558
args.push(branches[i]);
@@ -1519,7 +1571,6 @@ export class DataSource extends Disposable {
15191571
});
15201572
}
15211573
}
1522-
15231574
// Add the unique list of base hashes of stashes, so that commits only referenced by stashes are displayed
15241575
const stashBaseHashes = stashes.map((stash) => stash.baseHash);
15251576
stashBaseHashes.filter((hash, index) => stashBaseHashes.indexOf(hash) === index).forEach((hash) => args.push(hash));
@@ -1528,6 +1579,8 @@ export class DataSource extends Disposable {
15281579
}
15291580
args.push('--');
15301581

1582+
1583+
15311584
return this.spawnGit(args, repo, (stdout) => {
15321585
let lines = stdout.split(EOL_REGEX);
15331586
let commits: GitCommitRecord[] = [];

src/gitGraphView.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ export class GitGraphView extends Disposable {
409409
command: 'loadCommits',
410410
refreshId: msg.refreshId,
411411
onlyFollowFirstParent: msg.onlyFollowFirstParent,
412-
...await this.dataSource.getCommits(msg.repo, msg.branches, msg.maxCommits, msg.showTags, msg.showRemoteBranches, msg.includeCommitsMentionedByReflogs, msg.onlyFollowFirstParent, msg.commitOrdering, msg.remotes, msg.hideRemotes, msg.stashes)
412+
...await this.dataSource.getCommits(msg.repo, msg.branches, msg.authors, msg.maxCommits, msg.showTags, msg.showRemoteBranches, msg.includeCommitsMentionedByReflogs, msg.onlyFollowFirstParent, msg.commitOrdering, msg.remotes, msg.hideRemotes, msg.stashes)
413413
});
414414
break;
415415
case 'loadConfig':
@@ -722,6 +722,8 @@ export class GitGraphView extends Disposable {
722722
<div id="controls"${stickyClassAttr}>
723723
<span id="repoControl"><span class="unselectable">Repo: </span><div id="repoDropdown" class="dropdown"></div></span>
724724
<span id="branchControl"><span class="unselectable">Branches: </span><div id="branchDropdown" class="dropdown"></div></span>
725+
<span id="authorControl"><span class="unselectable">Authors: </span><div id="authorDropdown" class="dropdown"></div></span>
726+
725727
<label id="showRemoteBranchesControl"><input type="checkbox" id="showRemoteBranchesCheckbox" tabindex="-1"><span class="customCheckbox"></span>Show Remote Branches</label>
726728
<div id="findBtn" title="Find"></div>
727729
<div id="terminalBtn" title="Open a Terminal for this Repository"></div>

src/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export const enum GitPushBranchMode {
8989

9090
export interface GitRepoConfig {
9191
readonly branches: GitRepoConfigBranches;
92+
readonly authors: ActionedUser[];
9293
readonly diffTool: string | null;
9394
readonly guiDiffTool: string | null;
9495
readonly pushDefault: string | null;
@@ -106,7 +107,10 @@ export interface GitRepoConfig {
106107
}
107108

108109
export type GitRepoConfigBranches = { [branchName: string]: GitRepoConfigBranch };
109-
110+
export interface ActionedUser{
111+
name: string;
112+
email: string;
113+
};
110114
export interface GitRepoConfigBranch {
111115
readonly pushRemote: string | null;
112116
readonly remote: string | null;
@@ -903,6 +907,7 @@ export interface RequestLoadCommits extends RepoRequest {
903907
readonly command: 'loadCommits';
904908
readonly refreshId: number;
905909
readonly branches: ReadonlyArray<string> | null; // null => Show All
910+
readonly authors: ReadonlyArray<string> | null; // null => Show All
906911
readonly maxCommits: number;
907912
readonly showTags: boolean;
908913
readonly showRemoteBranches: boolean;

web/dropdown.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,17 @@ class Dropdown {
9494
* @param options An array of the options to display in the dropdown.
9595
* @param optionsSelected An array of the selected options in the dropdown.
9696
*/
97-
public setOptions(options: ReadonlyArray<DropdownOption>, optionsSelected: string[]) {
97+
public setOptions(options: ReadonlyArray<DropdownOption>, optionsSelected: string[]|null) {
9898
this.options = options;
9999
this.optionsSelected = [];
100100
let selectedOption = -1, isSelected;
101-
for (let i = 0; i < options.length; i++) {
102-
isSelected = optionsSelected.includes(options[i].value);
103-
this.optionsSelected[i] = isSelected;
104-
if (isSelected) {
105-
selectedOption = i;
101+
if(optionsSelected) {
102+
for (let i = 0; i < options.length; i++) {
103+
isSelected = optionsSelected.includes(options[i].value);
104+
this.optionsSelected[i] = isSelected;
105+
if (isSelected) {
106+
selectedOption = i;
107+
}
106108
}
107109
}
108110
if (selectedOption === -1) {

web/global.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ declare global {
5858
readonly commitHead: string | null;
5959
readonly avatars: AvatarImageCollection;
6060
readonly currentBranches: string[] | null;
61+
readonly currentAuthors: string[] | null;
6162
readonly moreCommitsAvailable: boolean;
6263
readonly maxCommits: number;
6364
readonly onlyFollowFirstParent: boolean;

web/main.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
class GitGraphView {
23
private gitRepos: GG.GitRepoSet;
34
private gitBranches: ReadonlyArray<string> = [];
@@ -12,6 +13,7 @@ class GitGraphView {
1213
private onlyFollowFirstParent: boolean = false;
1314
private avatars: AvatarImageCollection = {};
1415
private currentBranches: string[] | null = null;
16+
private currentAuthors: string[] | null = null;
1517

1618
private currentRepo!: string;
1719
private currentRepoLoading: boolean = true;
@@ -45,6 +47,7 @@ class GitGraphView {
4547
private readonly settingsWidget: SettingsWidget;
4648
private readonly repoDropdown: Dropdown;
4749
private readonly branchDropdown: Dropdown;
50+
private readonly authorDropdown: Dropdown;
4851

4952
private readonly viewElem: HTMLElement;
5053
private readonly controlsElem: HTMLElement;
@@ -92,7 +95,13 @@ class GitGraphView {
9295
this.clearCommits();
9396
this.requestLoadRepoInfoAndCommits(true, true);
9497
});
95-
98+
this.authorDropdown = new Dropdown('authorDropdown', false, true, 'Authors', (values) => {
99+
this.currentAuthors = values;
100+
this.maxCommits = this.config.initialLoadCommits;
101+
this.saveState();
102+
this.clearCommits();
103+
this.requestLoadRepoInfoAndCommits(true, true);
104+
});
96105
this.showRemoteBranchesElem = <HTMLInputElement>document.getElementById('showRemoteBranchesCheckbox')!;
97106
this.showRemoteBranchesElem.addEventListener('change', () => {
98107
this.saveRepoStateValue(this.currentRepo, 'showRemoteBranchesV2', this.showRemoteBranchesElem.checked ? GG.BooleanOverride.Enabled : GG.BooleanOverride.Disabled);
@@ -123,6 +132,7 @@ class GitGraphView {
123132
if (prevState && !prevState.currentRepoLoading && typeof this.gitRepos[prevState.currentRepo] !== 'undefined') {
124133
this.currentRepo = prevState.currentRepo;
125134
this.currentBranches = prevState.currentBranches;
135+
this.currentAuthors = prevState.currentAuthors;
126136
this.maxCommits = prevState.maxCommits;
127137
this.expandedCommit = prevState.expandedCommit;
128138
this.avatars = prevState.avatars;
@@ -216,6 +226,7 @@ class GitGraphView {
216226
this.gitStashes = [];
217227
this.gitTags = [];
218228
this.currentBranches = null;
229+
this.currentAuthors = null;
219230
this.renderFetchButton();
220231
this.closeCommitDetails(false);
221232
this.settingsWidget.close();
@@ -270,10 +281,21 @@ class GitGraphView {
270281
}
271282
}
272283

284+
// Configure current branches
285+
if (this.currentBranches !== null && !(this.currentBranches.length === 1 && this.currentBranches[0] === SHOW_ALL_BRANCHES)) {
286+
// Filter any branches that are currently selected, but no longer exist
287+
const globPatterns = this.config.customBranchGlobPatterns.map((pattern) => pattern.glob);
288+
this.currentBranches = this.currentBranches.filter((branch) =>
289+
this.gitBranches.includes(branch) || globPatterns.includes(branch)
290+
);
291+
}
273292
this.saveState();
293+
this.currentAuthors = [];
294+
this.currentAuthors.push(SHOW_ALL_BRANCHES);
274295

275296
// Set up branch dropdown options
276297
this.branchDropdown.setOptions(this.getBranchOptions(true), this.currentBranches);
298+
this.authorDropdown.setOptions(this.getAuthorOptions(), this.currentAuthors);
277299

278300
// Remove hidden remotes that no longer exist
279301
let hiddenRemotes = this.gitRepos[this.currentRepo].hideRemotes;
@@ -496,6 +518,7 @@ class GitGraphView {
496518
this.renderCdvExternalDiffBtn();
497519
}
498520
this.settingsWidget.refresh();
521+
this.authorDropdown.setOptions(this.getAuthorOptions(), this.currentAuthors);
499522
}
500523

501524
private displayLoadDataError(message: string, reason: string) {
@@ -539,7 +562,17 @@ class GitGraphView {
539562
}
540563
return options;
541564
}
542-
565+
public getAuthorOptions(): ReadonlyArray<DialogSelectInputOption> {
566+
const options: DialogSelectInputOption[] = [];
567+
options.push({ name: 'All', value: SHOW_ALL_BRANCHES });
568+
if(this.gitConfig && this.gitConfig.authors) {
569+
for (let i = 0; i < this!.gitConfig!.authors.length; i++) {
570+
const author = this!.gitConfig!.authors[i];
571+
options.push({ name: author.name, value: author.name });
572+
}
573+
}
574+
return options;
575+
}
543576
public getCommitId(hash: string) {
544577
return typeof this.commitLookup[hash] === 'number' ? this.commitLookup[hash] : null;
545578
}
@@ -611,6 +644,7 @@ class GitGraphView {
611644
repo: this.currentRepo,
612645
refreshId: ++this.currentRepoRefreshState.loadCommitsRefreshId,
613646
branches: this.currentBranches === null || (this.currentBranches.length === 1 && this.currentBranches[0] === SHOW_ALL_BRANCHES) ? null : this.currentBranches,
647+
authors: this.currentAuthors === null || (this.currentAuthors.length === 1 && this.currentAuthors[0] === SHOW_ALL_BRANCHES) ? null : this.currentAuthors,
614648
maxCommits: this.maxCommits,
615649
showTags: getShowTags(repoState.showTags),
616650
showRemoteBranches: getShowRemoteBranches(repoState.showRemoteBranchesV2),
@@ -724,6 +758,7 @@ class GitGraphView {
724758
commitHead: this.commitHead,
725759
avatars: this.avatars,
726760
currentBranches: this.currentBranches,
761+
currentAuthors: this.currentAuthors,
727762
moreCommitsAvailable: this.moreCommitsAvailable,
728763
maxCommits: this.maxCommits,
729764
onlyFollowFirstParent: this.onlyFollowFirstParent,
@@ -979,6 +1014,8 @@ class GitGraphView {
9791014
private getBranchContextMenuActions(target: DialogTarget & RefTarget): ContextMenuActions {
9801015
const refName = target.ref, visibility = this.config.contextMenuActionsVisibility.branch;
9811016
const isSelectedInBranchesDropdown = this.branchDropdown.isSelected(refName);
1017+
// const isSelectedInBranchesDropdown = this.authorDropdown.isSelected(refName);
1018+
9821019
return [[
9831020
{
9841021
title: 'Checkout Branch',
@@ -2010,6 +2047,8 @@ class GitGraphView {
20102047
editorFontFamily = eff;
20112048
this.repoDropdown.refresh();
20122049
this.branchDropdown.refresh();
2050+
this.authorDropdown.refresh();
2051+
20132052
}
20142053
if (fmc !== findMatchColour) {
20152054
findMatchColour = fmc;
@@ -2125,6 +2164,9 @@ class GitGraphView {
21252164
} else if (this.branchDropdown.isOpen()) {
21262165
this.branchDropdown.close();
21272166
handledEvent(e);
2167+
} else if (this.authorDropdown.isOpen()) {
2168+
this.authorDropdown.close();
2169+
handledEvent(e);
21282170
} else if (this.settingsWidget.isVisible()) {
21292171
this.settingsWidget.close();
21302172
handledEvent(e);

web/styles/main.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ body.tagLabelsRightAligned .gitRef.tag{
809809
white-space:nowrap;
810810
margin:0 10px;
811811
}
812-
#repoDropdown, #branchDropdown{
812+
#repoDropdown, #branchDropdown #authorDropdown{
813813
margin-left:3px;
814814
}
815815
#showRemoteBranchesControl > .customCheckbox{

0 commit comments

Comments
 (0)