瀏覽代碼

Adds view decorations (branches & commit files)

main
Eric Amodio 3 年之前
父節點
當前提交
a07acf3ebd
共有 9 個檔案被更改,包括 284 行新增6 行删除
  1. +63
    -0
      package.json
  2. +4
    -2
      src/constants.ts
  3. +3
    -0
      src/container.ts
  4. +25
    -0
      src/git/models/branch.ts
  5. +5
    -2
      src/git/models/status.ts
  6. +6
    -1
      src/views/nodes/branchNode.ts
  7. +2
    -1
      src/views/nodes/commitFileNode.ts
  8. +2
    -0
      src/views/nodes/fileRevisionAsCommitNode.ts
  9. +174
    -0
      src/views/viewDecorationProvider.ts

+ 63
- 0
package.json 查看文件

@ -2807,6 +2807,69 @@
"light": "#b15e35",
"highContrast": "#ff874c"
}
},
{
"id": "gitlens.decorations.copiedForegroundColor",
"description": "Specifies the decoration foreground color of copied files",
"defaults": {
"light": "#007100",
"dark": "#73C991",
"highContrast": "#73C991"
}
},
{
"id": "gitlens.decorations.renamedForegroundColor",
"description": "Specifies the decoration foreground color of renamed files",
"defaults": {
"light": "#007100",
"dark": "#73C991",
"highContrast": "#73C991"
}
},
{
"id": "gitlens.decorations.branchAheadForegroundColor",
"description": "Specifies the decoration foreground color of branches that are ahead of their upstream",
"defaults": {
"dark": "#35b15e",
"light": "#35b15e",
"highContrast": "#4dff88"
}
},
{
"id": "gitlens.decorations.branchBehindForegroundColor",
"description": "Specifies the decoration foreground color of branches that are behind their upstream",
"defaults": {
"dark": "#b15e35",
"light": "#b15e35",
"highContrast": "#ff874c"
}
},
{
"id": "gitlens.decorations.branchDivergedForegroundColor",
"description": "Specifies the decoration foreground color of branches that are both ahead and behind their upstream",
"defaults": {
"dark": "#D8AF1B",
"light": "#D8AF1B",
"highContrast": "#D8AF1B"
}
},
{
"id": "gitlens.decorations.branchUpToDateForegroundColor",
"description": "Specifies the decoration foreground color of branches that are up to date with their upstream",
"defaults": {
"dark": "sideBar.foreground",
"light": "sideBar.foreground",
"highContrast": "sideBar.foreground"
}
},
{
"id": "gitlens.decorations.branchUnpublishedForegroundColor",
"description": "Specifies the decoration foreground color of branches that are not yet published to an upstream",
"defaults": {
"dark": "#35b15e",
"light": "#35b15e",
"highContrast": "#4dff88"
}
}
],
"commands": [

+ 4
- 2
src/constants.ts 查看文件

@ -119,11 +119,12 @@ export function hasVisibleTextEditor(): boolean {
return window.visibleTextEditors.some(e => isTextEditor(e));
}
export enum GlyphChars {
export const enum GlyphChars {
AngleBracketLeftHeavy = '\u2770',
AngleBracketRightHeavy = '\u2771',
ArrowBack = '\u21a9',
ArrowDown = '\u2193',
ArrowDownUp = '\u21F5',
ArrowDropRight = '\u2937',
ArrowHeadRight = '\u27A4',
ArrowLeft = '\u2190',
@ -136,13 +137,14 @@ export enum GlyphChars {
ArrowRightDouble = '\u21d2',
ArrowRightHollow = '\u21e8',
ArrowUp = '\u2191',
ArrowUpDown = '\u21C5',
ArrowUpRight = '\u2197',
ArrowsHalfLeftRight = '\u21cb',
ArrowsHalfRightLeft = '\u21cc',
ArrowsLeftRight = '\u21c6',
ArrowsRightLeft = '\u21c4',
Asterisk = '\u2217',
Check = '\u2713',
Check = '',
Dash = '\u2014',
Dot = '\u2022',
Ellipsis = '\u2026',

+ 3
- 0
src/container.ts 查看文件

@ -35,6 +35,7 @@ import { SearchAndCompareView } from './views/searchAndCompareView';
import { StashesView } from './views/stashesView';
import { TagsView } from './views/tagsView';
import { ViewCommands } from './views/viewCommands';
import { ViewFileDecorationProvider } from './views/viewDecorationProvider';
import { VslsController } from './vsls/vsls';
import { RebaseEditorProvider } from './webviews/rebaseEditor';
import { SettingsWebview } from './webviews/settingsWebview';
@ -60,6 +61,8 @@ export class Container {
context.subscriptions.push((this._git = new GitService()));
context.subscriptions.push(new ViewFileDecorationProvider());
// Since there is a bit of a chicken & egg problem with the DocumentTracker and the GitService, initialize the tracker once the GitService is loaded
this._tracker.initialize();

+ 25
- 0
src/git/models/branch.ts 查看文件

@ -25,6 +25,15 @@ export interface GitTrackingState {
behind: number;
}
export enum GitBranchStatus {
Ahead = 'ahead',
Behind = 'behind',
Diverged = 'diverged',
UpToDate = 'upToDate',
Unpublished = 'unpublished',
LocalOnly = 'localOnly',
}
export class GitBranch implements GitBranchReference {
static is(branch: any): branch is GitBranch {
return branch instanceof GitBranch;
@ -189,7 +198,23 @@ export class GitBranch implements GitBranchReference {
return undefined;
}
@memoize()
async getStatus(): Promise<GitBranchStatus> {
if (this.tracking) {
if (this.state.ahead && this.state.behind) return GitBranchStatus.Diverged;
if (this.state.ahead) return GitBranchStatus.Ahead;
if (this.state.behind) return GitBranchStatus.Behind;
return GitBranchStatus.UpToDate;
}
const remotes = await Container.git.getRemotes(this.repoPath);
if (remotes.length > 0) return GitBranchStatus.Unpublished;
return GitBranchStatus.LocalOnly;
}
getTrackingStatus(options?: {
count?: boolean;
empty?: string;
expand?: boolean;
icons?: boolean;

+ 5
- 2
src/git/models/status.ts 查看文件

@ -256,6 +256,7 @@ export class GitStatus {
upstream: string | undefined,
state: { ahead: number; behind: number },
options: {
count?: boolean;
empty?: string;
expand?: boolean;
icons?: boolean;
@ -264,7 +265,7 @@ export class GitStatus {
suffix?: string;
} = {},
): string {
const { expand = false, icons = false, prefix = '', separator = ' ', suffix = '' } = options;
const { count = true, expand = false, icons = false, prefix = '', separator = ' ', suffix = '' } = options;
if (upstream == null || (state.behind === 0 && state.ahead === 0)) return options.empty ?? '';
if (expand) {
@ -285,7 +286,9 @@ export class GitStatus {
return `${prefix}${status}${suffix}`;
}
return `${prefix}${state.behind}${GlyphChars.ArrowDown}${separator}${state.ahead}${GlyphChars.ArrowUp}${suffix}`;
return `${prefix}${count ? state.behind : ''}${
count || state.behind !== 0 ? GlyphChars.ArrowDown : ''
}${separator}${count ? state.ahead : ''}${count || state.ahead !== 0 ? GlyphChars.ArrowUp : ''}${suffix}`;
}
}

+ 6
- 1
src/views/nodes/branchNode.ts 查看文件

@ -1,5 +1,5 @@
'use strict';
import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, window } from 'vscode';
import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, window } from 'vscode';
import { BranchesView } from '../branchesView';
import { BranchTrackingStatusNode } from './branchTrackingStatusNode';
import { CommitNode } from './commitNode';
@ -404,6 +404,11 @@ export class BranchNode
item.description = description;
item.id = this.id;
item.tooltip = tooltip;
item.resourceUri = Uri.parse(
`gitlens-view://branch/status/${await this.branch.getStatus()}${
this.options.showCurrent && this.current ? '/current' : ''
}`,
);
return item;
}

+ 2
- 1
src/views/nodes/commitFileNode.ts 查看文件

@ -1,6 +1,6 @@
'use strict';
import * as paths from 'path';
import { Command, Selection, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Command, Selection, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
import { Commands, DiffWithPreviousCommandArgs } from '../../commands';
import { Container } from '../../container';
import { GitBranch, GitFile, GitLogCommit, GitRevisionReference, StatusFileFormatter } from '../../git/git';
@ -63,6 +63,7 @@ export class CommitFileNode extends ViewR
const item = new TreeItem(this.label, TreeItemCollapsibleState.None);
item.contextValue = this.contextValue;
item.description = this.description;
item.resourceUri = Uri.parse(`gitlens-view://commit-file/status/${this.file.status}`);
item.tooltip = this.tooltip;
const icon = GitFile.getStatusIcon(this.file.status);

+ 2
- 0
src/views/nodes/fileRevisionAsCommitNode.ts 查看文件

@ -104,6 +104,8 @@ export class FileRevisionAsCommitNode extends ViewRefFileNode
messageTruncateAtNewLine: true,
});
item.resourceUri = Uri.parse(`gitlens-view://commit-file/status/${this.file.status}`);
// eslint-disable-next-line no-template-curly-in-string
const status = StatusFileFormatter.fromTemplate('${status}${ (originalPath)}', this.file); // lgtm [js/template-syntax-in-string-literal]
item.tooltip = CommitFormatter.fromTemplate(

+ 174
- 0
src/views/viewDecorationProvider.ts 查看文件

@ -0,0 +1,174 @@
'use strict';
import {
CancellationToken,
Disposable,
Event,
EventEmitter,
FileDecoration,
FileDecorationProvider,
ThemeColor,
Uri,
window,
} from 'vscode';
import { GlyphChars } from '../constants';
import { GitBranchStatus } from '../git/git';
export class ViewFileDecorationProvider implements FileDecorationProvider, Disposable {
private readonly _onDidChange = new EventEmitter<undefined | Uri | Uri[]>();
get onDidChange(): Event<undefined | Uri | Uri[]> {
return this._onDidChange.event;
}
private readonly disposable: Disposable;
constructor() {
this.disposable = Disposable.from(
// Register the current branch decorator separately (since we can only have 2 char's per decoration)
window.registerFileDecorationProvider({
provideFileDecoration: (uri, token) => {
if (uri.scheme !== 'gitlens-view' || uri.authority !== 'branch') return undefined;
return this.provideBranchCurrentDecoration(uri, token);
},
}),
window.registerFileDecorationProvider(this),
);
}
dispose(): void {
this.disposable.dispose();
}
provideFileDecoration(uri: Uri, token: CancellationToken): FileDecoration | undefined {
if (uri.scheme !== 'gitlens-view') return undefined;
switch (uri.authority) {
case 'branch':
return this.provideBranchStatusDecoration(uri, token);
case 'commit-file':
return this.provideCommitFileStatusDecoration(uri, token);
}
return undefined;
}
provideCommitFileStatusDecoration(uri: Uri, _token: CancellationToken): FileDecoration | undefined {
const [, , status] = uri.path.split('/');
switch (status) {
case '!':
return {
badge: 'I',
color: new ThemeColor('gitDecoration.ignoredResourceForeground'),
tooltip: 'Ignored',
};
case '?':
return {
badge: 'U',
color: new ThemeColor('gitDecoration.untrackedResourceForeground'),
tooltip: 'Untracked',
};
case 'A':
return {
badge: 'A',
color: new ThemeColor('gitDecoration.addedResourceForeground'),
tooltip: 'Added',
};
case 'C':
return {
badge: 'C',
color: new ThemeColor('gitlens.decorations.copiedForegroundColor'),
tooltip: 'Copied',
};
case 'D':
return {
badge: 'D',
color: new ThemeColor('gitDecoration.deletedResourceForeground'),
tooltip: 'Deleted',
};
case 'M':
return {
badge: 'M',
// color: new ThemeColor('gitDecoration.modifiedResourceForeground'),
tooltip: 'Modified',
};
case 'R':
return {
badge: 'R',
color: new ThemeColor('gitlens.decorations.renamedForegroundColor'),
tooltip: 'Renamed',
};
default:
return undefined;
}
}
provideBranchStatusDecoration(uri: Uri, _token: CancellationToken): FileDecoration | undefined {
const [, , status] = uri.path.split('/');
switch (status as GitBranchStatus) {
case GitBranchStatus.Ahead:
return {
badge: '⮝',
color: new ThemeColor('gitlens.decorations.branchAheadForegroundColor'),
tooltip: 'Ahead',
};
case GitBranchStatus.Behind:
return {
badge: '⮟',
color: new ThemeColor('gitlens.decorations.branchBehindForegroundColor'),
tooltip: 'Behind',
};
case GitBranchStatus.Diverged:
return {
badge: '⮟⮝',
color: new ThemeColor('gitlens.decorations.branchDivergedForegroundColor'),
tooltip: 'Diverged',
};
case GitBranchStatus.UpToDate:
return {
badge: '',
color: new ThemeColor('gitlens.decorations.branchUpToDateForegroundColor'),
tooltip: 'Up to Date',
};
case GitBranchStatus.Unpublished:
return {
badge: '⮙+',
color: new ThemeColor('gitlens.decorations.branchUnpublishedForegroundColor'),
tooltip: 'Unpublished',
};
default:
return undefined;
}
}
provideBranchCurrentDecoration(uri: Uri, _token: CancellationToken): FileDecoration | undefined {
const [, , status, current] = uri.path.split('/');
if (!current) return undefined;
let color;
switch (status as GitBranchStatus) {
case GitBranchStatus.Ahead:
color = new ThemeColor('gitlens.decorations.branchAheadForegroundColor');
break;
case GitBranchStatus.Behind:
color = new ThemeColor('gitlens.decorations.branchBehindForegroundColor');
break;
case GitBranchStatus.Diverged:
color = new ThemeColor('gitlens.decorations.branchDivergedForegroundColor');
break;
case GitBranchStatus.UpToDate:
color = new ThemeColor('gitlens.decorations.branchUpToDateForegroundColor');
break;
case GitBranchStatus.Unpublished:
color = new ThemeColor('gitlens.decorations.branchUnpublishedForegroundColor');
break;
}
return {
badge: GlyphChars.Check,
color: color,
tooltip: 'Current Branch',
};
}
}

Loading…
取消
儲存