diff --git a/src/annotations/autolinks.ts b/src/annotations/autolinks.ts index 133d894..cb91445 100644 --- a/src/annotations/autolinks.ts +++ b/src/annotations/autolinks.ts @@ -5,7 +5,8 @@ import { GlyphChars } from '../constants'; import { Container } from '../container'; import { GitRemote, IssueOrPullRequest } from '../git/models'; import { Logger } from '../logger'; -import { Dates, debug, Encoding, Iterables, Promises, Strings } from '../system'; +import { Dates, debug, Encoding, Iterables, Strings } from '../system'; +import { PromiseCancelledError, raceAll } from '../system/promise'; const numRegex = //g; @@ -89,11 +90,7 @@ export class Autolinks implements Disposable { if (ids.size === 0) return undefined; - const issuesOrPullRequests = await Promises.raceAll( - ids.values(), - id => provider.getIssueOrPullRequest(id), - timeout, - ); + const issuesOrPullRequests = await raceAll(ids.values(), id => provider.getIssueOrPullRequest(id), timeout); if (issuesOrPullRequests.size === 0 || Iterables.every(issuesOrPullRequests.values(), pr => pr === undefined)) { return undefined; } @@ -113,7 +110,7 @@ export class Autolinks implements Disposable { text: string, markdown: boolean, remotes?: GitRemote[], - issuesOrPullRequests?: Map, + issuesOrPullRequests?: Map, footnotes?: Map, ) { for (const ref of this._references) { @@ -143,7 +140,7 @@ export class Autolinks implements Disposable { private ensureAutolinkCached( ref: CacheableAutolinkReference | DynamicAutolinkReference, - issuesOrPullRequests?: Map, + issuesOrPullRequests?: Map, ): ref is CacheableAutolinkReference | DynamicAutolinkReference { if (isDynamic(ref)) return true; @@ -182,7 +179,7 @@ export class Autolinks implements Disposable { title = ` "${ref.title.replace(numRegex, num)}`; if (issue != null) { - if (issue instanceof Promises.CancellationError) { + if (issue instanceof PromiseCancelledError) { title += `\n${GlyphChars.Dash.repeat(2)}\nDetails timed out`; } else { const issueTitle = issue.title.replace(/([")\\])/g, '\\$1').trim(); @@ -225,7 +222,7 @@ export class Autolinks implements Disposable { footnotes.set( index, `${linkText}: ${ - issue instanceof Promises.CancellationError + issue instanceof PromiseCancelledError ? 'Details timed out' : `${issue.title} ${GlyphChars.Dot} ${ issue.closed ? 'Closed' : 'Opened' diff --git a/src/annotations/lineAnnotationController.ts b/src/annotations/lineAnnotationController.ts index 1fc8dd3..9b8ee88 100644 --- a/src/annotations/lineAnnotationController.ts +++ b/src/annotations/lineAnnotationController.ts @@ -18,7 +18,8 @@ import { CommitFormatter } from '../git/formatters'; import { GitBlameCommit, PullRequest } from '../git/models'; import { Authentication } from '../git/remotes/provider'; import { LogCorrelationContext, Logger } from '../logger'; -import { debug, Iterables, log, Promises } from '../system'; +import { debug, Iterables, log } from '../system'; +import { PromiseCancelledError, PromiseCancelledErrorWithId, raceAll } from '../system/promise'; import { LinesChangeEvent, LineSelection } from '../trackers/gitLineTracker'; import { Annotations } from './annotations'; @@ -170,7 +171,7 @@ export class LineAnnotationController implements Disposable { if (refs.size === 0) return undefined; const { provider } = remote; - const prs = await Promises.raceAll( + const prs = await raceAll( refs.values(), ref => this.container.git.getPullRequestForCommit(ref, provider), timeout, @@ -335,21 +336,21 @@ export class LineAnnotationController implements Disposable { editor: TextEditor, prs: Map< string, - PullRequest | Promises.CancellationErrorWithId> | undefined + PullRequest | PromiseCancelledErrorWithId> | undefined >, cancellationToken: CancellationToken, timeout: number, cc: LogCorrelationContext | undefined, ) { // If there are any PRs that timed out, refresh the annotation(s) once they complete - const count = Iterables.count(prs.values(), pr => pr instanceof Promises.CancellationError); + const count = Iterables.count(prs.values(), pr => pr instanceof PromiseCancelledError); if (cancellationToken.isCancellationRequested || count === 0) return; Logger.debug(cc, `${GlyphChars.Dot} ${count} pull request queries took too long (over ${timeout} ms)`); const resolved = new Map(); for (const [key, value] of prs) { - resolved.set(key, value instanceof Promises.CancellationError ? await value.promise : value); + resolved.set(key, value instanceof PromiseCancelledError ? await value.promise : value); } if (cancellationToken.isCancellationRequested || editor !== this._editor) return; diff --git a/src/commands/gitCommands.ts b/src/commands/gitCommands.ts index 80d5717..be20ac3 100644 --- a/src/commands/gitCommands.ts +++ b/src/commands/gitCommands.ts @@ -5,7 +5,8 @@ import { Usage, WorkspaceState } from '../constants'; import type { Container } from '../container'; import { KeyMapping } from '../keyboard'; import { Directive, DirectiveQuickPickItem } from '../quickpicks'; -import { log, Promises } from '../system'; +import { log } from '../system/decorators/log'; +import { isPromise } from '../system/promise'; import { command, Command, CommandContext, Commands } from './common'; import { BranchGitCommand, BranchGitCommandArgs } from './git/branch'; import { CherryPickGitCommand, CherryPickGitCommandArgs } from './git/cherry-pick'; @@ -334,7 +335,7 @@ export class GitCommandsCommand extends Command { return; } - if (Promises.is(result)) { + if (isPromise(result)) { input.buttons = this.getButtons(step, commandsStep.command); } @@ -506,7 +507,7 @@ export class GitCommandsCommand extends Command { return; } - if (Promises.is(result)) { + if (isPromise(result)) { quickpick.buttons = this.getButtons( activeCommand != null ? activeCommand.value : step, activeCommand ?? commandsStep.command, diff --git a/src/git/formatters/commitFormatter.ts b/src/git/formatters/commitFormatter.ts index 436398a..b96f70a 100644 --- a/src/git/formatters/commitFormatter.ts +++ b/src/git/formatters/commitFormatter.ts @@ -16,7 +16,8 @@ import { DateStyle, FileAnnotationType } from '../../configuration'; import { GlyphChars } from '../../constants'; import { Container } from '../../container'; import { emojify } from '../../emojis'; -import { Iterables, Promises, Strings } from '../../system'; +import { Iterables, Strings } from '../../system'; +import { PromiseCancelledError } from '../../system/promise'; import { ContactPresence } from '../../vsls/vsls'; import { GitUri } from '../gitUri'; import { GitCommit, GitLogCommit, GitRemote, GitRevision, IssueOrPullRequest, PullRequest } from '../models'; @@ -26,7 +27,7 @@ import { FormatOptions, Formatter } from './formatter'; const emptyStr = ''; export interface CommitFormatOptions extends FormatOptions { - autolinkedIssuesOrPullRequests?: Map; + autolinkedIssuesOrPullRequests?: Map; avatarSize?: number; dateStyle?: DateStyle; editor?: { line: number; uri: Uri }; @@ -36,7 +37,7 @@ export interface CommitFormatOptions extends FormatOptions { messageAutolinks?: boolean; messageIndent?: number; messageTruncateAtNewLine?: boolean; - pullRequestOrRemote?: PullRequest | Promises.CancellationError | GitRemote; + pullRequestOrRemote?: PullRequest | PromiseCancelledError | GitRemote; pullRequestPendingMessage?: string; presence?: ContactPresence; previousLineDiffUris?: { current: GitUri; previous: GitUri | undefined }; @@ -358,7 +359,7 @@ export class CommitFormatter extends Formatter { }\n${GlyphChars.Dash.repeat(2)}\n${Strings.escapeMarkdown(pr.title).replace(/"/g, '\\"')}\n${ pr.state }, ${pr.formatDateFromNow()}")`; - } else if (pr instanceof Promises.CancellationError) { + } else if (pr instanceof PromiseCancelledError) { commands += `${separator}[$(git-pull-request) PR $(loading~spin)](command:${Commands.RefreshHover} "Searching for a Pull Request (if any) that introduced this commit...")`; } else if (pr.provider != null && Container.instance.config.integrations.enabled) { commands += `${separator}[$(plug) Connect to ${pr.provider.name}${ @@ -540,7 +541,7 @@ export class CommitFormatter extends Formatter { } else { text = `PR #${pr.id}`; } - } else if (pr instanceof Promises.CancellationError) { + } else if (pr instanceof PromiseCancelledError) { text = this._options.markdown ? `[PR $(loading~spin)](command:${Commands.RefreshHover} "Searching for a Pull Request (if any) that introduced this commit...")` : this._options?.pullRequestPendingMessage ?? emptyStr; diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index e9ceb3a..45cc48d 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -29,9 +29,12 @@ import { import type { Container } from '../container'; import { ProviderNotFoundError } from '../errors'; import { Logger } from '../logger'; -import { Arrays, debug, gate, Iterables, log, Promises } from '../system'; +import { groupByFilterMap, groupByMap } from '../system/array'; +import { gate } from '../system/decorators/gate'; +import { debug, log } from '../system/decorators/log'; +import { count, filter, flatMap, map } from '../system/iterable'; import { isDescendent, normalizePath } from '../system/path'; -import { PromiseOrValue } from '../system/promise'; +import { cancellable, isPromise, PromiseCancelledError, PromiseOrValue } from '../system/promise'; import { CharCode } from '../system/string'; import { vslsUriPrefixRegex } from '../vsls/vsls'; import { GitProvider, GitProviderDescriptor, GitProviderId, PagedResult, ScmRepository } from './gitProvider'; @@ -117,7 +120,7 @@ export class GitProviderService implements Disposable { } else if (added?.length) { // If a provider was added, only preserve paths with a resolved repoPath for (const [key, value] of this._pathToRepoPathCache) { - if (value === null || Promises.is(value)) { + if (value === null || isPromise(value)) { this._pathToRepoPathCache.delete(key); } } @@ -141,7 +144,7 @@ export class GitProviderService implements Disposable { } else if (added?.length) { // If a repository was added, only preserve paths with a resolved repoPath for (const [key, value] of this._pathToRepoPathCache) { - if (value === null || Promises.is(value)) { + if (value === null || isPromise(value)) { this._pathToRepoPathCache.delete(key); } } @@ -263,18 +266,18 @@ export class GitProviderService implements Disposable { } get registeredProviders(): GitProviderDescriptor[] { - return [...Iterables.map(this._providers.values(), p => ({ ...p.descriptor }))]; + return [...map(this._providers.values(), p => ({ ...p.descriptor }))]; } get openRepositories(): Repository[] { - const repositories = [...Iterables.filter(this.repositories, r => !r.closed)]; + const repositories = [...filter(this.repositories, r => !r.closed)]; if (repositories.length === 0) return repositories; return Repository.sort(repositories); } get openRepositoryCount(): number { - return Iterables.count(this.repositories, r => !r.closed); + return count(this.repositories, r => !r.closed); } get repositories(): Iterable { @@ -423,14 +426,14 @@ export class GitProviderService implements Disposable { } getOpenRepositories(id: GitProviderId): Iterable { - return Iterables.filter(this.repositories, r => !r.closed && (id == null || id === r.provider.id)); + return filter(this.repositories, r => !r.closed && (id == null || id === r.provider.id)); } getOpenRepositoriesByProvider(): Map { - const repositories = [...Iterables.filter(this.repositories, r => !r.closed)]; + const repositories = [...filter(this.repositories, r => !r.closed)]; if (repositories.length === 0) return new Map(); - return Arrays.groupByMap(repositories, r => r.provider.id); + return groupByMap(repositories, r => r.provider.id); } private _discoveredWorkspaceFolders = new Map>(); @@ -451,8 +454,8 @@ export class GitProviderService implements Disposable { const results = await Promise.allSettled(promises); - const repositories = Iterables.flatMap, Repository>( - Iterables.filter, PromiseFulfilledResult>( + const repositories = flatMap, Repository>( + filter, PromiseFulfilledResult>( results, (r): r is PromiseFulfilledResult => r.status === 'fulfilled', ), @@ -927,7 +930,7 @@ export class GitProviderService implements Disposable { this.getTags(repoPath), ]); - const branchesAndTagsBySha = Arrays.groupByFilterMap( + const branchesAndTagsBySha = groupByFilterMap( (branches as (GitBranch | GitTag)[]).concat(tags as (GitBranch | GitTag)[]), bt => bt.sha, bt => { @@ -1314,18 +1317,18 @@ export class GitProviderService implements Disposable { } let promiseOrPR = provider.getPullRequestForBranch(branch, options); - if (promiseOrPR == null || !Promises.is(promiseOrPR)) { + if (promiseOrPR == null || !isPromise(promiseOrPR)) { return promiseOrPR; } if (timeout != null && timeout > 0) { - promiseOrPR = Promises.cancellable(promiseOrPR, timeout); + promiseOrPR = cancellable(promiseOrPR, timeout); } try { return await promiseOrPR; } catch (ex) { - if (ex instanceof Promises.CancellationError) { + if (ex instanceof PromiseCancelledError) { throw ex; } @@ -1366,18 +1369,18 @@ export class GitProviderService implements Disposable { } let promiseOrPR = provider.getPullRequestForCommit(ref); - if (promiseOrPR == null || !Promises.is(promiseOrPR)) { + if (promiseOrPR == null || !isPromise(promiseOrPR)) { return promiseOrPR; } if (options?.timeout != null && options.timeout > 0) { - promiseOrPR = Promises.cancellable(promiseOrPR, options.timeout); + promiseOrPR = cancellable(promiseOrPR, options.timeout); } try { return await promiseOrPR; } catch (ex) { - if (ex instanceof Promises.CancellationError) { + if (ex instanceof PromiseCancelledError) { throw ex; } @@ -1522,7 +1525,7 @@ export class GitProviderService implements Disposable { let repoPathOrPromise = this._pathToRepoPathCache.get(filePath); if (repoPathOrPromise !== undefined) { - rp = Promises.is(repoPathOrPromise) ? await repoPathOrPromise : repoPathOrPromise; + rp = isPromise(repoPathOrPromise) ? await repoPathOrPromise : repoPathOrPromise; // If the repoPath is explicitly null, then we know no repo exists if (rp === null) return undefined; @@ -1878,8 +1881,8 @@ export class GitProviderService implements Disposable { @log() async getOpenScmRepositories(): Promise { const results = await Promise.allSettled([...this._providers.values()].map(p => p.getOpenScmRepositories())); - const repositories = Iterables.flatMap, ScmRepository>( - Iterables.filter, PromiseFulfilledResult>( + const repositories = flatMap, ScmRepository>( + filter, PromiseFulfilledResult>( results, (r): r is PromiseFulfilledResult => r.status === 'fulfilled', ), diff --git a/src/git/remotes/provider.ts b/src/git/remotes/provider.ts index a2ac620..4041366 100644 --- a/src/git/remotes/provider.ts +++ b/src/git/remotes/provider.ts @@ -15,7 +15,10 @@ import { WorkspaceState } from '../../constants'; import { Container } from '../../container'; import { AuthenticationError, ProviderRequestClientError } from '../../errors'; import { Logger } from '../../logger'; -import { debug, Encoding, gate, log, Promises } from '../../system'; +import { gate } from '../../system/decorators/gate'; +import { debug, log } from '../../system/decorators/log'; +import { encodeUrl } from '../../system/encoding'; +import { isPromise } from '../../system/promise'; import { Account, DefaultBranch, @@ -235,7 +238,7 @@ export abstract class RemoteProvider implements RemoteProviderReference { protected encodeUrl(url: string): string; protected encodeUrl(url: string | undefined): string | undefined; protected encodeUrl(url: string | undefined): string | undefined { - return Encoding.encodeUrl(url)?.replace(/#/g, '%23'); + return encodeUrl(url)?.replace(/#/g, '%23'); } } @@ -530,7 +533,7 @@ export abstract class RichRemoteProvider extends RemoteProvider { pr = this.getPullRequestForCommitCore(ref); this._prsByCommit.set(ref, pr); } - if (pr == null || !Promises.is(pr)) return pr ?? undefined; + if (pr == null || !isPromise(pr)) return pr ?? undefined; return pr.then(pr => pr ?? undefined); } diff --git a/src/hovers/hovers.ts b/src/hovers/hovers.ts index f34d0a0..edcad92 100644 --- a/src/hovers/hovers.ts +++ b/src/hovers/hovers.ts @@ -17,7 +17,8 @@ import { PullRequest, } from '../git/models'; import { Logger, LogLevel } from '../logger'; -import { Iterables, Promises, Strings } from '../system'; +import { Iterables, Strings } from '../system'; +import { PromiseCancelledError } from '../system/promise'; export namespace Hovers { export async function changesMessage( @@ -190,7 +191,7 @@ export namespace Hovers { cancellationToken?: CancellationToken; pullRequests?: { enabled: boolean; - pr?: PullRequest | Promises.CancellationError>; + pr?: PullRequest | PromiseCancelledError>; }; getBranchAndTagTips?: ( sha: string, @@ -296,7 +297,7 @@ export namespace Hovers { if (autolinks != null && Logger.enabled(LogLevel.Debug)) { // If there are any issues/PRs that timed out, log it - const count = Iterables.count(autolinks.values(), pr => pr instanceof Promises.CancellationError); + const count = Iterables.count(autolinks.values(), pr => pr instanceof PromiseCancelledError); if (count !== 0) { Logger.debug( cc, @@ -309,7 +310,7 @@ export namespace Hovers { // const pending = [ // ...Iterables.map(autolinks.values(), issueOrPullRequest => - // issueOrPullRequest instanceof Promises.CancellationError + // issueOrPullRequest instanceof CancelledPromiseError // ? issueOrPullRequest.promise // : undefined, // ), @@ -376,7 +377,7 @@ export namespace Hovers { return pr; } catch (ex) { - if (ex instanceof Promises.CancellationError) { + if (ex instanceof PromiseCancelledError) { Logger.debug(cc, `timed out ${GlyphChars.Dot} ${Strings.getDurationMilliseconds(start)} ms`); return ex; diff --git a/src/quickpicks/commitPicker.ts b/src/quickpicks/commitPicker.ts index 3af98d1..16cf8e2 100644 --- a/src/quickpicks/commitPicker.ts +++ b/src/quickpicks/commitPicker.ts @@ -11,7 +11,8 @@ import { DirectiveQuickPickItem, getQuickPickIgnoreFocusOut, } from '../quickpicks'; -import { Iterables, Promises } from '../system'; +import { filter, map } from '../system/iterable'; +import { isPromise } from '../system/promise'; export namespace CommitPicker { export async function show( @@ -33,7 +34,7 @@ export namespace CommitPicker { quickpick.matchOnDescription = true; quickpick.matchOnDetail = true; - if (Promises.is(log)) { + if (isPromise(log)) { quickpick.busy = true; quickpick.enabled = false; quickpick.show(); @@ -56,7 +57,7 @@ export namespace CommitPicker { ? [DirectiveQuickPickItem.create(Directive.Cancel)] : [ ...(options?.showOtherReferences ?? []), - ...Iterables.map(log.commits.values(), commit => + ...map(log.commits.values(), commit => CommitQuickPickItem.create(commit, options?.picked === commit.ref, { compact: true, icon: true, @@ -206,7 +207,7 @@ export namespace StashPicker { quickpick.matchOnDescription = true; quickpick.matchOnDetail = true; - if (Promises.is(stash)) { + if (isPromise(stash)) { quickpick.busy = true; quickpick.enabled = false; quickpick.show(); @@ -217,10 +218,8 @@ export namespace StashPicker { if (stash != null) { quickpick.items = [ ...(options?.showOtherReferences ?? []), - ...Iterables.map( - options?.filter != null - ? Iterables.filter(stash.commits.values(), options.filter) - : stash.commits.values(), + ...map( + options?.filter != null ? filter(stash.commits.values(), options.filter) : stash.commits.values(), commit => CommitQuickPickItem.create(commit, options?.picked === commit.ref, { compact: true, diff --git a/src/statusbar/statusBarController.ts b/src/statusbar/statusBarController.ts index 1544720..c79eed8 100644 --- a/src/statusbar/statusBarController.ts +++ b/src/statusbar/statusBarController.ts @@ -19,7 +19,8 @@ import { CommitFormatter } from '../git/formatters'; import { GitBlameCommit, PullRequest } from '../git/models'; import { Hovers } from '../hovers/hovers'; import { LogCorrelationContext, Logger } from '../logger'; -import { debug, Promises } from '../system'; +import { debug } from '../system/decorators/log'; +import { PromiseCancelledError } from '../system/promise'; import { LinesChangeEvent } from '../trackers/gitLineTracker'; export class StatusBarController implements Disposable { @@ -333,7 +334,7 @@ export class StatusBarController implements Disposable { private async getPullRequest( commit: GitBlameCommit, { timeout }: { timeout?: number } = {}, - ): Promise> | undefined> { + ): Promise> | undefined> { const remote = await this.container.git.getRichRemoteProvider(commit.repoPath); if (remote?.provider == null) return undefined; @@ -341,7 +342,7 @@ export class StatusBarController implements Disposable { try { return await this.container.git.getPullRequestForCommit(commit.ref, provider, { timeout: timeout }); } catch (ex) { - return ex instanceof Promises.CancellationError ? ex : undefined; + return ex instanceof PromiseCancelledError ? ex : undefined; } } @@ -357,7 +358,7 @@ export class StatusBarController implements Disposable { | undefined, pullRequests: { enabled: boolean; - pr: PullRequest | Promises.CancellationError> | undefined | undefined; + pr: PullRequest | PromiseCancelledError> | undefined | undefined; }, cancellationToken: CancellationToken, ) { @@ -386,12 +387,12 @@ export class StatusBarController implements Disposable { private async waitForPendingPullRequest( editor: TextEditor, commit: GitBlameCommit, - pr: PullRequest | Promises.CancellationError> | undefined, + pr: PullRequest | PromiseCancelledError> | undefined, cancellationToken: CancellationToken, timeout: number, cc: LogCorrelationContext | undefined, ) { - if (cancellationToken.isCancellationRequested || !(pr instanceof Promises.CancellationError)) return; + if (cancellationToken.isCancellationRequested || !(pr instanceof PromiseCancelledError)) return; // If the PR timed out, refresh the status bar once it completes Logger.debug(cc, `${GlyphChars.Dot} pull request query took too long (over ${timeout} ms)`); diff --git a/src/system.ts b/src/system.ts index 1514944..1ae6ce5 100644 --- a/src/system.ts +++ b/src/system.ts @@ -29,7 +29,6 @@ export * as Encoding from './system/encoding'; export * as Functions from './system/function'; export * as Iterables from './system/iterable'; export * as Objects from './system/object'; -export * as Promises from './system/promise'; export * from './system/searchTree'; export * from './system/stopwatch'; export * as Strings from './system/string'; diff --git a/src/system/decorators/gate.ts b/src/system/decorators/gate.ts index 5ce0fcb..5809d11 100644 --- a/src/system/decorators/gate.ts +++ b/src/system/decorators/gate.ts @@ -1,5 +1,5 @@ 'use strict'; -import { is as isPromise } from '../promise'; +import { isPromise } from '../promise'; import { resolveProp } from './resolver'; export function gate any>(resolver?: (...args: Parameters) => string) { diff --git a/src/system/decorators/log.ts b/src/system/decorators/log.ts index 024d0d3..dfc044c 100644 --- a/src/system/decorators/log.ts +++ b/src/system/decorators/log.ts @@ -3,7 +3,7 @@ import { hrtime } from '@env/hrtime'; import { LogCorrelationContext, Logger, LogLevel } from '../../logger'; import { filterMap } from '../array'; import { getParameters } from '../function'; -import { is as isPromise } from '../promise'; +import { isPromise } from '../promise'; import { getDurationMilliseconds } from '../string'; const emptyStr = ''; diff --git a/src/system/decorators/timeout.ts b/src/system/decorators/timeout.ts index bb0b5f0..b180765 100644 --- a/src/system/decorators/timeout.ts +++ b/src/system/decorators/timeout.ts @@ -1,5 +1,5 @@ 'use strict'; -import { cancellable, is as isPromise } from '../promise'; +import { cancellable, isPromise } from '../promise'; export function timeout(timeout: number): any; export function timeout(timeoutFromLastArg: true, defaultTimeout?: number): any; diff --git a/src/system/promise.ts b/src/system/promise.ts index 3ac4c70..b1f6a44 100644 --- a/src/system/promise.ts +++ b/src/system/promise.ts @@ -33,13 +33,13 @@ export function any(...promises: Promise[]): Promise { }); } -export class CancellationError = Promise> extends Error { +export class PromiseCancelledError = Promise> extends Error { constructor(public readonly promise: T, message: string) { super(message); } } -export class CancellationErrorWithId = Promise> extends CancellationError { +export class PromiseCancelledErrorWithId = Promise> extends PromiseCancelledError { constructor(public readonly id: TKey, promise: T, message: string) { super(promise, message); } @@ -65,7 +65,7 @@ export function cancellable( if (typeof options.onDidCancel === 'function') { options.onDidCancel(resolve, reject); } else { - reject(new CancellationError(promise, options.cancelMessage ?? 'TIMED OUT')); + reject(new PromiseCancelledError(promise, options.cancelMessage ?? 'TIMED OUT')); } }, timeoutOrToken); } else { @@ -76,7 +76,7 @@ export function cancellable( if (typeof options.onDidCancel === 'function') { options.onDidCancel(resolve, reject); } else { - reject(new CancellationError(promise, options.cancelMessage ?? 'CANCELLED')); + reject(new PromiseCancelledError(promise, options.cancelMessage ?? 'CANCELLED')); } }); } @@ -102,23 +102,23 @@ export function cancellable( }); } -export function is(obj: PromiseLike | T): obj is Promise { +export function isPromise(obj: PromiseLike | T): obj is Promise { return obj instanceof Promise || typeof (obj as PromiseLike)?.then === 'function'; } export function raceAll( promises: Promise[], timeout?: number, -): Promise<(TPromise | CancellationError>)[]>; +): Promise<(TPromise | PromiseCancelledError>)[]>; export function raceAll( promises: Map>, timeout?: number, -): Promise>>>; +): Promise>>>; export function raceAll( ids: Iterable, fn: (id: T) => Promise, timeout?: number, -): Promise>>>; +): Promise>>>; export async function raceAll( promisesOrIds: Promise[] | Map> | Iterable, timeoutOrFn?: number | ((id: T) => Promise), @@ -135,7 +135,7 @@ export async function raceAll( if (promises instanceof Map) { return new Map( await Promise.all( - map<[T, Promise], Promise<[T, TPromise | CancellationErrorWithId>]>>( + map<[T, Promise], Promise<[T, TPromise | PromiseCancelledErrorWithId>]>>( promises.entries(), timeout == null ? ([id, promise]) => promise.then(p => [id, p]) @@ -143,9 +143,9 @@ export async function raceAll( Promise.race([ promise, - new Promise>>(resolve => + new Promise>>(resolve => setTimeout( - () => resolve(new CancellationErrorWithId(id, promise, 'TIMED OUT')), + () => resolve(new PromiseCancelledErrorWithId(id, promise, 'TIMED OUT')), timeout, ), ), @@ -161,8 +161,8 @@ export async function raceAll( : promises.map(p => Promise.race([ p, - new Promise>>(resolve => - setTimeout(() => resolve(new CancellationError(p, 'TIMED OUT')), timeout), + new Promise>>(resolve => + setTimeout(() => resolve(new PromiseCancelledError(p, 'TIMED OUT')), timeout), ), ]), ), diff --git a/src/views/nodes/autolinkedItemsNode.ts b/src/views/nodes/autolinkedItemsNode.ts index 8ff750d..7deefb7 100644 --- a/src/views/nodes/autolinkedItemsNode.ts +++ b/src/views/nodes/autolinkedItemsNode.ts @@ -3,7 +3,8 @@ import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { GitUri } from '../../git/gitUri'; import { GitFile, GitLog, GitRemote, IssueOrPullRequest, PullRequest } from '../../git/models'; import { RichRemoteProvider } from '../../git/remotes/provider'; -import { debug, gate, Promises } from '../../system'; +import { debug, gate } from '../../system'; +import { PromiseCancelledErrorWithId } from '../../system/promise'; import { ViewsWithCommits } from '../viewBase'; import { AutolinkedItemNode } from './autolinkedItemNode'; import { MessageNode } from './common'; @@ -53,7 +54,7 @@ export class AutolinkedItemsNode extends ViewNode { if (autolinkedMapResult.status === 'fulfilled' && autolinkedMapResult.value != null) { for (const [id, issue] of autolinkedMapResult.value) { - if (issue == null || issue instanceof Promises.CancellationErrorWithId) continue; + if (issue == null || issue instanceof PromiseCancelledErrorWithId) continue; items.set(id, issue); } diff --git a/src/views/nodes/resultsCommitsNode.ts b/src/views/nodes/resultsCommitsNode.ts index 69c64a0..597e703 100644 --- a/src/views/nodes/resultsCommitsNode.ts +++ b/src/views/nodes/resultsCommitsNode.ts @@ -2,7 +2,8 @@ import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import { GitUri } from '../../git/gitUri'; import { GitLog } from '../../git/models'; -import { debug, gate, Iterables, Promises } from '../../system'; +import { debug, gate, Iterables } from '../../system'; +import { cancellable, PromiseCancelledError } from '../../system/promise'; import { ViewsWithCommits } from '../viewBase'; import { AutolinkedItemsNode } from './autolinkedItemsNode'; import { CommitNode } from './commitNode'; @@ -126,7 +127,7 @@ export class ResultsCommitsNode this.triggerChange(false)); } diff --git a/src/views/nodes/resultsFilesNode.ts b/src/views/nodes/resultsFilesNode.ts index b3c2a93..b92ad62 100644 --- a/src/views/nodes/resultsFilesNode.ts +++ b/src/views/nodes/resultsFilesNode.ts @@ -3,8 +3,9 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode'; import { ViewFilesLayout } from '../../configuration'; import { GitUri } from '../../git/gitUri'; import { GitFile } from '../../git/models'; -import { Arrays, debug, gate, Iterables, Promises, Strings } from '../../system'; +import { Arrays, debug, gate, Iterables, Strings } from '../../system'; import { joinPaths, normalizePath } from '../../system/path'; +import { cancellable, PromiseCancelledError } from '../../system/promise'; import { ViewsWithCommits } from '../viewBase'; import { FileNode, FolderNode } from './folderNode'; import { ResultsFileNode } from './resultsFileNode'; @@ -98,7 +99,7 @@ export class ResultsFilesNode extends ViewNode { let state; try { - const results = await Promises.cancellable(this.getFilesQueryResults(), 100); + const results = await cancellable(this.getFilesQueryResults(), 100); label = results.label; files = (this.filtered ? results.filtered?.files : undefined) ?? results.files; @@ -114,7 +115,7 @@ export class ResultsFilesNode extends ViewNode { ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed; } catch (ex) { - if (ex instanceof Promises.CancellationError) { + if (ex instanceof PromiseCancelledError) { ex.promise.then(() => queueMicrotask(() => this.triggerChange(false))); } diff --git a/src/views/searchAndCompareView.ts b/src/views/searchAndCompareView.ts index 7cd64f9..9aea827 100644 --- a/src/views/searchAndCompareView.ts +++ b/src/views/searchAndCompareView.ts @@ -8,7 +8,10 @@ import { GitUri } from '../git/gitUri'; import { GitLog, GitRevision } from '../git/models'; import { SearchPattern } from '../git/search'; import { ReferencePicker, ReferencesQuickPickIncludes } from '../quickpicks'; -import { debug, gate, Iterables, log, Promises } from '../system'; +import { filterMap } from '../system/array'; +import { gate } from '../system/decorators/gate'; +import { debug, log } from '../system/decorators/log'; +import { isPromise } from '../system/promise'; import { CompareResultsNode, ContextValues, @@ -121,9 +124,9 @@ export class SearchAndCompareViewNode extends ViewNode { if (this.children.length === 0) return; const promises: Promise[] = [ - ...Iterables.filterMap(this.children, c => { + ...filterMap(this.children, c => { const result = c.refresh === undefined ? false : c.refresh(); - return Promises.is(result) ? result : undefined; + return isPromise(result) ? result : undefined; }), ]; await Promise.all(promises); diff --git a/src/views/viewBase.ts b/src/views/viewBase.ts index 60d2207..dc6ece8 100644 --- a/src/views/viewBase.ts +++ b/src/views/viewBase.ts @@ -34,7 +34,9 @@ import { } from '../configuration'; import { Container } from '../container'; import { Logger } from '../logger'; -import { debug, Functions, log, Promises } from '../system'; +import { debug, log } from '../system/decorators/log'; +import { debounce } from '../system/function'; +import { cancellable, isPromise } from '../system/promise'; import { BranchesView } from './branchesView'; import { CommitsView } from './commitsView'; import { ContributorsView } from './contributorsView'; @@ -240,7 +242,7 @@ export abstract class ViewBase< this.onConfigurationChanged(e); }, this), this.tree, - this.tree.onDidChangeVisibility(Functions.debounce(this.onVisibilityChanged, 250), this), + this.tree.onDidChangeVisibility(debounce(this.onVisibilityChanged, 250), this), this.tree.onDidCollapseElement(this.onElementCollapsed, this), this.tree.onDidExpandElement(this.onElementExpanded, this), ); @@ -394,7 +396,7 @@ export abstract class ViewBase< if (predicate(node)) return node; if (canTraverse != null) { const traversable = canTraverse(node); - if (Promises.is(traversable)) { + if (isPromise(traversable)) { if (!(await traversable)) continue; } else if (!traversable) { continue; @@ -418,13 +420,9 @@ export abstract class ViewBase< await this.loadMoreNodeChildren(node, defaultPageSize); - pagedChildren = await Promises.cancellable( - Promise.resolve(node.getChildren()), - token ?? 60000, - { - onDidCancel: resolve => resolve([]), - }, - ); + pagedChildren = await cancellable(Promise.resolve(node.getChildren()), token ?? 60000, { + onDidCancel: resolve => resolve([]), + }); child = pagedChildren.find(predicate); if (child != null) return child;