diff --git a/CHANGELOG.md b/CHANGELOG.md index 23f6664..449e5b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Improves performance - Optimized git output parsing to increase speed and reduce memory usage - Defers diff chunk parsing until it is actually required +- Adds `gitlens.defaultDateFormat` setting to specify how all absolute dates will be formatted by default ### Fixed - Fixes excessive memory usage when parsing diffs diff --git a/README.md b/README.md index c45829d..2755ab1 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,7 @@ GitLens is highly customizable and provides many configuration settings to allow |Name | Description |-----|------------ +|`gitlens.defaultDateFormat`|Specifies how all absolute dates will be formatted by default\nSee https://momentjs.com/docs/#/displaying/format/ for valid formats |`gitlens.insiders`|Opts into the insiders channel -- provides access to upcoming features |`gitlens.outputLevel`|Specifies how much (if any) output will be sent to the GitLens output channel diff --git a/package.json b/package.json index 769aafd..0ec5890 100644 --- a/package.json +++ b/package.json @@ -402,6 +402,11 @@ "default": false, "description": "Specifies whether or not to show debug information in code lens" }, + "gitlens.defaultDateFormat": { + "type": "string", + "default": null, + "description": "Specifies how all absolute dates will be formatted by default\nSee https://momentjs.com/docs/#/displaying/format/ for valid formats" + }, "gitlens.statusBar.enabled": { "type": "boolean", "default": true, diff --git a/src/annotations/annotations.ts b/src/annotations/annotations.ts index 796e1fb..5dfd82d 100644 --- a/src/annotations/annotations.ts +++ b/src/annotations/annotations.ts @@ -59,8 +59,8 @@ export class Annotations { } as DecorationOptions; } - static detailsHover(commit: GitCommit): DecorationOptions { - const message = CommitFormatter.toHoverAnnotation(commit); + static detailsHover(commit: GitCommit, dateFormat: string | null): DecorationOptions { + const message = CommitFormatter.toHoverAnnotation(commit, dateFormat); return { hoverMessage: message } as DecorationOptions; @@ -127,9 +127,9 @@ export class Annotations { } as IRenderOptions; } - static hover(commit: GitCommit, renderOptions: IRenderOptions, heatmap: boolean): DecorationOptions { + static hover(commit: GitCommit, renderOptions: IRenderOptions, heatmap: boolean, dateFormat: string | null): DecorationOptions { return { - hoverMessage: CommitFormatter.toHoverAnnotation(commit), + hoverMessage: CommitFormatter.toHoverAnnotation(commit, dateFormat), renderOptions: heatmap ? { before: { ...renderOptions.before } } : undefined } as DecorationOptions; } diff --git a/src/annotations/gutterBlameAnnotationProvider.ts b/src/annotations/gutterBlameAnnotationProvider.ts index cda5744..ea1185a 100644 --- a/src/annotations/gutterBlameAnnotationProvider.ts +++ b/src/annotations/gutterBlameAnnotationProvider.ts @@ -25,7 +25,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase { }, {} as { [token: string]: ICommitFormatOptions }); const options: ICommitFormatOptions = { - dateFormat: cfg.dateFormat, + dateFormat: cfg.dateFormat === null ? this._config.defaultDateFormat : cfg.dateFormat, tokenOptions: tokenOptions }; @@ -33,6 +33,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase { const offset = this.uri.offset; let previousLine: string | undefined = undefined; const renderOptions = Annotations.gutterRenderOptions(this._config.theme, cfg.heatmap); + const dateFormat = this._config.defaultDateFormat; const decorations: DecorationOptions[] = []; @@ -58,7 +59,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase { decorations.push(gutter); if (cfg.hover.details) { - const details = Annotations.detailsHover(commit); + const details = Annotations.detailsHover(commit, dateFormat); details.range = cfg.hover.wholeLine ? this.editor.document.validateRange(new Range(line, 0, line, endOfLineIndex)) : gutter.range; diff --git a/src/annotations/hoverBlameAnnotationProvider.ts b/src/annotations/hoverBlameAnnotationProvider.ts index 53166b0..d879961 100644 --- a/src/annotations/hoverBlameAnnotationProvider.ts +++ b/src/annotations/hoverBlameAnnotationProvider.ts @@ -18,6 +18,7 @@ export class HoverBlameAnnotationProvider extends BlameAnnotationProviderBase { const now = moment(); const offset = this.uri.offset; const renderOptions = Annotations.hoverRenderOptions(this._config.theme, cfg.heatmap); + const dateFormat = this._config.defaultDateFormat; const decorations: DecorationOptions[] = []; @@ -27,7 +28,7 @@ export class HoverBlameAnnotationProvider extends BlameAnnotationProviderBase { const line = l.line + offset; - const hover = Annotations.hover(commit, renderOptions, cfg.heatmap.enabled); + const hover = Annotations.hover(commit, renderOptions, cfg.heatmap.enabled, dateFormat); const endIndex = cfg.wholeLine ? endOfLineIndex : this.editor.document.lineAt(line).firstNonWhitespaceCharacterIndex; hover.range = this.editor.document.validateRange(new Range(line, 0, line, endIndex)); diff --git a/src/annotations/recentChangesAnnotationProvider.ts b/src/annotations/recentChangesAnnotationProvider.ts index d8de743..005ddae 100644 --- a/src/annotations/recentChangesAnnotationProvider.ts +++ b/src/annotations/recentChangesAnnotationProvider.ts @@ -21,6 +21,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase { if (diff === undefined) return false; const cfg = this._config.annotations.file.recentChanges; + const dateFormat = this._config.defaultDateFormat; const decorators: DecorationOptions[] = []; @@ -42,7 +43,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase { if (cfg.hover.details) { decorators.push({ - hoverMessage: CommitFormatter.toHoverAnnotation(commit), + hoverMessage: CommitFormatter.toHoverAnnotation(commit, dateFormat), range: range } as DecorationOptions); } diff --git a/src/configuration.ts b/src/configuration.ts index 397a967..fe7acc9 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -216,7 +216,7 @@ export interface IConfig { file: { gutter: { format: string; - dateFormat: string; + dateFormat: string | null; compact: boolean; heatmap: { enabled: boolean; @@ -252,7 +252,7 @@ export interface IConfig { trailing: { format: string; - dateFormat: string; + dateFormat: string | null; hover: { changes: boolean; details: boolean; @@ -301,12 +301,14 @@ export interface IConfig { debug: boolean; }; + defaultDateFormat: string | null; + statusBar: { enabled: boolean; alignment: 'left' | 'right'; command: StatusBarCommand; format: string; - dateFormat: string; + dateFormat: string | null; }; strings: { diff --git a/src/currentLineController.ts b/src/currentLineController.ts index c7dd456..c8d880b 100644 --- a/src/currentLineController.ts +++ b/src/currentLineController.ts @@ -291,7 +291,7 @@ export class CurrentLineController extends Disposable { showDetailsInStartingWhitespace = true; } - const decoration = Annotations.trailing(commit, cfgAnnotations.format, cfgAnnotations.dateFormat, this._config.theme); + const decoration = Annotations.trailing(commit, cfgAnnotations.format, cfgAnnotations.dateFormat === null ? this._config.defaultDateFormat : cfgAnnotations.dateFormat, this._config.theme); decoration.range = editor.document.validateRange(new Range(line, endOfLineIndex, line, endOfLineIndex)); decorationOptions.push(decoration); @@ -395,7 +395,7 @@ export class CurrentLineController extends Disposable { // I have no idea why I need this protection -- but it happens if (editor.document === undefined) return; - const decoration = Annotations.detailsHover(logCommit || commit); + const decoration = Annotations.detailsHover(logCommit || commit, this._config.defaultDateFormat); decoration.range = editor.document.validateRange(new Range(line, showDetailsStartIndex, line, endOfLineIndex)); decorationOptions.push(decoration); @@ -429,7 +429,7 @@ export class CurrentLineController extends Disposable { const cfg = this._config.statusBar; if (!cfg.enabled || this._statusBarItem === undefined) return; - this._statusBarItem.text = `$(git-commit) ${CommitFormatter.fromTemplate(cfg.format, commit, cfg.dateFormat)}`; + this._statusBarItem.text = `$(git-commit) ${CommitFormatter.fromTemplate(cfg.format, commit, cfg.dateFormat === null ? this._config.defaultDateFormat : cfg.dateFormat)}`; switch (cfg.command) { case StatusBarCommand.BlameAnnotate: diff --git a/src/git/formatters/commit.ts b/src/git/formatters/commit.ts index e3eeae9..27736ab 100644 --- a/src/git/formatters/commit.ts +++ b/src/git/formatters/commit.ts @@ -158,7 +158,11 @@ export class CommitFormatter { return Strings.interpolate(template, new CommitFormatter(commit, options)); } - static toHoverAnnotation(commit: GitCommit, dateFormat: string = 'MMMM Do, YYYY h:MMa'): string | string[] { + static toHoverAnnotation(commit: GitCommit, dateFormat: string | null): string | string[] { + if (dateFormat === null) { + dateFormat = 'MMMM Do, YYYY h:MMa'; + } + const message = commit.isUncommitted ? '' : `\n\n> ${commit.message.replace(/\n/g, ' \n')}`; return `\`${commit.shortSha}\` __${commit.author}__, ${moment(commit.date).fromNow()} _(${moment(commit.date).format(dateFormat)})_${message}`; } diff --git a/src/gitService.ts b/src/gitService.ts index 0b9dc79..26a6515 100644 --- a/src/gitService.ts +++ b/src/gitService.ts @@ -521,13 +521,14 @@ export class GitService extends Disposable { if (blame === undefined) return undefined; const commitCount = blame.commits.size; + const dateFormat = this.config.defaultDateFormat === null ? 'MMMM Do, YYYY h:MMa' : this.config.defaultDateFormat; const locations: Location[] = []; Iterables.forEach(blame.commits.values(), (c, i) => { if (c.isUncommitted) return; - const decoration = `\u2937 ${c.author}, ${moment(c.date).format('MMMM Do, YYYY h:MMa')}`; - const uri = GitService.toReferenceGitContentUri(c, i + 1, commitCount, c.originalFileName, decoration); + const decoration = `\u2937 ${c.author}, ${moment(c.date).format(dateFormat)}`; + const uri = GitService.toReferenceGitContentUri(c, i + 1, commitCount, c.originalFileName, decoration, dateFormat); locations.push(new Location(uri, new Position(0, 0))); if (c.sha === selectedSha) { locations.push(new Location(uri, new Position((line || 0) + 1, 0))); @@ -858,13 +859,14 @@ export class GitService extends Disposable { if (log === undefined) return undefined; const commitCount = log.commits.size; + const dateFormat = this.config.defaultDateFormat === null ? 'MMMM Do, YYYY h:MMa' : this.config.defaultDateFormat; const locations: Location[] = []; Iterables.forEach(log.commits.values(), (c, i) => { if (c.isUncommitted) return; - const decoration = `\u2937 ${c.author}, ${moment(c.date).format('MMMM Do, YYYY h:MMa')}`; - const uri = GitService.toReferenceGitContentUri(c, i + 1, commitCount, c.originalFileName, decoration); + const decoration = `\u2937 ${c.author}, ${moment(c.date).format(dateFormat)}`; + const uri = GitService.toReferenceGitContentUri(c, i + 1, commitCount, c.originalFileName, decoration, dateFormat); locations.push(new Location(uri, new Position(0, 0))); if (c.sha === selectedSha) { locations.push(new Location(uri, new Position((line || 0) + 1, 0))); @@ -1086,11 +1088,11 @@ export class GitService extends Disposable { return Uri.parse(`${DocumentSchemes.GitLensGit}:${path.basename(fileName!, extension)}:${shortSha}${extension}?${JSON.stringify(data)}`); } - static toReferenceGitContentUri(commit: GitCommit, index: number, commitCount: number, originalFileName?: string, decoration?: string): Uri { - return GitService._toReferenceGitContentUri(commit, DocumentSchemes.GitLensGit, commitCount, GitService._toGitUriData(commit, index, originalFileName, decoration)); + static toReferenceGitContentUri(commit: GitCommit, index: number, commitCount: number, originalFileName: string | undefined, decoration: string, dateFormat: string | null): Uri { + return GitService._toReferenceGitContentUri(commit, DocumentSchemes.GitLensGit, commitCount, GitService._toGitUriData(commit, index, originalFileName, decoration), dateFormat); } - private static _toReferenceGitContentUri(commit: GitCommit, scheme: DocumentSchemes, commitCount: number, data: IGitUriData) { + private static _toReferenceGitContentUri(commit: GitCommit, scheme: DocumentSchemes, commitCount: number, data: IGitUriData, dateFormat: string | null) { const pad = (n: number) => ('0000000' + n).slice(-('' + commitCount).length); const ext = path.extname(data.fileName); const uriPath = `${path.relative(commit.repoPath, data.fileName.slice(0, -ext.length))}/${commit.shortSha}${ext}`; @@ -1100,8 +1102,12 @@ export class GitService extends Disposable { message = message.substring(0, 49) + '\u2026'; } + if (dateFormat === null) { + dateFormat = 'MMMM Do, YYYY h:MMa'; + } + // NOTE: Need to specify an index here, since I can't control the sort order -- just alphabetic or by file location - return Uri.parse(`${scheme}:${pad(data.index || 0)} \u2022 ${encodeURIComponent(message)} \u2022 ${moment(commit.date).format('MMM D, YYYY hh:MMa')} \u2022 ${encodeURIComponent(uriPath)}?${JSON.stringify(data)}`); + return Uri.parse(`${scheme}:${pad(data.index || 0)} \u2022 ${encodeURIComponent(message)} \u2022 ${moment(commit.date).format(dateFormat)} \u2022 ${encodeURIComponent(uriPath)}?${JSON.stringify(data)}`); } private static _toGitUriData<T extends IGitUriData>(commit: IGitUriData, index?: number, originalFileName?: string, decoration?: string): T {