Browse Source

Remove date formatter

Since we are using native date formatting the formatter abstraction is no longer needed
main
Eric Amodio 2 years ago
parent
commit
f107ef29d9
16 changed files with 253 additions and 380 deletions
  1. +19
    -17
      src/annotations/autolinks.ts
  2. +5
    -10
      src/commands/git/fetch.ts
  3. +10
    -16
      src/commands/git/pull.ts
  4. +15
    -28
      src/commands/git/push.ts
  5. +8
    -10
      src/git/models/branch.ts
  6. +12
    -36
      src/git/models/commit.ts
  7. +7
    -14
      src/git/models/contributor.ts
  8. +14
    -45
      src/git/models/pullRequest.ts
  9. +3
    -11
      src/git/models/reflog.ts
  10. +5
    -5
      src/git/models/repository.ts
  11. +9
    -31
      src/git/models/tag.ts
  12. +27
    -32
      src/quickpicks/gitQuickPickItems.ts
  13. +94
    -97
      src/system/date.ts
  14. +4
    -4
      src/views/nodes/autolinkedItemNode.ts
  15. +17
    -20
      src/views/nodes/branchTrackingStatusNode.ts
  16. +4
    -4
      src/webviews/apps/shared/appWithConfigBase.ts

+ 19
- 17
src/annotations/autolinks.ts View File

