From 5d415b86e895b4441df1f67afe9a382f7c2d91f1 Mon Sep 17 00:00:00 2001 From: Eric Amodio <eamodio@gmail.com> Date: Wed, 28 Feb 2018 01:57:01 -0500 Subject: [PATCH] Adds issue-linking for commit messages in hovers --- CHANGELOG.md | 4 + images/ss-cl-issue-linking.png | Bin 0 -> 10551 bytes src/annotations/annotations.ts | 96 +++++++++++---------- src/annotations/blameAnnotationProvider.ts | 2 +- src/annotations/recentChangesAnnotationProvider.ts | 2 +- src/currentLineController.ts | 2 +- src/git/remotes/bitbucket-server.ts | 17 +++- src/git/remotes/bitbucket.ts | 11 +++ src/git/remotes/github.ts | 11 +++ src/git/remotes/gitlab.ts | 7 ++ src/git/remotes/provider.ts | 6 +- src/git/remotes/visualStudio.ts | 7 ++ 12 files changed, 114 insertions(+), 51 deletions(-) create mode 100644 images/ss-cl-issue-linking.png diff --git a/CHANGELOG.md b/CHANGELOG.md index e818f52..803da69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] ### Added +- Adds issue linking for commit messages in hovers + +  + - Adds multi-cursor support to current line annotations — closes [#291](https://github.com/eamodio/vscode-gitlens/issues/291) - Adds support to toggle annotations for each file individually or for all files at once — closes [#289](https://github.com/eamodio/vscode-gitlens/issues/289) - Adds new controls the interactive settings editor (*Open Settings* from the Command Palette) to configure this new behavior diff --git a/images/ss-cl-issue-linking.png b/images/ss-cl-issue-linking.png new file mode 100644 index 0000000000000000000000000000000000000000..80ff34d70c67ef785e4159067eb50bed7c23c598 GIT binary patch literal 10551 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 MO;5E<`PrNQ1*~!F!T<mO literal 0 HcmV?d00001 diff --git a/src/annotations/annotations.ts b/src/annotations/annotations.ts index f8e0ca6..f2227b9 100644 --- a/src/annotations/annotations.ts +++ b/src/annotations/annotations.ts @@ -4,7 +4,7 @@ import { DiffWithCommand, OpenCommitInRemoteCommand, OpenFileRevisionCommand, Sh import { FileAnnotationType } from './../configuration'; import { GlyphChars } from '../constants'; import { Container } from '../container'; -import { CommitFormatter, GitCommit, GitDiffChunkLine, GitService, GitUri, ICommitFormatOptions } from '../gitService'; +import { CommitFormatter, GitCommit, GitDiffChunkLine, GitRemote, GitService, GitUri, ICommitFormatOptions } from '../gitService'; interface IHeatmapConfig { enabled: boolean; @@ -62,7 +62,7 @@ export class Annotations { return commandBar; } - static getHoverMessage(commit: GitCommit, dateFormat: string | null, hasRemote: boolean, annotationType?: FileAnnotationType, line: number = 0): MarkdownString { + static getHoverMessage(commit: GitCommit, dateFormat: string | null, remotes: GitRemote[], annotationType?: FileAnnotationType, line: number = 0): MarkdownString { if (dateFormat === null) { dateFormat = 'MMMM Do, YYYY h:mma'; } @@ -71,10 +71,18 @@ export class Annotations { let commandBar = ''; let showCommitDetailsCommand = ''; if (!commit.isUncommitted) { - commandBar = `\n\n${this.getHoverCommandBar(commit, hasRemote, annotationType, line)}`; + commandBar = `\n\n${this.getHoverCommandBar(commit, remotes.length !== 0, annotationType, line)}`; showCommitDetailsCommand = `[\`${commit.shortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(commit.sha)} "Show Commit Details")`; - message = commit.message + message = commit.message; + for (const r of remotes) { + if (r.provider === undefined) continue; + + message = r.provider.enrichMessage(message); + break; + } + + message // Escape markdown .replace(escapeMarkdownRegEx, '\\$&') // Escape markdown header (since the above regex won't match it) @@ -135,12 +143,12 @@ export class Annotations { } as DecorationOptions; } - static detailsHover(commit: GitCommit, dateFormat: string | null, hasRemote: boolean, annotationType?: FileAnnotationType, line: number = 0): DecorationOptions { - const message = this.getHoverMessage(commit, dateFormat, hasRemote, annotationType); - return { - hoverMessage: message - } as DecorationOptions; - } + // static detailsHover(commit: GitCommit, dateFormat: string | null, hasRemote: boolean, annotationType?: FileAnnotationType, line: number = 0): DecorationOptions { + // const message = this.getHoverMessage(commit, dateFormat, hasRemote, annotationType); + // return { + // hoverMessage: message + // } as DecorationOptions; + // } static gutter(commit: GitCommit, format: string, dateFormatOrFormatOptions: string | null | ICommitFormatOptions, renderOptions: IRenderOptions): DecorationOptions { const decoration = { @@ -227,28 +235,28 @@ export class Annotations { } as IRenderOptions; } - static hover(commit: GitCommit, renderOptions: IRenderOptions, now: number): DecorationOptions { - const decoration = { - renderOptions: { before: { ...renderOptions } } - } as DecorationOptions; + // static hover(commit: GitCommit, renderOptions: IRenderOptions, now: number): DecorationOptions { + // const decoration = { + // renderOptions: { before: { ...renderOptions } } + // } as DecorationOptions; - this.applyHeatmap(decoration, commit.date, now); + // this.applyHeatmap(decoration, commit.date, now); - return decoration; - } + // return decoration; + // } - static hoverRenderOptions(heatmap: IHeatmapConfig): IRenderOptions { - if (!heatmap.enabled) return { before: undefined }; + // static hoverRenderOptions(heatmap: IHeatmapConfig): IRenderOptions { + // if (!heatmap.enabled) return { before: undefined }; - return { - borderStyle: 'solid', - borderWidth: '0 0 0 2px', - contentText: GlyphChars.ZeroWidthSpace, - height: '100%', - margin: '0 26px 0 0', - textDecoration: 'none' - } as IRenderOptions; - } + // return { + // borderStyle: 'solid', + // borderWidth: '0 0 0 2px', + // contentText: GlyphChars.ZeroWidthSpace, + // height: '100%', + // margin: '0 26px 0 0', + // textDecoration: 'none' + // } as IRenderOptions; + // } static trailing(commit: GitCommit, format: string, dateFormat: string | null): DecorationOptions { const message = CommitFormatter.fromTemplate(format, commit, { @@ -269,20 +277,20 @@ export class Annotations { } as DecorationOptions; } - static withRange(decoration: DecorationOptions, start?: number, end?: number): DecorationOptions { - let range = decoration.range; - if (start !== undefined) { - range = range.with({ - start: range.start.with({ character: start }) - }); - } - - if (end !== undefined) { - range = range.with({ - end: range.end.with({ character: end }) - }); - } - - return { ...decoration, range: range }; - } + // static withRange(decoration: DecorationOptions, start?: number, end?: number): DecorationOptions { + // let range = decoration.range; + // if (start !== undefined) { + // range = range.with({ + // start: range.start.with({ character: start }) + // }); + // } + + // if (end !== undefined) { + // range = range.with({ + // end: range.end.with({ character: end }) + // }); + // } + + // return { ...decoration, range: range }; + // } } \ No newline at end of file diff --git a/src/annotations/blameAnnotationProvider.ts b/src/annotations/blameAnnotationProvider.ts index 06d828b..f5ed56b 100644 --- a/src/annotations/blameAnnotationProvider.ts +++ b/src/annotations/blameAnnotationProvider.ts @@ -121,7 +121,7 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase } } - const message = Annotations.getHoverMessage(logCommit || commit, Container.config.defaultDateFormat, await Container.git.hasRemote(commit.repoPath), this.annotationType, this.editor.selection.active.line); + const message = Annotations.getHoverMessage(logCommit || commit, Container.config.defaultDateFormat, await Container.git.getRemotes(commit.repoPath), this.annotationType, this.editor.selection.active.line); return new Hover(message, document.validateRange(new Range(position.line, 0, position.line, RangeEndOfLineIndex))); } diff --git a/src/annotations/recentChangesAnnotationProvider.ts b/src/annotations/recentChangesAnnotationProvider.ts index 22aa342..38d1739 100644 --- a/src/annotations/recentChangesAnnotationProvider.ts +++ b/src/annotations/recentChangesAnnotationProvider.ts @@ -56,7 +56,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase { if (cfg.hovers.enabled && cfg.hovers.annotations.enabled) { if (cfg.hovers.annotations.details) { this.decorations.push({ - hoverMessage: Annotations.getHoverMessage(commit, dateFormat, await Container.git.hasRemote(commit.repoPath), this.annotationType, this.editor.selection.active.line), + hoverMessage: Annotations.getHoverMessage(commit, dateFormat, await Container.git.getRemotes(commit.repoPath), this.annotationType, this.editor.selection.active.line), range: range } as DecorationOptions); } diff --git a/src/currentLineController.ts b/src/currentLineController.ts index 46d566c..d43973f 100644 --- a/src/currentLineController.ts +++ b/src/currentLineController.ts @@ -263,7 +263,7 @@ export class CurrentLineController extends Disposable { const trackedDocument = await Container.tracker.get(document); if (trackedDocument === undefined) return undefined; - const message = Annotations.getHoverMessage(logCommit || commit, Container.config.defaultDateFormat, trackedDocument.hasRemotes, fileAnnotations, position.line); + const message = Annotations.getHoverMessage(logCommit || commit, Container.config.defaultDateFormat, await Container.git.getRemotes(commit.repoPath), fileAnnotations, position.line); return new Hover(message, range); } diff --git a/src/git/remotes/bitbucket-server.ts b/src/git/remotes/bitbucket-server.ts index 663f4a7..e18871b 100644 --- a/src/git/remotes/bitbucket-server.ts +++ b/src/git/remotes/bitbucket-server.ts @@ -2,6 +2,9 @@ import { Range } from 'vscode'; import { RemoteProvider } from './provider'; +const issueEnricherRegEx = /(^|\s)(issue #([0-9]+))\b/gi; +const prEnricherRegEx = /(^|\s)(pull request #([0-9]+))\b/gi; + export class BitbucketServerService extends RemoteProvider { constructor( @@ -14,13 +17,21 @@ export class BitbucketServerService extends RemoteProvider { super(domain, path, protocol, name, custom); } + protected get baseUrl() { + const [project, repo] = this.splitPath(); + return `https://${this.domain}/projects/${project}/repos/${repo}`; + } + get name() { return this.formatName('Bitbucket Server'); } - protected get baseUrl() { - const [project, repo] = this.splitPath(); - return `https://${this.domain}/projects/${project}/repos/${repo}`; + enrichMessage(message: string): string { + return message + // Matches issue #123 + .replace(issueEnricherRegEx, `$1[$2](${this.baseUrl}/issues/$3 "Open Issue $2")`) + // Matches pull request #123 + .replace(prEnricherRegEx, `$1[$2](${this.baseUrl}/pull-requests/$3 "Open PR $2")`); } protected getUrlForBranches(): string { diff --git a/src/git/remotes/bitbucket.ts b/src/git/remotes/bitbucket.ts index 1e863b7..21e543b 100644 --- a/src/git/remotes/bitbucket.ts +++ b/src/git/remotes/bitbucket.ts @@ -2,6 +2,9 @@ import { Range } from 'vscode'; import { RemoteProvider } from './provider'; +const issueEnricherRegEx = /(^|\s)(issue #([0-9]+))\b/gi; +const prEnricherRegEx = /(^|\s)(pull request #([0-9]+))\b/gi; + export class BitbucketService extends RemoteProvider { constructor( @@ -18,6 +21,14 @@ export class BitbucketService extends RemoteProvider { return this.formatName('Bitbucket'); } + enrichMessage(message: string): string { + return message + // Matches issue #123 + .replace(issueEnricherRegEx, `$1[$2](${this.baseUrl}/issues/$3 "Open Issue $2")`) + // Matches pull request #123 + .replace(prEnricherRegEx, `$1[$2](${this.baseUrl}/pull-requests/$3 "Open PR $2")`); + } + protected getUrlForBranches(): string { return `${this.baseUrl}/branches`; } diff --git a/src/git/remotes/github.ts b/src/git/remotes/github.ts index 5624468..23becee 100644 --- a/src/git/remotes/github.ts +++ b/src/git/remotes/github.ts @@ -2,6 +2,9 @@ import { Range } from 'vscode'; import { RemoteProvider } from './provider'; +const issueEnricherRegEx = /(^|\s)((?:#|gh-)([0-9]+))\b/gi; +const issueEnricher3rdParyRegEx = /\b((\w+-?\w+(?!-)\/\w+-?\w+(?!-))#([0-9]+))\b/g; + export class GitHubService extends RemoteProvider { constructor( @@ -18,6 +21,14 @@ export class GitHubService extends RemoteProvider { return this.formatName('GitHub'); } + enrichMessage(message: string): string { + return message + // Matches #123 or gh-123 or GH-123 + .replace(issueEnricherRegEx, `$1[$2](${this.baseUrl}/issues/$3 "Open Issue $2")`) + // Matches eamodio/vscode-gitlens#123 + .replace(issueEnricher3rdParyRegEx, `[$1](${this.protocol}://${this.domain}/$2/issues/$3 "Open Issue #$3 from $2")`); + } + protected getUrlForBranches(): string { return `${this.baseUrl}/branches`; } diff --git a/src/git/remotes/gitlab.ts b/src/git/remotes/gitlab.ts index af4f187..6cc1c2c 100644 --- a/src/git/remotes/gitlab.ts +++ b/src/git/remotes/gitlab.ts @@ -2,6 +2,8 @@ import { Range } from 'vscode'; import { RemoteProvider } from './provider'; +const issueEnricherRegEx = /(^|\s)(#([0-9]+))\b/gi; + export class GitLabService extends RemoteProvider { constructor( @@ -18,6 +20,11 @@ export class GitLabService extends RemoteProvider { return this.formatName('GitLab'); } + enrichMessage(message: string): string { + // Matches #123 + return message.replace(issueEnricherRegEx, `$1[$2](${this.baseUrl}/issues/$3 "Open Issue $2")`); + } + protected getUrlForBranches(): string { return `${this.baseUrl}/branches`; } diff --git a/src/git/remotes/provider.ts b/src/git/remotes/provider.ts index 1495a6d..e8830ce 100644 --- a/src/git/remotes/provider.ts +++ b/src/git/remotes/provider.ts @@ -39,7 +39,7 @@ export abstract class RemoteProvider { constructor( public readonly domain: string, public readonly path: string, - private readonly protocol: string = 'https', + public readonly protocol: string = 'https', name?: string, public readonly custom: boolean = false ) { @@ -52,6 +52,10 @@ export abstract class RemoteProvider { return `${this.protocol}://${this.domain}/${this.path}`; } + enrichMessage(message: string): string { + return message; + } + protected formatName(name: string) { if (this._name !== undefined) return this._name; return `${name}${this.custom ? ` (${this.domain})` : ''}`; diff --git a/src/git/remotes/visualStudio.ts b/src/git/remotes/visualStudio.ts index 1f48ac9..e588e4c 100644 --- a/src/git/remotes/visualStudio.ts +++ b/src/git/remotes/visualStudio.ts @@ -2,6 +2,8 @@ import { Range } from 'vscode'; import { RemoteProvider } from './provider'; +const issueEnricherRegEx = /(^|\s)(#([0-9]+))\b/gi; + export class VisualStudioService extends RemoteProvider { constructor( @@ -17,6 +19,11 @@ export class VisualStudioService extends RemoteProvider { return 'Visual Studio Team Services'; } + enrichMessage(message: string): string { + // Matches #123 + return message.replace(issueEnricherRegEx, `$1[$2](${this.baseUrl}/_workitems/edit/$3 "Open Work Item $2")`); + } + protected getUrlForBranches(): string { return `${this.baseUrl}/branches`; }