@ -4,8 +4,12 @@ import { GlyphChars } from '../constants';
import { Container } from '../container';
import { GitRemote, IssueOrPullRequest } from '../git/models';
import { Logger } from '../logger';
import { Dates, debug, Encoding, Iterables, Strings } from '../system';
import { fromNow } from '../system/date';
import { debug } from '../system/decorators/log';
import { encodeUrl } from '../system/encoding';
import { every, join, map } from '../system/iterable';
import { PromiseCancelledError, raceAll } from '../system/promise';
import { escapeMarkdown, escapeRegex, getSuperscript } from '../system/string';
const numRegex = /<num>/g;
@ -70,9 +74,7 @@ export class Autolinks implements Disposable {
if (ref.messageRegex === undefined) {
ref.messageRegex = new RegExp(
`(?<=^|\\s|\\(|\\\\\\[)(${Strings.escapeRegex(ref.prefix)}([${
ref.alphanumeric ? '\\w' : '0-9'
}]+))\\b`,
`(?<=^|\\s|\\(|\\\\\\[)(${escapeRegex(ref.prefix)}([${ref.alphanumeric ? '\\w' : '0-9'}]+))\\b`,
ref.ignoreCase ? 'gi' : 'g',
);
}
@ -90,7 +92,7 @@ export class Autolinks implements Disposable {
if (ids.size === 0) return undefined;
const issuesOrPullRequests = await raceAll(ids.values(), id => provider.getIssueOrPullRequest(id), timeout);
if (issuesOrPullRequests.size === 0 || Iterables.every(issuesOrPullRequests.values(), pr => pr === undefined)) {
if (issuesOrPullRequests.size === 0 || every(issuesOrPullRequests.values(), pr => pr === undefined)) {
return undefined;
}
@ -146,7 +148,7 @@ export class Autolinks implements Disposable {
try {
if (ref.messageMarkdownRegex === undefined) {
ref.messageMarkdownRegex = new RegExp(
`(?<=^|\\s|\\(|\\\\\\[)(${Strings.escapeRegex(Strings.escapeMarkdown(ref.prefix))}([${
`(?<=^|\\s|\\(|\\\\\\[)(${escapeRegex(escapeMarkdown(ref.prefix))}([${
ref.alphanumeric ? '\\w' : '0-9'
}]+))\\b`,
ref.ignoreCase ? 'gi' : 'g',
@ -154,7 +156,7 @@ export class Autolinks implements Disposable {
}
if (issuesOrPullRequests == null || issuesOrPullRequests.size === 0) {
const replacement = `[$1](${Encoding.encodeUrl(ref.url.replace(numRegex, '$2'))}${
const replacement = `[$1](${encodeUrl(ref.url.replace(numRegex, '$2'))}${
ref.title ? ` "${ref.title.replace(numRegex, '$2')}"` : ''
})`;
ref.linkify = (text: string, markdown: boolean) =>
@ -171,7 +173,7 @@ export class Autolinks implements Disposable {
return text.replace(ref.messageMarkdownRegex!, (_substring, linkText, num) => {
const issue = issuesOrPullRequests?.get(num);
const issueUrl = Encoding.encodeUrl(ref.url.replace(numRegex, num));
const issueUrl = encodeUrl(ref.url.replace(numRegex, num));
let title = '';
if (ref.title) {
@ -191,15 +193,15 @@ export class Autolinks implements Disposable {
issue,
)} [**${issueTitle}**](${issueUrl}${title}")\\\n${GlyphChars.Space.repeat(
5,
)}${linkText} ${issue.closed ? 'closed' : 'opened'} ${Dates.getFormatter(
)}${linkText} ${issue.closed ? 'closed' : 'opened'} ${fromNow(
issue.closedDate ?? issue.date,
).fromNow()}`,
)}`,
);
}
title += `\n${GlyphChars.Dash.repeat(2)}\n${issueTitle}\n${
issue.closed ? 'Closed' : 'Opened'
}, ${Dates.getFormatter(issue.closedDate ?? issue.date).fromNow()}`;
}, ${fromNow(issue.closedDate ?? issue.date)}`;
}
}
title += '"';
@ -223,17 +225,17 @@ export class Autolinks implements Disposable {
`${linkText}: ${
issue instanceof PromiseCancelledError
? 'Details timed out'
: `${issue.title} ${GlyphChars.Dot} ${
issue.closed ? 'Closed' : 'Opened'
}, ${Dates.getFormatter(issue.closedDate ?? issue.date).fromNow()}`
: `${issue.title} ${GlyphChars.Dot} ${issue.closed ? 'Closed' : 'Opened'}, ${fromNow(
issue.closedDate ?? issue.date,
)}`
}`,
);
return `${linkText}${Strings.getSuperscript(index)}`;
return `${linkText}${getSuperscript(index)}`;
});
return includeFootnotes && footnotes != null && footnotes.size !== 0
? `${text}\n${GlyphChars.Dash.repeat(2)}\n${Iterables.join(
Iterables.map(footnotes, ([i, footnote]) => `${Strings.getSuperscript(i)} ${footnote}`),
? `${text}\n${GlyphChars.Dash.repeat(2)}\n${join(
map(footnotes, ([i, footnote]) => `${getSuperscript(i)} ${footnote}`),
'\n',
)}`
: text;

+ 5
- 10
src/commands/git/fetch.ts View File

@ -2,7 +2,9 @@ import { GlyphChars } from '../../constants';
import { Container } from '../../container';
import { GitBranchReference, GitReference, Repository } from '../../git/models';
import { FlagsQuickPickItem } from '../../quickpicks';
import { Arrays, Dates, Strings } from '../../system';
import { isStringArray } from '../../system/array';
import { fromNow } from '../../system/date';
import { pad } from '../../system/string';
import { ViewsWithRepositoryFolders } from '../../views/viewBase';
import {
appendReposToTitle,
@ -86,12 +88,7 @@ export class FetchGitCommand extends QuickCommand {
while (this.canStepsContinue(state)) {
context.title = this.title;
if (
state.counter < 1 ||
state.repos == null ||
state.repos.length === 0 ||
Arrays.isStringArray(state.repos)
) {
if (state.counter < 1 || state.repos == null || state.repos.length === 0 || isStringArray(state.repos)) {
skippedStepOne = false;
if (context.repos.length === 1) {
skippedStepOne = true;
@ -137,9 +134,7 @@ export class FetchGitCommand extends QuickCommand {
if (state.repos.length === 1) {
const lastFetched = await state.repos[0].getLastFetched();
if (lastFetched !== 0) {
lastFetchedOn = `${Strings.pad(GlyphChars.Dot, 2, 2)}Last fetched ${Dates.getFormatter(
new Date(lastFetched),
).fromNow()}`;
lastFetchedOn = `${pad(GlyphChars.Dot, 2, 2)}Last fetched ${fromNow(new Date(lastFetched))}`;
}
}

+ 10
- 16
src/commands/git/pull.ts View File

@ -2,7 +2,9 @@ import { GlyphChars } from '../../constants';
import { Container } from '../../container';
import { GitBranch, GitBranchReference, GitReference, Repository } from '../../git/models';
import { Directive, DirectiveQuickPickItem, FlagsQuickPickItem } from '../../quickpicks';
import { Arrays, Dates, Strings } from '../../system';
import { isStringArray } from '../../system/array';
import { fromNow } from '../../system/date';
import { pad, pluralize } from '../../system/string';
import { ViewsWithRepositoryFolders } from '../../views/viewBase';
import {
appendReposToTitle,
@ -92,12 +94,7 @@ export class PullGitCommand extends QuickCommand {
while (this.canStepsContinue(state)) {
context.title = this.title;
if (
state.counter < 1 ||
state.repos == null ||
state.repos.length === 0 ||
Arrays.isStringArray(state.repos)
) {
if (state.counter < 1 || state.repos == null || state.repos.length === 0 || isStringArray(state.repos)) {
skippedStepOne = false;
if (context.repos.length === 1) {
skippedStepOne = true;
@ -182,10 +179,9 @@ export class PullGitCommand extends QuickCommand {
label: this.title,
detail: `Will pull${
branch.state.behind
? ` ${Strings.pluralize(
'commit',
branch.state.behind,
)} into ${GitReference.toString(branch)}`
? ` ${pluralize('commit', branch.state.behind)} into ${GitReference.toString(
branch,
)}`
: ` into ${GitReference.toString(branch)}`
}`,
}),
@ -198,14 +194,12 @@ export class PullGitCommand extends QuickCommand {
let lastFetchedOn = '';
if (lastFetched !== 0) {
lastFetchedOn = `${Strings.pad(GlyphChars.Dot, 2, 2)}Last fetched ${Dates.getFormatter(
new Date(lastFetched),
).fromNow()}`;
lastFetchedOn = `${pad(GlyphChars.Dot, 2, 2)}Last fetched ${fromNow(new Date(lastFetched))}`;
}
const pullDetails =
status?.state.behind != null
? ` ${Strings.pluralize('commit', status.state.behind)} into $(repo) ${repo.formattedName}`
? ` ${pluralize('commit', status.state.behind)} into $(repo) ${repo.formattedName}`
: ` into $(repo) ${repo.formattedName}`;
step = this.createConfirmStep(
@ -227,7 +221,7 @@ export class PullGitCommand extends QuickCommand {
onDidClickButton: async (quickpick, button) => {
if (button !== QuickCommandButtons.Fetch || quickpick.busy) return false;
quickpick.title = `Confirm ${context.title}${Strings.pad(GlyphChars.Dot, 2, 2)}Fetching${
quickpick.title = `Confirm ${context.title}${pad(GlyphChars.Dot, 2, 2)}Fetching${
GlyphChars.Ellipsis
}`;

+ 15
- 28
src/commands/git/push.ts View File

@ -3,7 +3,9 @@ import { BuiltInGitConfiguration, GlyphChars } from '../../constants';
import { Container } from '../../container';
import { GitBranch, GitBranchReference, GitReference, Repository } from '../../git/models';
import { Directive, DirectiveQuickPickItem, FlagsQuickPickItem } from '../../quickpicks';
import { Arrays, Dates, Strings } from '../../system';
import { isStringArray } from '../../system/array';
import { fromNow } from '../../system/date';
import { pad, pluralize } from '../../system/string';
import { ViewsWithRepositoryFolders } from '../../views/viewBase';
import {
appendReposToTitle,
@ -98,12 +100,7 @@ export class PushGitCommand extends QuickCommand {
while (this.canStepsContinue(state)) {
context.title = this.title;
if (
state.counter < 1 ||
state.repos == null ||
state.repos.length === 0 ||
Arrays.isStringArray(state.repos)
) {
if (state.counter < 1 || state.repos == null || state.repos.length === 0 || isStringArray(state.repos)) {
skippedStepOne = false;
if (context.repos.length === 1) {
skippedStepOne = true;
@ -233,15 +230,10 @@ export class PushGitCommand extends QuickCommand {
label: `Force ${this.title}${useForceWithLease ? ' (with lease)' : ''}`,
description: `--force${useForceWithLease ? '-with-lease' : ''}`,
detail: `Will force push${useForceWithLease ? ' (with lease)' : ''} ${
branch?.state.ahead
? ` ${Strings.pluralize('commit', branch.state.ahead)}`
: ''
branch?.state.ahead ? ` ${pluralize('commit', branch.state.ahead)}` : ''
}${branch.getRemoteName() ? ` to ${branch.getRemoteName()}` : ''}${
branch != null && branch.state.behind > 0
? `, overwriting ${Strings.pluralize(
'commit',
branch.state.behind,
)}${
? `, overwriting ${pluralize('commit', branch.state.behind)}${
branch?.getRemoteName()
? ` on ${branch.getRemoteName()}`
: ''
@ -255,17 +247,14 @@ export class PushGitCommand extends QuickCommand {
label: `Cancel ${this.title}`,
detail: `Cannot push; ${GitReference.toString(
branch,
)} is behind ${branch.getRemoteName()} by ${Strings.pluralize(
'commit',
branch.state.behind,
)}`,
)} is behind ${branch.getRemoteName()} by ${pluralize('commit', branch.state.behind)}`,
}),
);
} else if (branch != null && branch?.state.ahead > 0) {
step = this.createConfirmStep(appendReposToTitle(`Confirm ${context.title}`, state, context), [
FlagsQuickPickItem.create<Flags>(state.flags, [branch.getRemoteName()!], {
label: this.title,
detail: `Will push ${Strings.pluralize(
detail: `Will push ${pluralize(
'commit',
branch.state.ahead,
)} from ${GitReference.toString(branch)} to ${branch.getRemoteName()}`,
@ -343,9 +332,7 @@ export class PushGitCommand extends QuickCommand {
const lastFetched = await repo.getLastFetched();
if (lastFetched !== 0) {
lastFetchedOn = `${Strings.pad(GlyphChars.Dot, 2, 2)}Last fetched ${Dates.getFormatter(
new Date(lastFetched),
).fromNow()}`;
lastFetchedOn = `${pad(GlyphChars.Dot, 2, 2)}Last fetched ${fromNow(new Date(lastFetched))}`;
}
let pushDetails;
@ -358,9 +345,9 @@ export class PushGitCommand extends QuickCommand {
: ''
}${status?.upstream ? ` to ${GitBranch.getRemote(status.upstream)}` : ''}`;
} else {
pushDetails = `${
status?.state.ahead ? ` ${Strings.pluralize('commit', status.state.ahead)}` : ''
}${status?.upstream ? ` to ${GitBranch.getRemote(status.upstream)}` : ''}`;
pushDetails = `${status?.state.ahead ? ` ${pluralize('commit', status.state.ahead)}` : ''}${
status?.upstream ? ` to ${GitBranch.getRemote(status.upstream)}` : ''
}`;
}
step = this.createConfirmStep(
@ -379,7 +366,7 @@ export class PushGitCommand extends QuickCommand {
description: `--force${useForceWithLease ? '-with-lease' : ''}`,
detail: `Will force push${useForceWithLease ? ' (with lease)' : ''} ${pushDetails}${
status != null && status.state.behind > 0
? `, overwriting ${Strings.pluralize('commit', status.state.behind)}${
? `, overwriting ${pluralize('commit', status.state.behind)}${
status?.upstream ? ` on ${GitBranch.getRemote(status.upstream)}` : ''
}`
: ''
@ -391,7 +378,7 @@ export class PushGitCommand extends QuickCommand {
label: `Cancel ${this.title}`,
detail: `Cannot push; ${GitReference.toString(branch)} is behind${
status?.upstream ? ` ${GitBranch.getRemote(status.upstream)}` : ''
} by ${Strings.pluralize('commit', status.state.behind)}`,
} by ${pluralize('commit', status.state.behind)}`,
})
: undefined,
);
@ -400,7 +387,7 @@ export class PushGitCommand extends QuickCommand {
step.onDidClickButton = async (quickpick, button) => {
if (button !== QuickCommandButtons.Fetch || quickpick.busy) return false;
quickpick.title = `Confirm ${context.title}${Strings.pad(GlyphChars.Dot, 2, 2)}Fetching${
quickpick.title = `Confirm ${context.title}${pad(GlyphChars.Dot, 2, 2)}Fetching${
GlyphChars.Ellipsis
}`;

+ 8
- 10
src/git/models/branch.ts View File

@ -1,7 +1,10 @@
import { BranchSorting, configuration, DateStyle } from '../../configuration';
import { Starred, WorkspaceState } from '../../constants';
import { Container } from '../../container';
import { Dates, debug, memoize, Strings } from '../../system';
import { formatDate, fromNow } from '../../system/date';
import { debug } from '../../system/decorators/log';
import { memoize } from '../../system/decorators/memoize';
import { sortCompare } from '../../system/string';
import { GitBranchReference, GitReference, GitRevision } from '../models';
import { PullRequest, PullRequestState } from './pullRequest';
import { GitRemote } from './remote';
@ -78,7 +81,7 @@ export class GitBranch implements GitBranchReference {
(a.name === 'master' ? -1 : 1) - (b.name === 'master' ? -1 : 1) ||
(a.name === 'develop' ? -1 : 1) - (b.name === 'develop' ? -1 : 1) ||
(b.remote ? -1 : 1) - (a.remote ? -1 : 1) ||
Strings.sortCompare(a.name, b.name),
sortCompare(a.name, b.name),
);
case BranchSorting.NameDesc:
return branches.sort(
@ -92,7 +95,7 @@ export class GitBranch implements GitBranchReference {
(a.name === 'master' ? -1 : 1) - (b.name === 'master' ? -1 : 1) ||
(a.name === 'develop' ? -1 : 1) - (b.name === 'develop' ? -1 : 1) ||
(b.remote ? -1 : 1) - (a.remote ? -1 : 1) ||
Strings.sortCompare(b.name, a.name),
sortCompare(b.name, a.name),
);
case BranchSorting.DateDesc:
default:
@ -152,22 +155,17 @@ export class GitBranch implements GitBranchReference {
return this.detached ? this.sha! : this.name;
}
@memoize()
private get dateFormatter(): Dates.DateFormatter | undefined {
return this.date == null ? undefined : Dates.getFormatter(this.date);
}
@memoize<GitBranch['formatDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatDate(format?: string | null): string {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.dateFormatter?.format(format) ?? '';
return this.date != null ? formatDate(this.date, format) : '';
}
formatDateFromNow(): string {
return this.dateFormatter?.fromNow() ?? '';
return this.date != null ? fromNow(this.date) : '';
}
@debug()

+ 12
- 36
src/git/models/commit.ts View File

@ -2,7 +2,8 @@ import { Uri } from 'vscode';
import { getAvatarUri } from '../../avatars';
import { configuration, DateSource, DateStyle, GravatarDefaultStyle } from '../../configuration';
import { Container } from '../../container';
import { Dates, memoize } from '../../system';
import { formatDate, fromNow } from '../../system/date';
import { memoize } from '../../system/decorators/memoize';
import { CommitFormatter } from '../formatters';
import { GitUri } from '../gitUri';
import { GitReference, GitRevision, GitRevisionReference, PullRequest } from '../models';
@ -173,59 +174,34 @@ export abstract class GitCommit implements GitRevisionReference {
return Container.instance.git.getWorkingUri(this.repoPath, this.uri);
}
@memoize()
private get authorDateFormatter(): Dates.DateFormatter {
return Dates.getFormatter(this.authorDate);
}
@memoize()
private get committerDateFormatter(): Dates.DateFormatter {
return Dates.getFormatter(this.committerDate);
}
private get dateFormatter(): Dates.DateFormatter {
return CommitDateFormatting.dateSource === DateSource.Committed
? this.committerDateFormatter
: this.authorDateFormatter;
}
@memoize<GitCommit['formatAuthorDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatAuthorDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.authorDateFormatter.format(format);
return formatDate(this.authorDate, format ?? 'MMMM Do, YYYY h:mma');
}
formatAuthorDateFromNow(short?: boolean) {
return this.authorDateFormatter.fromNow(short);
return fromNow(this.authorDate, short);
}
@memoize<GitCommit['formatCommitterDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatCommitterDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.committerDateFormatter.format(format);
return formatDate(this.committerDate, format ?? 'MMMM Do, YYYY h:mma');
}
formatCommitterDateFromNow(short?: boolean) {
return this.committerDateFormatter.fromNow(short);
return fromNow(this.committerDate, short);
}
@memoize<GitCommit['formatDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.dateFormatter.format(format);
return CommitDateFormatting.dateSource === DateSource.Committed
? this.formatCommitterDate(format)
: this.formatAuthorDate(format);
}
formatDateFromNow(short?: boolean) {
return this.dateFormatter.fromNow(short);
return CommitDateFormatting.dateSource === DateSource.Committed
? this.formatCommitterDateFromNow(short)
: this.formatAuthorDateFromNow(short);
}
getFormattedPath(options: { relativeTo?: string; suffix?: string; truncateTo?: number } = {}): string {

+ 7
- 14
src/git/models/contributor.ts View File

@ -1,7 +1,9 @@
import { Uri } from 'vscode';
import { getAvatarUri } from '../../avatars';
import { configuration, ContributorSorting, GravatarDefaultStyle } from '../../configuration';
import { Dates, memoize, Strings } from '../../system';
import { formatDate, fromNow } from '../../system/date';
import { memoize } from '../../system/decorators/memoize';
import { sortCompare } from '../../system/string';
export interface ContributorSortOptions {
current?: true;
@ -40,11 +42,11 @@ export class GitContributor {
);
case ContributorSorting.NameAsc:
return contributors.sort(
(a, b) => (a.current ? -1 : 1) - (b.current ? -1 : 1) || Strings.sortCompare(a.name, b.name),
(a, b) => (a.current ? -1 : 1) - (b.current ? -1 : 1) || sortCompare(a.name, b.name),
);
case ContributorSorting.NameDesc:
return contributors.sort(
(a, b) => (a.current ? -1 : 1) - (b.current ? -1 : 1) || Strings.sortCompare(b.name, a.name),
(a, b) => (a.current ? -1 : 1) - (b.current ? -1 : 1) || sortCompare(b.name, a.name),
);
case ContributorSorting.CountDesc:
default:
@ -71,22 +73,13 @@ export class GitContributor {
public readonly current: boolean = false,
) {}
@memoize()
private get dateFormatter(): Dates.DateFormatter {
return Dates.getFormatter(this.date);
}
@memoize<GitContributor['formatDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.dateFormatter.format(format);
return formatDate(this.date, format ?? 'MMMM Do, YYYY h:mma');
}
formatDateFromNow(short?: boolean) {
return this.dateFormatter.fromNow(short);
return fromNow(this.date, short);
}
getAvatarUri(options?: { defaultStyle?: GravatarDefaultStyle; size?: number }): Uri | Promise<Uri> {

+ 14
- 45
src/git/models/pullRequest.ts View File

@ -1,7 +1,8 @@
import { ColorThemeKind, ThemeColor, ThemeIcon, window } from 'vscode';
import { configuration, DateStyle } from '../../configuration';
import { Colors } from '../../constants';
import { Dates, memoize } from '../../system';
import { formatDate, fromNow } from '../../system/date';
import { memoize } from '../../system/decorators/memoize';
import { RemoteProviderReference } from './remoteProvider';
export const PullRequestDateFormatting = {
@ -79,75 +80,43 @@ export class PullRequest {
: this.formatDateFromNow();
}
@memoize()
private get dateFormatter(): Dates.DateFormatter {
return Dates.getFormatter(this.mergedDate ?? this.closedDate ?? this.date);
}
@memoize<PullRequest['formatDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.dateFormatter.format(format);
return formatDate(this.mergedDate ?? this.closedDate ?? this.date, format ?? 'MMMM Do, YYYY h:mma');
}
formatDateFromNow() {
return this.dateFormatter.fromNow();
}
@memoize()
private get closedDateFormatter(): Dates.DateFormatter | undefined {
return this.closedDate === undefined ? undefined : Dates.getFormatter(this.closedDate);
return fromNow(this.mergedDate ?? this.closedDate ?? this.date);
}
@memoize<PullRequest['formatClosedDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatClosedDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.closedDateFormatter?.format(format) ?? '';
if (this.closedDate == null) return '';
return formatDate(this.closedDate, format ?? 'MMMM Do, YYYY h:mma');
}
formatClosedDateFromNow() {
return this.closedDateFormatter?.fromNow() ?? '';
}
@memoize()
private get mergedDateFormatter(): Dates.DateFormatter | undefined {
return this.mergedDate === undefined ? undefined : Dates.getFormatter(this.mergedDate);
if (this.closedDate == null) return '';
return fromNow(this.closedDate);
}
@memoize<PullRequest['formatMergedDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatMergedDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.mergedDateFormatter?.format(format) ?? '';
if (this.mergedDate == null) return '';
return formatDate(this.mergedDate, format ?? 'MMMM Do, YYYY h:mma') ?? '';
}
formatMergedDateFromNow() {
return this.mergedDateFormatter?.fromNow() ?? '';
}
@memoize()
private get updatedDateFormatter(): Dates.DateFormatter {
return Dates.getFormatter(this.date);
if (this.mergedDate == null) return '';
return fromNow(this.mergedDate);
}
@memoize<PullRequest['formatUpdatedDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatUpdatedDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.updatedDateFormatter.format(format);
return formatDate(this.date, format ?? 'MMMM Do, YYYY h:mma') ?? '';
}
formatUpdatedDateFromNow() {
return this.updatedDateFormatter.fromNow();
return fromNow(this.date);
}
}

+ 3
- 11
src/git/models/reflog.ts View File

@ -1,5 +1,6 @@
import { DateStyle } from '../../config';
import { Dates, memoize } from '../../system';
import { formatDate, fromNow } from '../../system/date';
import { CommitDateFormatting, GitRevision } from '../models';
export interface GitReflog {
@ -28,15 +29,11 @@ export class GitReflogRecord {
@memoize<GitReflogRecord['formatDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.dateFormatter.format(format);
return formatDate(this.date, format ?? 'MMMM Do, YYYY h:mma');
}
formatDateFromNow() {
return this.dateFormatter.fromNow();
return fromNow(this.date);
}
get formattedDate(): string {
@ -86,9 +83,4 @@ export class GitReflogRecord {
this._selector = selector;
}
}
@memoize()
private get dateFormatter(): Dates.DateFormatter {
return Dates.getFormatter(this.date);
}
}

+ 5
- 5
src/git/models/repository.ts View File

@ -20,7 +20,7 @@ import { Logger } from '../../logger';
import { Messages } from '../../messages';
import { asRepoComparisonKey } from '../../repositories';
import { filterMap, groupByMap } from '../../system/array';
import { getFormatter } from '../../system/date';
import { formatDate, fromNow } from '../../system/date';
import { gate } from '../../system/decorators/gate';
import { debug, log, logName } from '../../system/decorators/log';
import { debounce } from '../../system/function';
@ -139,13 +139,13 @@ export interface RepositoryFileSystemChangeEvent {
@logName<Repository>((r, name) => `${name}(${r.id})`)
export class Repository implements Disposable {
static formatLastFetched(lastFetched: number, short: boolean = true): string {
const formatter = getFormatter(new Date(lastFetched));
const date = new Date(lastFetched);
if (Date.now() - lastFetched < millisecondsPerDay) {
return formatter.fromNow();
return fromNow(date);
}
if (short) {
return formatter.format(Container.instance.config.defaultDateShortFormat ?? 'MMM D, YYYY');
return formatDate(date, Container.instance.config.defaultDateShortFormat ?? 'MMM D, YYYY');
}
let format =
@ -154,7 +154,7 @@ export class Repository implements Disposable {
if (!/[hHm]/.test(format)) {
format += ` [at] ${Container.instance.config.defaultTimeFormat ?? 'h:mma'}`;
}
return formatter.format(format);
return formatDate(date, format);
}
static getLastFetchedUpdateInterval(lastFetched: number): number {

+ 9
- 31
src/git/models/tag.ts View File

@ -1,5 +1,7 @@
import { configuration, DateStyle, TagSorting } from '../../configuration';
import { Dates, memoize, Strings } from '../../system';
import { formatDate, fromNow } from '../../system/date';
import { memoize } from '../../system/decorators/memoize';
import { sortCompare } from '../../system/string';
import { GitReference, GitTagReference } from '../models';
export const TagDateFormatting = {
@ -33,9 +35,9 @@ export class GitTag implements GitTagReference {
case TagSorting.DateAsc:
return tags.sort((a, b) => a.date.getTime() - b.date.getTime());
case TagSorting.NameAsc:
return tags.sort((a, b) => Strings.sortCompare(a.name, b.name));
return tags.sort((a, b) => sortCompare(a.name, b.name));
case TagSorting.NameDesc:
return tags.sort((a, b) => Strings.sortCompare(b.name, a.name));
return tags.sort((a, b) => sortCompare(b.name, a.name));
case TagSorting.DateDesc:
default:
return tags.sort((a, b) => b.date.getTime() - a.date.getTime());
@ -63,46 +65,22 @@ export class GitTag implements GitTagReference {
return this.name;
}
@memoize()
private get commitDateFormatter(): Dates.DateFormatter | undefined {
return this.commitDate == null ? undefined : Dates.getFormatter(this.commitDate);
}
@memoize()
private get dateFormatter(): Dates.DateFormatter {
return Dates.getFormatter(this.date);
}
@memoize<GitTag['formatCommitDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatCommitDate(format?: string | null) {
const formatter = this.commitDateFormatter;
if (formatter == null) return '';
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return formatter.format(format);
return this.commitDate != null ? formatDate(this.commitDate, format ?? 'MMMM Do, YYYY h:mma') : '';
}
formatCommitDateFromNow() {
const formatter = this.commitDateFormatter;
if (formatter == null) return '';
return formatter.fromNow();
return this.commitDate != null ? fromNow(this.commitDate) : '';
}
@memoize<GitTag['formatDate']>(format => (format == null ? 'MMMM Do, YYYY h:mma' : format))
formatDate(format?: string | null) {
if (format == null) {
format = 'MMMM Do, YYYY h:mma';
}
return this.dateFormatter.format(format);
return formatDate(this.date, format ?? 'MMMM Do, YYYY h:mma');
}
formatDateFromNow() {
return this.dateFormatter.fromNow();
return fromNow(this.date);
}
@memoize()

+ 27
- 32
src/quickpicks/gitQuickPickItems.ts View File

@ -14,7 +14,8 @@ import {
GitTag,
Repository,
} from '../git/models';
import { Dates, Strings } from '../system';
import { fromNow } from '../system/date';
import { pad } from '../system/string';
import { CommandQuickPickItem, QuickPickItemOfT } from './quickPicksItems';
export class GitCommandQuickPickItem extends CommandQuickPickItem<[GitCommandsCommandArgs]> {
@ -105,13 +106,13 @@ export namespace BranchQuickPickItem {
if (options.ref) {
if (branch.sha) {
description = description
? `${description}${Strings.pad('$(git-commit)', 2, 2)}${GitRevision.shorten(branch.sha)}`
: `${Strings.pad('$(git-commit)', 0, 2)}${GitRevision.shorten(branch.sha)}`;
? `${description}${pad('$(git-commit)', 2, 2)}${GitRevision.shorten(branch.sha)}`
: `${pad('$(git-commit)', 0, 2)}${GitRevision.shorten(branch.sha)}`;
}
if (branch.date !== undefined) {
description = description
? `${description}${Strings.pad(GlyphChars.Dot, 2, 2)}${branch.formattedDate}`
? `${description}${pad(GlyphChars.Dot, 2, 2)}${branch.formattedDate}`
: branch.formattedDate;
}
}
@ -119,7 +120,7 @@ export namespace BranchQuickPickItem {
const checked =
options.checked || (options.checked == null && options.current === 'checkmark' && branch.current);
const item: BranchQuickPickItem = {
label: `${Strings.pad('$(git-branch)', 0, 2)}${branch.starred ? '$(star-full) ' : ''}${branch.name}${
label: `${pad('$(git-branch)', 0, 2)}${branch.starred ? '$(star-full) ' : ''}${branch.name}${
checked ? `${GlyphChars.Space.repeat(2)}$(check)${GlyphChars.Space}` : ''
}`,
description: description,
@ -154,12 +155,10 @@ export namespace CommitQuickPickItem {
if (options.compact) {
const item: CommitQuickPickItem<T> = {
label: `${options.icon ? Strings.pad('$(archive)', 0, 2) : ''}${number}${commit.getShortMessage()}`,
description: `${commit.formattedDate}${Strings.pad(
GlyphChars.Dot,
2,
2,
)}${commit.getFormattedDiffStatus({ compact: true })}`,
label: `${options.icon ? pad('$(archive)', 0, 2) : ''}${number}${commit.getShortMessage()}`,
description: `${commit.formattedDate}${pad(GlyphChars.Dot, 2, 2)}${commit.getFormattedDiffStatus({
compact: true,
})}`,
alwaysShow: options.alwaysShow,
buttons: options.buttons,
picked: picked,
@ -170,9 +169,9 @@ export namespace CommitQuickPickItem {
}
const item: CommitQuickPickItem<T> = {
label: `${options.icon ? Strings.pad('$(archive)', 0, 2) : ''}${number}${commit.getShortMessage()}`,
label: `${options.icon ? pad('$(archive)', 0, 2) : ''}${number}${commit.getShortMessage()}`,
description: '',
detail: `${GlyphChars.Space.repeat(2)}${commit.formattedDate}${Strings.pad(
detail: `${GlyphChars.Space.repeat(2)}${commit.formattedDate}${pad(
GlyphChars.Dot,
2,
2,
@ -188,10 +187,10 @@ export namespace CommitQuickPickItem {
if (options.compact) {
const item: CommitQuickPickItem<T> = {
label: `${options.icon ? Strings.pad('$(git-commit)', 0, 2) : ''}${commit.getShortMessage()}`,
description: `${commit.author}, ${commit.formattedDate}${Strings.pad('$(git-commit)', 2, 2)}${
label: `${options.icon ? pad('$(git-commit)', 0, 2) : ''}${commit.getShortMessage()}`,
description: `${commit.author}, ${commit.formattedDate}${pad('$(git-commit)', 2, 2)}${
commit.shortSha
}${Strings.pad(GlyphChars.Dot, 2, 2)}${commit.getFormattedDiffStatus({ compact: true })}`,
}${pad(GlyphChars.Dot, 2, 2)}${commit.getFormattedDiffStatus({ compact: true })}`,
alwaysShow: options.alwaysShow,
buttons: options.buttons,
picked: picked,
@ -201,13 +200,13 @@ export namespace CommitQuickPickItem {
}
const item: CommitQuickPickItem<T> = {
label: `${options.icon ? Strings.pad('$(git-commit)', 0, 2) : ''}${commit.getShortMessage()}`,
label: `${options.icon ? pad('$(git-commit)', 0, 2) : ''}${commit.getShortMessage()}`,
description: '',
detail: `${GlyphChars.Space.repeat(2)}${commit.author}, ${commit.formattedDate}${Strings.pad(
detail: `${GlyphChars.Space.repeat(2)}${commit.author}, ${commit.formattedDate}${pad(
'$(git-commit)',
2,
2,
)}${commit.shortSha}${Strings.pad(GlyphChars.Dot, 2, 2)}${commit.getFormattedDiffStatus({
)}${commit.shortSha}${pad(GlyphChars.Dot, 2, 2)}${commit.getFormattedDiffStatus({
compact: true,
})}`,
alwaysShow: options.alwaysShow,
@ -254,7 +253,7 @@ export namespace RefQuickPickItem {
): RefQuickPickItem {
if (ref === '') {
return {
label: `${options.icon ? Strings.pad('$(file-directory)', 0, 2) : ''}Working Tree`,
label: `${options.icon ? pad('$(file-directory)', 0, 2) : ''}Working Tree`,
description: '',
alwaysShow: options.alwaysShow,
buttons: options.buttons,
@ -268,7 +267,7 @@ export namespace RefQuickPickItem {
if (ref === 'HEAD') {
return {
label: `${options.icon ? Strings.pad('$(git-branch)', 0, 2) : ''}HEAD`,
label: `${options.icon ? pad('$(git-branch)', 0, 2) : ''}HEAD`,
description: '',
alwaysShow: options.alwaysShow,
buttons: options.buttons,
@ -349,7 +348,7 @@ export namespace RepositoryQuickPickItem {
if (repoStatus.files.length !== 0) {
workingStatus = repoStatus.getFormattedDiffStatus({
compact: true,
prefix: Strings.pad(GlyphChars.Dot, 2, 2),
prefix: pad(GlyphChars.Dot, 2, 2),
});
}
@ -366,10 +365,8 @@ export namespace RepositoryQuickPickItem {
if (options.fetched) {
const lastFetched = await repository.getLastFetched();
if (lastFetched !== 0) {
const fetched = `Last fetched ${Dates.getFormatter(new Date(lastFetched)).fromNow()}`;
description = `${
description ? `${description}${Strings.pad(GlyphChars.Dot, 2, 2)}${fetched}` : fetched
}`;
const fetched = `Last fetched ${fromNow(new Date(lastFetched))}`;
description = `${description ? `${description}${pad(GlyphChars.Dot, 2, 2)}${fetched}` : fetched}`;
}
}
@ -412,22 +409,20 @@ export namespace TagQuickPickItem {
}
if (options.ref) {
description = `${description}${Strings.pad('$(git-commit)', description ? 2 : 0, 2)}${GitRevision.shorten(
description = `${description}${pad('$(git-commit)', description ? 2 : 0, 2)}${GitRevision.shorten(
tag.sha,
)}`;
description = `${description ? `${description}${Strings.pad(GlyphChars.Dot, 2, 2)}` : ''}${
tag.formattedDate
}`;
description = `${description ? `${description}${pad(GlyphChars.Dot, 2, 2)}` : ''}${tag.formattedDate}`;
}
if (options.message) {
const message = emojify(tag.message);
description = description ? `${description}${Strings.pad(GlyphChars.Dot, 2, 2)}${message}` : message;
description = description ? `${description}${pad(GlyphChars.Dot, 2, 2)}${message}` : message;
}
const item: TagQuickPickItem = {
label: `${Strings.pad('$(tag)', 0, 2)}${tag.name}${
label: `${pad('$(tag)', 0, 2)}${tag.name}${
options.checked ? `${GlyphChars.Space.repeat(2)}$(check)${GlyphChars.Space}` : ''
}`,
description: description,

+ 94
- 97
src/system/date.ts View File

@ -25,114 +25,111 @@ export interface DateFormatter {
format(format: DateTimeFormat | string | null | undefined): string;
}
export function getFormatter(date: Date): DateFormatter {
return {
fromNow: function (short?: boolean) {
const elapsed = date.getTime() - new Date().getTime();
for (const [unit, threshold, shortUnit] of relativeUnitThresholds) {
const elapsedABS = Math.abs(elapsed);
if (elapsedABS >= threshold || threshold === 1000 /* second */) {
if (short) {
if (locale == null) {
if (defaultShortRelativeTimeFormat != null) {
locale = defaultShortRelativeTimeFormat.resolvedOptions().locale;
} else if (defaultRelativeTimeFormat != null) {
locale = defaultRelativeTimeFormat.resolvedOptions().locale;
} else {
defaultShortRelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, {
localeMatcher: 'best fit',
numeric: 'always',
style: 'narrow',
});
locale = defaultShortRelativeTimeFormat.resolvedOptions().locale;
}
}
if (locale === 'en' || locale?.startsWith('en-')) {
const value = Math.round(elapsedABS / threshold);
return `${value}${shortUnit}`;
}
if (defaultShortRelativeTimeFormat == null) {
defaultShortRelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, {
localeMatcher: 'best fit',
numeric: 'always',
style: 'narrow',
});
}
return defaultShortRelativeTimeFormat.format(Math.round(elapsed / threshold), unit);
}
if (defaultRelativeTimeFormat == null) {
defaultRelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, {
export function fromNow(date: Date, short?: boolean): string {
const elapsed = date.getTime() - new Date().getTime();
for (const [unit, threshold, shortUnit] of relativeUnitThresholds) {
const elapsedABS = Math.abs(elapsed);
if (elapsedABS >= threshold || threshold === 1000 /* second */) {
if (short) {
if (locale == null) {
if (defaultShortRelativeTimeFormat != null) {
locale = defaultShortRelativeTimeFormat.resolvedOptions().locale;
} else if (defaultRelativeTimeFormat != null) {
locale = defaultRelativeTimeFormat.resolvedOptions().locale;
} else {
defaultShortRelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, {
localeMatcher: 'best fit',
numeric: 'auto',
style: 'long',
numeric: 'always',
style: 'narrow',
});
locale = defaultShortRelativeTimeFormat.resolvedOptions().locale;
}
return defaultRelativeTimeFormat.format(Math.round(elapsed / threshold), unit);
}
}
return '';
},
format: function (format: 'full' | 'long' | 'medium' | 'short' | string | null | undefined) {
format = format ?? undefined;
let formatter = dateTimeFormatCache.get(format);
if (formatter == null) {
const options = getDateTimeFormatOptionsFromFormatString(format);
formatter = new Intl.DateTimeFormat(undefined, options);
dateTimeFormatCache.set(format, formatter);
if (locale === 'en' || locale?.startsWith('en-')) {
const value = Math.round(elapsedABS / threshold);
return `${value}${shortUnit}`;
}
if (defaultShortRelativeTimeFormat == null) {
defaultShortRelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, {
localeMatcher: 'best fit',
numeric: 'always',
style: 'narrow',
});
}
return defaultShortRelativeTimeFormat.format(Math.round(elapsed / threshold), unit);
}
if (format == null || dateTimeFormatRegex.test(format)) {
return formatter.format(date);
if (defaultRelativeTimeFormat == null) {
defaultRelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, {
localeMatcher: 'best fit',
numeric: 'auto',
style: 'long',
});
}
return defaultRelativeTimeFormat.format(Math.round(elapsed / threshold), unit);
}
}
const parts = formatter.formatToParts(date);
return format.replace(
customDateTimeFormatParserRegex,
(
_match,
literal,
_year,
_month,
_day,
_weekday,
_hour,
_minute,
_second,
_fractionalSecond,
_dayPeriod,
_timeZoneName,
_offset,
_s,
groups,
) => {
if (literal != null) return (literal as string).substring(1, literal.length - 1);
for (const key in groups) {
const value = groups[key];
if (value == null) continue;
const part = parts.find(p => p.type === key);
if (value === 'Do' && part?.type === 'day') {
return formatWithOrdinal(Number(part.value));
} else if (value === 'a' && part?.type === 'dayPeriod') {
return part.value.toLocaleLowerCase();
}
return part?.value ?? '';
}
return '';
}
export function formatDate(date: Date, format: 'full' | 'long' | 'medium' | 'short' | string | null | undefined) {
format = format ?? undefined;
return '';
},
);
let formatter = dateTimeFormatCache.get(format);
if (formatter == null) {
const options = getDateTimeFormatOptionsFromFormatString(format);
formatter = new Intl.DateTimeFormat(undefined, options);
dateTimeFormatCache.set(format, formatter);
}
if (format == null || dateTimeFormatRegex.test(format)) {
return formatter.format(date);
}
const parts = formatter.formatToParts(date);
return format.replace(
customDateTimeFormatParserRegex,
(
_match,
literal,
_year,
_month,
_day,
_weekday,
_hour,
_minute,
_second,
_fractionalSecond,
_dayPeriod,
_timeZoneName,
_offset,
_s,
groups,
) => {
if (literal != null) return (literal as string).substring(1, literal.length - 1);
for (const key in groups) {
const value = groups[key];
if (value == null) continue;
const part = parts.find(p => p.type === key);
if (value === 'Do' && part?.type === 'day') {
return formatWithOrdinal(Number(part.value));
} else if (value === 'a' && part?.type === 'dayPeriod') {
return part.value.toLocaleLowerCase();
}
return part?.value ?? '';
}
return '';
},
};
);
}
function getDateTimeFormatOptionsFromFormatString(

+ 4
- 4
src/views/nodes/autolinkedItemNode.ts View File

@ -1,7 +1,7 @@
import { MarkdownString, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { GitUri } from '../../git/gitUri';
import { GitFile, IssueOrPullRequest, IssueOrPullRequestType } from '../../git/models';
import { Dates } from '../../system';
import { fromNow } from '../../system/date';
import { ViewsWithCommits } from '../viewBase';
import { ContextValues, ViewNode } from './viewNode';
@ -37,10 +37,10 @@ export class AutolinkedItemNode extends ViewNode {
}
getTreeItem(): TreeItem {
const formatter = Dates.getFormatter(this.issue.closedDate ?? this.issue.date);
const relativeTime = fromNow(this.issue.closedDate ?? this.issue.date);
const item = new TreeItem(`${this.issue.id}: ${this.issue.title}`, TreeItemCollapsibleState.None);
item.description = formatter.fromNow();
item.description = relativeTime;
item.iconPath = IssueOrPullRequest.getThemeIcon(this.issue);
item.contextValue =
this.issue.type === IssueOrPullRequestType.PullRequest
@ -55,7 +55,7 @@ export class AutolinkedItemNode extends ViewNode {
this.issue.url
}${linkTitle}) \\\n[#${this.issue.id}](${this.issue.url}${linkTitle}) was ${
this.issue.closed ? 'closed' : 'opened'
} ${formatter.fromNow()}`,
} ${relativeTime}`,
true,
);
tooltip.supportHtml = true;

+ 17
- 20
src/views/nodes/branchTrackingStatusNode.ts View File

@ -2,7 +2,11 @@ import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleSta
import { Colors } from '../../constants';
import { GitUri } from '../../git/gitUri';
import { GitBranch, GitLog, GitRemote, GitRevision, GitTrackingState } from '../../git/models';
import { Dates, debug, gate, Iterables, Strings } from '../../system';
import { fromNow } from '../../system/date';
import { gate } from '../../system/decorators/gate';
import { debug } from '../../system/decorators/log';
import { first, map } from '../../system/iterable';
import { pluralize } from '../../system/string';
import { ViewsWithCommits } from '../viewBase';
import { BranchNode } from './branchNode';
import { BranchTrackingStatusFilesNode } from './branchTrackingStatusFilesNode';
@ -82,7 +86,7 @@ export class BranchTrackingStatusNode extends ViewNode impleme
ref: commit.sha,
});
if (previousLog != null) {
commits[commits.length - 1] = Iterables.first(previousLog.commits.values());
commits[commits.length - 1] = first(previousLog.commits.values());
}
}
} else {
@ -113,10 +117,7 @@ export class BranchTrackingStatusNode extends ViewNode impleme
} else {
children.push(
...insertDateMarkers(
Iterables.map(
commits,
c => new CommitNode(this.view, this, c, this.upstreamType === 'ahead', this.branch),
),
map(commits, c => new CommitNode(this.view, this, c, this.upstreamType === 'ahead', this.branch)),
this,
1,
),
@ -166,12 +167,10 @@ export class BranchTrackingStatusNode extends ViewNode impleme
label = `Changes to push to ${remote?.name ?? GitBranch.getRemote(this.status.upstream!)}${
remote?.provider?.name ? ` on ${remote?.provider.name}` : ''
}`;
description = Strings.pluralize('commit', this.status.state.ahead);
tooltip = `Branch $(git-branch) ${this.branch.name} is ${Strings.pluralize(
'commit',
this.status.state.ahead,
{ infix: '$(arrow-up) ' },
)} ahead of $(git-branch) ${this.status.upstream}${
description = pluralize('commit', this.status.state.ahead);
tooltip = `Branch $(git-branch) ${this.branch.name} is ${pluralize('commit', this.status.state.ahead, {
infix: '$(arrow-up) ',
})} ahead of $(git-branch) ${this.status.upstream}${
remote?.provider?.name ? ` on ${remote.provider.name}` : ''
}`;
@ -189,12 +188,10 @@ export class BranchTrackingStatusNode extends ViewNode impleme
label = `Changes to pull from ${remote?.name ?? GitBranch.getRemote(this.status.upstream!)}${
remote?.provider?.name ? ` on ${remote.provider.name}` : ''
}`;
description = Strings.pluralize('commit', this.status.state.behind);
tooltip = `Branch $(git-branch) ${this.branch.name} is ${Strings.pluralize(
'commit',
this.status.state.behind,
{ infix: '$(arrow-down) ' },
)} behind $(git-branch) ${this.status.upstream}${
description = pluralize('commit', this.status.state.behind);
tooltip = `Branch $(git-branch) ${this.branch.name} is ${pluralize('commit', this.status.state.behind, {
infix: '$(arrow-down) ',
})} behind $(git-branch) ${this.status.upstream}${
remote?.provider?.name ? ` on ${remote.provider.name}` : ''
}`;
@ -212,7 +209,7 @@ export class BranchTrackingStatusNode extends ViewNode impleme
label = `Up to date with ${remote?.name ?? GitBranch.getRemote(this.status.upstream!)}${
remote?.provider?.name ? ` on ${remote.provider.name}` : ''
}`;
description = lastFetched ? `Last fetched ${Dates.getFormatter(new Date(lastFetched)).fromNow()}` : '';
description = lastFetched ? `Last fetched ${fromNow(new Date(lastFetched))}` : '';
tooltip = `Branch $(git-branch) ${this.branch.name} is up to date with $(git-branch) ${
this.status.upstream
}${remote?.provider?.name ? ` on ${remote.provider.name}` : ''}`;
@ -251,7 +248,7 @@ export class BranchTrackingStatusNode extends ViewNode impleme
item.contextValue = contextValue;
item.description = description;
if (lastFetched) {
tooltip += `\n\nLast fetched ${Dates.getFormatter(new Date(lastFetched)).fromNow()}`;
tooltip += `\n\nLast fetched ${fromNow(new Date(lastFetched))}`;
}
item.iconPath = icon;

+ 4
- 4
src/webviews/apps/shared/appWithConfigBase.ts View File

@ -8,13 +8,13 @@ import {
PreviewConfigurationCommandType,
UpdateConfigurationCommandType,
} from '../../protocol';
import { getFormatter } from '../shared/date';
import { formatDate } from '../shared/date';
import { App } from './appBase';
import { DOM } from './dom';
const offset = (new Date().getTimezoneOffset() / 60) * 100;
const dateFormatter = getFormatter(
new Date(`Wed Jul 25 2018 19:18:00 GMT${offset >= 0 ? '-' : '+'}${String(Math.abs(offset)).padStart(4, '0')}`),
const date = new Date(
`Wed Jul 25 2018 19:18:00 GMT${offset >= 0 ? '-' : '+'}${String(Math.abs(offset)).padStart(4, '0')}`,
);
let ipcSequence = 0;
@ -419,7 +419,7 @@ export abstract class AppWithConfig extends A
value = el.dataset.settingPreviewDefault;
}
el.innerText = value == null ? '' : dateFormatter.format(value);
el.innerText = value == null ? '' : formatDate(date, value);
break;
}
case 'commit': {

Loading…
Cancel
Save