Atlas › Test

session.test|title=sessionFileChangesEqual returns false when one entry is v1 and the other is v2|occurrence=1

Exact test identity: mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns false when one entry is v1 and the other is v2|occurrence=1

Package
mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common
Suite / test hierarchy
session.test|title=sessionFileChangesEqual returns false when one entry is v1 and the other is v2|occurrence=1
Test
session.test|title=sessionFileChangesEqual returns false when one entry is v1 and the other is v2|occurrence=1
Introduced at
session.ts ×1 Frontier kind: Joint frontier
Covered ranges
1226
Covered lines
10712
Covered files
76

Covered source

Expand a file to inspect source; the > gutter marks covered lines.

src/vs/workbench/contrib/chat/common/chatSessionsService.ts 906 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chatSessionsService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CancellationToken } from '../../../../base/common/cancellation.js';
7 > import { Event } from '../../../../base/common/event.js';
8 > import { IMarkdownString } from '../../../../base/common/htmlContent.js';
9 > import { IDisposable } from '../../../../base/common/lifecycle.js';
10 > import { IObservable } from '../../../../base/common/observable.js';
11 > import { ThemeIcon } from '../../../../base/common/themables.js';
12 > import { URI } from '../../../../base/common/uri.js';
13 > import { IPosition } from '../../../../editor/common/core/position.js';
14 > import { isRemoteAgentHostSessionType } from '../../../../platform/agentHost/common/agentHostSessionType.js';
15 > import { createDecorator, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
16 > import { Registry } from '../../../../platform/registry/common/platform.js';
17 > import { LOCAL_AGENT_HOST_SCHEME_PREFIX } from '../../../../platform/agentHost/common/agentHostConnectionsService.js';
18 > import { IChatAgentAttachmentCapabilities, IChatAgentRequest } from './participants/chatAgents.js';
19 > import { IChatEditingSession } from './editing/chatEditingService.js';
20 > import { IChatRequestModeInstructions, IChatRequestVariableData, ISerializableChatModelInputState } from './model/chatModel.js';
21 > import { IChatProgress, IChatResponseErrorDetails, IChatSessionTiming } from './chatService/chatService.js';
22 > import { Target } from './promptSyntax/promptTypes.js';
23 >
24 > export const enum ChatSessionsExtensions {
25 > AsyncActivation = 'workbench.contrib.chatSessions.asyncActivation'
26 > }
27 >
28 > export interface IAsyncChatSessionActivationContribution {
29 > matchSessionType(sessionType: string): boolean;
30 > waitForActivation(accessor: ServicesAccessor, sessionType: string): Promise<boolean>;
31 > }
32 >
33 > export interface IAsyncChatSessionActivationRegistry {
34 > register(contribution: IAsyncChatSessionActivationContribution): IDisposable;
35 > getActivators(sessionType: string): readonly IAsyncChatSessionActivationContribution[];
36 > }
37 >
38 > class AsyncChatSessionActivationRegistry implements IAsyncChatSessionActivationRegistry {
39 > private readonly _contributions = new Set<IAsyncChatSessionActivationContribution>();
40 >
41 > register(contribution: IAsyncChatSessionActivationContribution): IDisposable {
42 this._contributions.add(contribution);
43 return {
45 };
46 }
48 > getActivators(sessionType: string): readonly IAsyncChatSessionActivationContribution[] {
49 return Array.from(this._contributions).filter(contribution => contribution.matchSessionType(sessionType));
50 }
52 >
53 > Registry.add(ChatSessionsExtensions.AsyncActivation, new AsyncChatSessionActivationRegistry());
54 >
55 > export const enum ChatSessionStatus {
56 > Failed = 0,
57 > Completed = 1,
58 > InProgress = 2,
59 > NeedsInput = 3
60 > }
61 >
62 > export interface IChatSessionCommandContribution {
63 > readonly name: string;
64 > readonly description: string;
65 > readonly when?: string;
66 > }
67 >
68 > export interface IChatSessionProviderOptionModelMetadata {
69 > readonly name: string;
70 > readonly id: string;
71 > readonly vendor?: string;
72 > readonly version?: string;
73 > readonly family?: string;
74 > readonly tooltip?: string;
75 > readonly pricing?: string;
76 > readonly multiplierNumeric?: number;
77 > readonly inputCost?: number;
78 > readonly outputCost?: number;
79 > readonly cacheCost?: number;
80 > readonly cacheWriteCost?: number;
81 > readonly longContextInputCost?: number;
82 > readonly longContextOutputCost?: number;
83 > readonly longContextCacheCost?: number;
84 > readonly longContextCacheWriteCost?: number;
85 > readonly priceCategory?: string;
86 > readonly promo?: {
87 > readonly id: string;
88 > readonly discountPercent: number;
89 > readonly endsAt: string;
90 > readonly message: string;
91 > };
92 > readonly maxInputTokens?: number;
93 > readonly maxOutputTokens?: number;
94 > readonly capabilities?: {
95 > readonly vision?: boolean;
96 > readonly toolCalling?: boolean;
97 > };
98 > }
99 >
100 > export interface IChatSessionProviderOptionItem {
101 > readonly id: string;
102 > readonly name: string;
103 > readonly description?: string;
104 > readonly detail?: string;
105 > readonly locked?: boolean;
106 > readonly icon?: ThemeIcon;
107 > readonly default?: boolean;
108 > readonly slashCommand?: string;
109 > readonly tooltip?: string;
110 > readonly modelMetadata?: IChatSessionProviderOptionModelMetadata;
111 > // [key: string]: any;
112 > }
113 >
114 > export interface IChatSessionProviderOptionGroupCommand {
115 > readonly command: string;
116 > readonly title: string;
117 > readonly tooltip?: string;
118 > readonly arguments?: readonly unknown[];
119 > }
120 >
121 > export interface IChatSessionProviderOptionGroup {
122 > readonly id: string;
123 > readonly name: string;
124 > readonly description?: string;
125 > readonly detail?: string;
126 > readonly selected?: IChatSessionProviderOptionItem;
127 > readonly items: readonly IChatSessionProviderOptionItem[];
128 > /**
129 > * A context key expression that controls visibility of this option group picker.
130 > * When specified, the picker is only visible when the expression evaluates to true.
131 > * The expression can reference other option group values via `chatSessionOption.<groupId>`.
132 > * Example: `"chatSessionOption.models == 'gpt-4'"`
133 > */
134 > readonly when?: string;
135 > readonly icon?: ThemeIcon;
136 > /**
137 > * Custom commands to show in the option group's picker UI.
138 > * These will be shown in a separate section at the end of the picker.
139 > */
140 > readonly commands?: readonly IChatSessionProviderOptionGroupCommand[];
141 > /**
142 > * Optional kind hint that controls how the group is presented.
143 > * - `'permissions'`: the group's items are surfaced inside the chat permission picker
144 > * instead of being rendered as a standalone picker. At most one group per provider
145 > * may use this kind; if multiple are declared, the first one (in declaration order)
146 > * wins. The group has no UI of its own — it is invisible when the permission
147 > * picker is hidden by its own `when` clauses.
148 > */
149 > readonly kind?: 'permissions';
150 > }
151 >
152 > export interface IChatSessionsExtensionPoint {
153 > readonly type: string;
154 > readonly name: string;
155 > readonly displayName: string;
156 > readonly description: string;
157 > readonly when?: string;
158 > readonly icon?: string | { light: string; dark: string };
159 > readonly order?: number;
160 > readonly alternativeIds?: string[];
161 > readonly welcomeTitle?: string;
162 > readonly welcomeMessage?: string;
163 > readonly welcomeTips?: string;
164 > readonly inputPlaceholder?: string;
165 > readonly capabilities?: IChatAgentAttachmentCapabilities;
166 > readonly commands?: IChatSessionCommandContribution[];
167 > readonly canDelegate?: boolean;
168 > readonly isReadOnly?: boolean;
169 > /**
170 > * When set, the chat session will show a filtered mode picker with custom agents
171 > * that have a matching `target` property. This enables contributed chat sessions
172 > * to reuse the standard agent/mode dropdown with filtered custom agents.
173 > * Custom agents without a `target` property are also shown in all filtered lists
174 > */
175 > readonly customAgentTarget?: Target;
176 > readonly requiresCustomModels?: boolean;
177 > /**
178 > * Whether this session type supports the synthetic "Auto" model fallback.
179 > * Defaults to true. When false and no models are available, the picker
180 > * shows a "No models available" state instead of "Auto".
181 > *
182 > * This is distinct from {@link requiresCustomModels}, which only controls
183 > * whether the picker is filtered to the session's own model pool — a
184 > * session can own a custom pool yet still support Auto (e.g. the Copilot
185 > * CLI agent host).
186 > */
187 > readonly supportsAutoModel?: boolean;
188 > /**
189 > * Logical Agent Host provider ID for Agent Host-backed chat sessions.
190 > * For example, both local `agent-host-copilotcli` and remote
191 > * `remote-{authority}-copilotcli` sessions use `copilotcli`.
192 > */
193 > readonly agentHostProviderId?: string;
194 > /**
195 > * Whether this type needs a GitHub Copilot account and so is unusable until the user signs in. Set by
196 > * Copilot-backed types (Copilot CLI / agent host, cloud agent) where BYOK isn't supported. Defaults to false, so
197 > * third-party types that don't depend on Copilot stay usable while signed out.
198 > */
199 > readonly requiresCopilotSignIn?: boolean;
200 > /**
201 > * When false, the delegation picker is hidden for this session type.
202 > * Defaults to true.
203 > */
204 > readonly supportsDelegation?: boolean;
205 > /**
206 > * Decides whether to automatically attach instruction files to chat requests
207 > * for this session type. Defaults to false when not specified.
208 > */
209 > readonly autoAttachReferences?: boolean;
210 > }
211 >
212 > export interface IChatSessionItem {
213 > readonly resource: URI;
214 > readonly label: string;
215 > readonly iconPath?: ThemeIcon;
216 > readonly badge?: string | IMarkdownString;
217 > readonly description?: string | IMarkdownString;
218 > readonly status?: ChatSessionStatus;
219 > readonly tooltip?: string | IMarkdownString;
220 > readonly timing: IChatSessionTiming;
221 > readonly changes?: {
222 > readonly files: number;
223 > readonly insertions: number;
224 > readonly deletions: number;
225 > } | readonly IChatSessionFileChange[] | readonly IChatSessionFileChange2[];
226 > readonly archived?: boolean;
227 > readonly metadata?: IChatSessionItemMetadata;
228 > /**
229 > * Resource identifier the item was previously known by. When set, host-stored
230 > * per-resource state (archive, pin, read) recorded under that URI is adopted
231 > * forward onto {@link resource} on first state read, and the legacy entry is
232 > * removed. Scheme must match {@link resource}'s scheme; otherwise ignored.
233 > */
234 > readonly legacyResource?: URI;
235 > }
236 >
237 > export interface IChatSessionItemMetadata {
238 > //#region Changes metadata (for sessions window)
239 > readonly repositoryPath?: string;
240 > readonly workingDirectoryPath?: string;
241 > readonly firstCheckpointRef?: string;
242 > readonly lastCheckpointRef?: string;
243 > readonly worktreePath?: string;
244 > readonly uncommittedChanges?: number;
245 > readonly baseRefOid?: string;
246 > readonly headRefOid?: string;
247 > readonly branchName?: string;
248 > readonly branch?: string;
249 > readonly baseBranchName?: string;
250 > readonly baseBranch?: string;
251 > readonly baseBranchProtected?: boolean;
252 > readonly hasGitHubRemote?: boolean;
253 > readonly upstreamBranchName?: string;
254 > readonly incomingChanges?: number;
255 > readonly outgoingChanges?: number;
256 > //#endregion
257 >
258 > readonly [key: string]: unknown;
259 > }
260 >
261 > export interface IChatSessionFileChange {
262 > readonly modifiedUri: URI;
263 > readonly originalUri?: URI;
264 > readonly insertions: number;
265 > readonly deletions: number;
266 > readonly reviewed?: boolean;
267 > }
268 >
269 > export interface IChatSessionFileChange2 {
270 > readonly uri: URI;
271 > readonly originalUri?: URI;
272 > readonly modifiedUri?: URI;
273 > readonly insertions: number;
274 > readonly deletions: number;
275 > readonly reviewed?: boolean;
276 > }
277 >
278 > export type IChatSessionHistoryItem = {
279 > id?: string;
280 > type: 'request';
281 > prompt: string;
282 > participant: string;
283 > command?: string;
284 > variableData?: IChatRequestVariableData;
285 > modelId?: string;
286 > timestamp?: number;
287 > modeInstructions?: IChatRequestModeInstructions;
288 > isSystemInitiated?: boolean;
289 > systemInitiatedLabel?: string;
290 > isTerminalRequest?: boolean;
291 > } | {
292 > type: 'response';
293 > parts: IChatProgress[];
294 > participant: string;
295 > details?: string;
296 > elapsedMs?: number;
297 > completedAt?: number;
298 > /**
299 > * Error details for a failed response. Rendered as a proper chat error
300 > * (including the quota-exceeded upgrade affordance), mirroring the live
301 > * agent result's `errorDetails`.
302 > */
303 > errorDetails?: IChatResponseErrorDetails;
304 > };
305 >
306 > export type IChatSessionRequestHistoryItem = Extract<IChatSessionHistoryItem, { type: 'request' }>;
307 >
308 > export interface IChatSessionServerRequest {
309 > readonly prompt: string;
310 > readonly variableData?: IChatRequestVariableData;
311 > readonly timestamp?: number;
312 > readonly isSystemInitiated?: boolean;
313 > readonly systemInitiatedLabel?: string;
314 > readonly isTerminalRequest?: boolean;
315 > }
316 >
317 > /**
318 > * Whether `text` runs as a terminal command for the given command `prefix`
319 > * (e.g. `!`) — it starts with the prefix and has a non-empty command after it.
320 > * Mirrors the agent host's bang parser, where a lone `!` (or `!` followed only
321 > * by whitespace) is forwarded to the agent rather than executed.
322 > */
323 > export function isTerminalCommandPrompt(text: string, prefix: string | undefined): boolean {
324 return !!prefix && text.startsWith(prefix) && text.slice(prefix.length).trim().length > 0;
325 }
327 > /**
328 > * A set of well-known session types
329 > */
330 > export namespace SessionType {
331 > export const CopilotCLI = 'copilotcli';
332 > export const CopilotCloud = 'copilot-cloud-agent';
333 > export const Local = 'local';
334 > export const ClaudeCode = 'claude-code';
335 > export const Codex = 'openai-codex';
336 > export const Growth = 'copilot-growth';
337 > export const AgentHostCopilot = 'agent-host-copilotcli';
338 > export const AgentHostClaude = 'agent-host-claude';
339 > export const AgentHostCodex = 'agent-host-codex';
340 > }
341 >
342 > /**
343 > * Returns whether the given session type is a local agent host target.
344 > */
345 > export function isLocalAgentHostTarget(target: string): boolean {
346 return target === SessionType.AgentHostCopilot ||
347 target.startsWith(LOCAL_AGENT_HOST_SCHEME_PREFIX);
348 }
350 > /**
351 > * Returns whether the given session type is a remote agent host target.
352 > *
353 > * Note: The `remote-` prefix convention is established by
354 > * `RemoteAgentHostContribution` which generates session types as
355 > * `remote-{sanitizedAddress}-{provider}`. If future remote providers that
356 > * are NOT agent hosts need a different prefix, this function must be updated.
357 > */
358 > export function isRemoteAgentHostTarget(target: string): boolean {
359 return isRemoteAgentHostSessionType(target);
360 }
362 > /**
363 > * Returns whether the given session type is an agent host target.
364 > * Matches the local agent host (`agent-host-*`) and remote agent hosts (`remote-*`).
365 > */
366 > export function isAgentHostTarget(target: string): boolean {
367 return isLocalAgentHostTarget(target) || isRemoteAgentHostTarget(target);
368 }
370 > /**
371 > * The session type used for local agent chat sessions.
372 > */
373 > export const localChatSessionType = SessionType.Local;
374 >
375 > export interface IChatSession extends IDisposable {
376 > readonly onWillDispose: Event<void>;
377 >
378 > readonly sessionResource: URI;
379 >
380 > readonly title?: string;
381 >
382 > readonly history: readonly IChatSessionHistoryItem[];
383 >
384 >
385 > readonly options?: ReadonlyChatSessionOptionsMap;
386 >
387 > readonly progressObs?: IObservable<IChatProgress[]>;
388 > readonly isCompleteObs?: IObservable<boolean>;
389 > readonly isReadOnly?: IObservable<boolean>;
390 > readonly interruptActiveResponseCallback?: () => Promise<boolean>;
391 >
392 > /**
393 > * Event fired when the server initiates a new request (e.g. from a consumed
394 > * queued message). The consumer should create a new request+response pair in
395 > * the model and prepare to receive progress via {@link progressObs}.
396 > */
397 > readonly onDidStartServerRequest?: Event<IChatSessionServerRequest>;
398 >
399 > /**
400 > * Editing session transferred from a previously-untitled chat session in `onDidCommitChatSessionItem`.
401 > */
402 > transferredState?: {
403 > readonly editingSession: IChatEditingSession | undefined;
404 > readonly inputState: ISerializableChatModelInputState | undefined;
405 > };
406 >
407 > requestHandler?: (
408 > request: IChatAgentRequest,
409 > progress: (progress: IChatProgress[]) => void,
410 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
411 > history: any[], // TODO: Nail down types
412 > token: CancellationToken
413 > ) => Promise<void>;
414 >
415 > /**
416 > * Forks the session from the given request point.
417 > * @param request The request history item to fork from, or undefined to fork from the end.
418 > * @param token Cancellation token.
419 > * @returns The forked session item. The promise is rejected if forking fails.
420 > */
421 > forkSession?: (request: IChatSessionRequestHistoryItem | undefined, token: CancellationToken) => Promise<IChatSessionItem>;
422 >
423 > /**
424 > * Renames the session.
425 > * @param title The new title for the session.
426 > * @param token Cancellation token.
427 > * @returns A promise that resolves once the rename has been dispatched. The promise is rejected if renaming fails.
428 > */
429 > renameSession?: (title: string, token: CancellationToken) => Promise<void>;
430 > }
431 >
432 > export interface IChatSessionContentProvider {
433 > provideChatSessionContent(sessionResource: URI, token: CancellationToken): Promise<IChatSession>;
434 >
435 > /** Resolves a parsed response Markdown URI before it is sanitized and rendered. */
436 > resolveChatResponseUri?(sessionResource: URI, href: string, kind: 'link' | 'image'): string;
437 >
438 > /**
439 > * Optional. Compute completion items for an input being composed in this
440 > * session. Returning `undefined` lets the workbench fall back to its
441 > * default in-process completion providers.
442 > */
443 > provideChatInputCompletions?(sessionResource: URI, params: IChatInputCompletionsParams, token: CancellationToken): Promise<IChatInputCompletionsResult | undefined>;
444 >
445 > /**
446 > * Optional. Trigger characters that, when typed in the chat input,
447 > * SHOULD cause the workbench to issue a `provideChatInputCompletions`
448 > * request. Used to register a Monaco completion provider scoped to
449 > * sessions handled by this content provider.
450 > */
451 > provideChatInputCompletionTriggerCharacters?(): Promise<readonly string[]>;
452 > }
453 >
454 > /**
455 > * Inputs for {@link IChatSessionContentProvider.provideChatInputCompletions}
456 > * and {@link IChatSessionsService.provideChatInputCompletions}.
457 > */
458 > export interface IChatInputCompletionsParams {
459 > /**
460 > * The complete text of the input being completed (e.g. the user message
461 > * the user is currently composing).
462 > */
463 > readonly text: string;
464 > /**
465 > * The character offset within {@link text} at which the completion is
466 > * requested, measured in UTF-16 code units. MUST satisfy
467 > * `0 <= offset <= text.length`.
468 > */
469 > readonly offset: number;
470 > }
471 >
472 > /**
473 > * A neutral completion-item shape returned by
474 > * {@link IChatSessionContentProvider.provideChatInputCompletions}. The
475 > * workbench-side completion glue maps these into Monaco completion items
476 > * and the corresponding chat-input attachment.
477 > */
478 > export interface IChatInputCompletionItem {
479 > /** Text inserted into the input when this item is accepted. */
480 > readonly insertText: string;
481 > /**
482 > * Optional display label shown in the completion picker. When omitted, the
483 > * workbench displays {@link insertText}. Set this when the inserted text
484 > * differs from the label — e.g. an action item that inserts nothing
485 > * (`insertText: ''`) but should still be shown to the user.
486 > */
487 > readonly label?: string;
488 > /**
489 > * Half-open range `[start, end)` in the *current* input text that
490 > * {@link insertText} replaces. Positions use 1-based `lineNumber` and
491 > * `column` to match Monaco. When omitted, the workbench replaces the
492 > * word at the cursor.
493 > */
494 > readonly start?: IPosition;
495 > readonly end?: IPosition;
496 > /** Attachment associated with the item. */
497 > readonly attachment: IChatInputCompletionResourceAttachment | IChatInputCompletionCommandAttachment | IChatInputCompletionSkillAttachment;
498 > }
499 >
500 > /**
501 > * Resource attachment associated with a completion item. The workbench
502 > * adds it to the input's variable model when the item is accepted.
503 > */
504 > export interface IChatInputCompletionResourceAttachment {
505 > readonly kind: 'resource';
506 > readonly uri: URI;
507 > readonly displayName?: string;
508 > readonly isDirectory?: boolean;
509 > /**
510 > * Implementation-defined metadata that MUST be preserved by the
511 > * workbench when the accepted completion is sent back as part of a
512 > * user message attachment.
513 > */
514 > readonly _meta?: Record<string, unknown>;
515 > }
516 >
517 > /**
518 > * Command attachment associated with a completion item.
519 > */
520 > export interface IChatInputCompletionCommandAttachment {
521 > readonly kind: 'command';
522 > readonly command: string;
523 > readonly description: string;
524 > /**
525 > * Implementation-defined metadata that MUST be preserved by the
526 > * workbench when the accepted completion is sent back as part of a
527 > * user message attachment.
528 > */
529 > readonly _meta?: Record<string, unknown>;
530 > }
531 >
532 > /**
533 > * Skill attachment associated with a completion item. The workbench
534 > * adds it to the input's variable model when the item is accepted.
535 > */
536 > export interface IChatInputCompletionSkillAttachment {
537 > readonly kind: 'skill';
538 > readonly uri: URI;
539 > readonly displayName?: string;
540 > readonly description?: string;
541 > /**
542 > * Implementation-defined metadata that MUST be preserved by the
543 > * workbench when the accepted completion is sent back as part of a
544 > * user message attachment.
545 > */
546 > readonly _meta?: Record<string, unknown>;
547 > }
548 >
549 > /**
550 > * Result of {@link IChatSessionContentProvider.provideChatInputCompletions}.
551 > */
552 > export interface IChatInputCompletionsResult {
553 > readonly items: readonly IChatInputCompletionItem[];
554 > }
555 >
556 > export interface IChatNewSessionRequest {
557 > readonly prompt: string;
558 > readonly command?: string;
559 >
560 > readonly initialSessionOptions?: ReadonlyChatSessionOptionsMap;
561 >
562 > /**
563 > * The chat-input session resource the user was typing into when this
564 > * request was issued. Set when the chat infrastructure is rewriting an
565 > * untitled session URI to a real one on first send. Controllers can use
566 > * this to bridge any pre-creation state they tracked under the old URI
567 > * (e.g. provisional agent-host sessions) to the new resource that the
568 > * controller returns.
569 > */
570 > readonly untitledResource?: URI;
571 > }
572 >
573 > export interface IChatSessionItemsDelta {
574 > readonly addedOrUpdated?: readonly IChatSessionItem[];
575 > readonly removed?: readonly URI[];
576 > }
577 >
578 > export interface IChatSessionItemController {
579 >
580 > readonly onDidChangeChatSessionItems: Event<IChatSessionItemsDelta>;
581 >
582 > get items(): readonly IChatSessionItem[];
583 >
584 > refresh(token: CancellationToken): Promise<void>;
585 >
586 > newChatSessionItem?(request: IChatNewSessionRequest, token: CancellationToken): Promise<IChatSessionItem | undefined>;
587 >
588 > getNewChatSessionInputState?(sessionResource: URI, token: CancellationToken): Promise<readonly IChatSessionProviderOptionGroup[] | undefined>;
589 >
590 > resolveChatSessionItem?(resource: URI, token: CancellationToken): Promise<IChatSessionItem | undefined>;
591 >
592 > /**
593 > * Permanently delete the session identified by `resource`. Implementations should tear down any backend state for
594 > * the session. The controller is expected to fire an `onDidChangeChatSessionItems` event with the removed resource
595 > * as a result of the deletion.
596 > */
597 > deleteChatSessionItem?(resource: URI, token: CancellationToken): Promise<void>;
598 >
599 > /**
600 > * Set the authoritative archived state for the session identified by `resource`.
601 > */
602 > setChatSessionItemArchived?(resource: URI, archived: boolean): void;
603 > }
604 >
605 > export interface IChatSessionOptionsChangeEvent {
606 > readonly sessionResource: URI;
607 > readonly updates: ReadonlyMap<string, string | IChatSessionProviderOptionItem | undefined>;
608 > }
609 >
610 > export type ResolvedChatSessionsExtensionPoint = Omit<IChatSessionsExtensionPoint, 'icon'> & {
611 > readonly icon: ThemeIcon | URI | undefined;
612 > };
613 >
614 > /**
615 > * Session options as key-value pairs.
616 > *
617 > * Keys correspond to option group IDs (e.g., 'models', 'subagents') and values are either the selected option item IDs (string) or full option items (for locked state).
618 > */
619 > export type ChatSessionOptionsMap = Map<string, string | IChatSessionProviderOptionItem>;
620 >
621 > export namespace ChatSessionOptionsMap {
622 > export function fromRecord(obj: { [key: string]: string | IChatSessionProviderOptionItem }): ChatSessionOptionsMap {
623 return new Map(Object.entries(obj));
624 }
626 > export function toRecord(map: ReadonlyChatSessionOptionsMap): Record<string, string | IChatSessionProviderOptionItem> {
627 const record: Record<string, string | IChatSessionProviderOptionItem> = Object.create(null);
628 const entries = ensureIterable(map);
632 return record;
633 }
635 > export function toStrValueArray(map: ReadonlyChatSessionOptionsMap | undefined): Array<{ optionId: string; value: string }> | undefined {
636 if (!map) {
637 return undefined;
640 return Array.from(entries, ([optionId, value]) => ({ optionId, value: typeof value === 'string' ? value : value.id }));
641 }
643 > /**
644 > * Ensures the input is iterable. If a plain object is passed (e.g. due to
645 > * serialization across process boundaries losing the Map prototype), it is
646 > * converted to Map entries on the fly.
647 > */
648 > function ensureIterable(map: ReadonlyChatSessionOptionsMap): Iterable<[string, string | IChatSessionProviderOptionItem]> {
649 if (map instanceof Map) {
650 return map;
653 return Object.entries(map as unknown as Record<string, string | IChatSessionProviderOptionItem>);
654 }
656 >
657 > /**
658 > * Readonly version of {@link ChatSessionOptionsMap}
659 > */
660 > export type ReadonlyChatSessionOptionsMap = ReadonlyMap<string, string | IChatSessionProviderOptionItem>;
661 >
662 > export interface IChatSessionCustomizationItem {
663 > readonly label: string;
664 > readonly description?: string;
665 > readonly uri: URI;
666 > readonly storageLocation: number;
667 > readonly icon?: ThemeIcon;
668 > }
669 >
670 > export interface IChatSessionCustomizationItemGroup {
671 > readonly id: string;
672 > readonly items: IChatSessionCustomizationItem[];
673 > readonly commands?: readonly { readonly id: string; readonly title: string; readonly arguments?: readonly unknown[] }[];
674 > readonly itemCommands?: readonly { readonly id: string; readonly title: string; readonly arguments?: readonly unknown[] }[];
675 > }
676 >
677 > export interface IChatSessionCustomizationsProvider {
678 > readonly onDidChangeCustomizations: Event<void>;
679 > provideCustomizations(token: CancellationToken): Promise<IChatSessionCustomizationItemGroup[] | undefined>;
680 > }
681 >
682 >
683 > export interface IChatSessionCommitEvent {
684 > /** The original (untitled) session resource. */
685 > readonly original: URI;
686 > /** The committed (real) session resource. */
687 > readonly committed: URI;
688 > }
689 >
690 > export const IChatSessionsService = createDecorator<IChatSessionsService>('chatSessionsService');
691 >
692 > export interface IChatSessionsService {
693 > readonly _serviceBrand: undefined;
694 >
695 > // #region Chat session item provider support
696 > readonly onDidChangeItemsProviders: Event<{ readonly chatSessionType: string }>;
697 > readonly onDidChangeSessionItems: Event<IChatSessionItemsDelta>;
698 >
699 > /**
700 > * Fired when an untitled session is committed (URI swapped to a real resource)
701 > * after the first turn completes.
702 > */
703 > readonly onDidCommitSession: Event<IChatSessionCommitEvent>;
704 >
705 > readonly onDidChangeAvailability: Event<void>;
706 > readonly onDidChangeInProgress: Event<void>;
707 >
708 > getChatSessionContribution(chatSessionType: string): ResolvedChatSessionsExtensionPoint | undefined;
709 > getAllChatSessionContributions(): ResolvedChatSessionsExtensionPoint[];
710 >
711 > /**
712 > * Programmatically register a chat session contribution (for internal session types
713 > * that don't go through the extension point).
714 > */
715 > registerChatSessionContribution(contribution: IChatSessionsExtensionPoint): IDisposable;
716 >
717 > registerChatSessionItemController(chatSessionType: string, controller: IChatSessionItemController): IDisposable;
718 > getRegisteredChatSessionItemProviders(): readonly string[];
719 > activateChatSessionItemProvider(chatSessionType: string): Promise<void>;
720 >
721 > /**
722 > * Get the list of current chat session items grouped by session type.
723 > *
724 > * @param providerTypeFilter If specified, only returns items from the given providers. If undefined, returns items from all providers.
725 > *
726 > * @returns An async iterable that produces the list of session items for each provider. The order is not guaranteed. Some provider may take a long time to resolve.
727 > */
728 > getChatSessionItems(providerTypeFilter: readonly string[] | undefined, token: CancellationToken): AsyncIterable<{ readonly chatSessionType: string; readonly items: readonly IChatSessionItem[] }>;
729 >
730 > /**
731 > * Forces the controllers to refresh their session items, optionally filtered by provider type.
732 > */
733 > refreshChatSessionItems(providerTypeFilter: readonly string[] | undefined, token: CancellationToken): Promise<void>;
734 >
735 > /** @deprecated Use `getChatSessionItems` */
736 > getInProgress(): { chatSessionType: string; count: number }[];
737 >
738 > /**
739 > * Lazily resolves a chat session item, filling in expensive details like timing, changes, and badge.
740 > * Returns the resolved item, or undefined if no resolve handler is available.
741 > */
742 > resolveChatSessionItem(chatSessionType: string, resource: URI, token: CancellationToken): Promise<IChatSessionItem | undefined>;
743 >
744 > /**
745 > * Whether the registered item controller owns archived state for the session.
746 > */
747 > canSetChatSessionItemArchived(sessionResource: URI): boolean;
748 >
749 > /**
750 > * Sets archived state by delegating to the registered item controller.
751 > */
752 > setChatSessionItemArchived(sessionResource: URI, archived: boolean): void;
753 >
754 > // #endregion
755 >
756 > // #region Content provider support
757 > readonly onDidChangeContentProviderSchemes: Event<{ readonly added: string[]; readonly removed: string[] }>;
758 >
759 > getContentProviderSchemes(): string[];
760 >
761 > registerChatSessionContentProvider(scheme: string, provider: IChatSessionContentProvider): IDisposable;
762 > canResolveChatSession(sessionType: string): Promise<boolean>;
763 > getOrCreateChatSession(sessionResource: URI, token: CancellationToken): Promise<IChatSession>;
764 > /** Resolves a parsed response Markdown URI through its session content provider. */
765 > resolveChatResponseUri(sessionResource: URI, href: string, kind: 'link' | 'image'): string;
766 >
767 > /**
768 > * Compute completion items for an input being composed in the chat
769 > * session identified by `sessionResource`. Delegates to the registered
770 > * {@link IChatSessionContentProvider} for the session, if it implements
771 > * {@link IChatSessionContentProvider.provideChatInputCompletions}.
772 > * Returns `undefined` when no provider is available, in which case the
773 > * workbench's default in-process providers should be used.
774 > */
775 > provideChatInputCompletions(sessionResource: URI, params: IChatInputCompletionsParams, token: CancellationToken): Promise<IChatInputCompletionsResult | undefined>;
776 >
777 > /**
778 > * Trigger characters announced by the content provider for the given
779 > * session type. Used to dynamically register Monaco completion
780 > * providers per content-provider scheme. Returns `undefined` when the
781 > * scheme has no content provider, or `[]` when the provider does not
782 > * announce any trigger characters.
783 > */
784 > getChatInputCompletionTriggerCharacters(sessionType: string): Promise<readonly string[] | undefined>;
785 >
786 > getSessionOptions(sessionResource: URI): ReadonlyChatSessionOptionsMap | undefined;
787 > getSessionOption(sessionResource: URI, optionId: string): string | IChatSessionProviderOptionItem | undefined;
788 > setSessionOption(sessionResource: URI, optionId: string, value: string | IChatSessionProviderOptionItem): boolean;
789 > updateSessionOptions(sessionResource: URI, updates: ReadonlyChatSessionOptionsMap): boolean;
790 >
791 > /**
792 > * Fired when options for a chat session change.
793 > */
794 > readonly onDidChangeSessionOptions: Event<IChatSessionOptionsChangeEvent>;
795 >
796 > /**
797 > * Get the capabilities for a specific session type
798 > */
799 > getCapabilitiesForSessionType(chatSessionType: string): IChatAgentAttachmentCapabilities | undefined;
800 >
801 > /**
802 > * Get the customAgentTarget for a specific session type.
803 > * When the Target is not `Target.Undefined`, the mode picker should show filtered custom agents matching this target.
804 > */
805 > getCustomAgentTargetForSessionType(chatSessionType: string): Target;
806 >
807 > /**
808 > * Returns whether the session type requires custom models. When true, the model picker should show filtered custom models.
809 > */
810 > requiresCustomModelsForSessionType(chatSessionType: string): boolean;
811 >
812 > /**
813 > * Returns whether the session type supports the synthetic "Auto" model
814 > * fallback. The built-in local chat always supports it; contributed session
815 > * types default to `false` unless they set `supportsAutoModel`. When false
816 > * and no models are available, the picker shows a "No models available"
817 > * state instead of "Auto".
818 > */
819 > supportsAutoModelForSessionType(chatSessionType: string): boolean;
820 >
821 > /**
822 > * Whether the session type needs a Copilot account and so is unusable until the user signs in (BYOK isn't
823 > * supported). Defaults to false, so third-party types stay usable while signed out.
824 > */
825 > requiresCopilotSignInForSessionType(chatSessionType: string): boolean;
826 >
827 > /**
828 > * Returns whether the session type supports delegation.
829 > * Defaults to true when not explicitly set.
830 > */
831 > supportsDelegationForSessionType(chatSessionType: string): boolean;
832 >
833 > /**
834 > * Returns whether the loaded session supports forking conversations.
835 > */
836 > sessionSupportsFork(sessionResource: URI): boolean;
837 >
838 > /**
839 > * Forks a contributed chat session from the given request point.
840 > * @param sessionResource The session resource to fork.
841 > * @param request The request history item to fork from, or undefined to fork from the end.
842 > * @param token Cancellation token.
843 > * @returns The forked session item, or undefined if forking failed.
844 > */
845 > forkChatSession(sessionResource: URI, request: IChatSessionRequestHistoryItem | undefined, token: CancellationToken): Promise<IChatSessionItem>;
846 >
847 > /**
848 > * Returns whether the loaded session supports renaming.
849 > */
850 > sessionSupportsRename(sessionResource: URI): boolean;
851 >
852 > /**
853 > * Renames a contributed chat session.
854 > * @param sessionResource The session resource to rename.
855 > * @param title The new title for the session.
856 > * @param token Cancellation token.
857 > */
858 > renameChatSession(sessionResource: URI, title: string, token: CancellationToken): Promise<void>;
859 >
860 > readonly onDidChangeOptionGroups: Event<string>;
861 >
862 > getOptionGroupsForSessionType(chatSessionType: string): IChatSessionProviderOptionGroup[] | undefined;
863 > setOptionGroupsForSessionType(chatSessionType: string, handle: number, optionGroups?: readonly IChatSessionProviderOptionGroup[]): void;
864 >
865 > /**
866 > * Get the default options for new sessions of this type, derived from option groups'
867 > * `selected` or `default` items.
868 > */
869 > getNewChatSessionInputState(chatSessionType: string, sessionResource: URI): Promise<readonly IChatSessionProviderOptionGroup[] | undefined>;
870 >
871 > /**
872 > * Creates a new chat session item using the controller's newChatSessionItemHandler.
873 > * Returns undefined if the controller doesn't have a handler or if no controller is registered.
874 > */
875 > createNewChatSessionItem(chatSessionType: string, request: IChatNewSessionRequest, token: CancellationToken): Promise<IChatSessionItem | undefined>;
876 >
877 > /**
878 > * Permanently deletes a chat session item by delegating to the registered controller's `deleteChatSessionItem`
879 > * handler. Throws if the controller does not implement `deleteChatSessionItem`.
880 > */
881 > deleteChatSessionItem(sessionResource: URI, token: CancellationToken): Promise<void>;
882 >
883 > /**
884 > * Records the inverse `real → untitled` alias so option lookups for the real
885 > * session resolve to the untitled session's entry (e.g. {@link updateSessionOptions}).
886 > *
887 > * Call this BEFORE the real session loads, and never remove it — the real
888 > * session keeps reading its options through this alias even after the untitled
889 > * model is disposed. (Only the forward mapping is cleared, via
890 > * {@link clearMaterializedSessionResource}.) Publishing the forward mapping is a
891 > * separate step; see {@link setMaterializedSessionResource}.
892 > */
893 > registerSessionResourceAlias(untitledResource: URI, realResource: URI): void;
894 >
895 > /**
896 > * Records the forward `untitled → real` mapping (read via
897 > * {@link getMaterializedSessionResource}) so a late send still addressed to the
898 > * untitled resource re-targets the real session. Call this only AFTER the real
899 > * session has loaded.
900 > *
901 > * Kept separate from {@link registerSessionResourceAlias} on purpose: the
902 > * inverse alias must exist BEFORE the load (for option lookups), but this
903 > * forward mapping must appear only AFTER the real session exists — published
904 > * earlier, a failed or still-loading session would be re-targeted before it
905 > * exists (a later send would throw "Unknown session").
906 > */
907 > setMaterializedSessionResource(untitledResource: URI, realResource: URI): void;
908 >
909 > /**
910 > * Returns the real session resource that `untitledResource` materialized
911 > * into (via {@link setMaterializedSessionResource}), or `undefined` if it has
912 > * not materialized or the mapping was already cleared.
913 > */
914 > getMaterializedSessionResource(untitledResource: URI): URI | undefined;
915 >
916 > /**
917 > * Clears the forward `untitled → real` mapping for `sessionResource` (passed
918 > * either the untitled key or the real value), so {@link getMaterializedSessionResource}
919 > * stops re-targeting once the session is disposed. Does NOT remove the inverse
920 > * alias, which is intentionally permanent (see {@link registerSessionResourceAlias}).
921 > */
922 > clearMaterializedSessionResource(sessionResource: URI): void;
923 >
924 > /**
925 > * Fires {@link onDidCommitSession} to notify listeners that an untitled
926 > * session has been committed with a real resource URI.
927 > */
928 > fireSessionCommitted(original: URI, committed: URI): void;
929 >
930 > // #region Customizations provider support
931 > readonly onDidChangeCustomizations: Event<{ readonly chatSessionType: string }>;
932 > registerCustomizationsProvider(chatSessionType: string, provider: IChatSessionCustomizationsProvider): IDisposable;
933 > hasCustomizationsProvider(chatSessionType: string): boolean;
934 > getCustomizations(chatSessionType: string, token: CancellationToken): Promise<IChatSessionCustomizationItemGroup[] | undefined>;
935 > // #endregion
936 > }
937 >
938 > export function isSessionInProgressStatus(state: ChatSessionStatus): boolean {
939 return state === ChatSessionStatus.InProgress || state === ChatSessionStatus.NeedsInput;
940 }
942 > export function isIChatSessionFileChange2(obj: unknown): obj is IChatSessionFileChange2 {
943 > const candidate = obj as IChatSessionFileChange2; chatSessionsService.ts
944 > return candidate && candidate.uri instanceof URI && typeof candidate.insertions === 'number' && typeof candidate.deletions === 'number';
945 > }
src/vs/base/common/event.ts 839 covered LOC · 93 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- event.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CancelablePromise } from './async.js';
7 > import { CancellationToken } from './cancellation.js';
8 > import { diffSets } from './collections.js';
9 > import { onUnexpectedError } from './errors.js';
10 > import { createSingleCallFunction } from './functional.js';
11 > import { combinedDisposable, Disposable, DisposableMap, DisposableStore, IDisposable, toDisposable } from './lifecycle.js';
12 > import { LinkedList } from './linkedList.js';
13 > import { IObservable, IObservableWithChange, IObserver } from './observable.js';
14 > import { env } from './process.js';
15 > import { StopWatch } from './stopwatch.js';
16 > import { MicrotaskDelay } from './symbols.js';
17 >
18 >
19 > // -----------------------------------------------------------------------------------------------------------------------
20 > // Uncomment the next line to print warnings whenever an emitter with listeners is disposed. That is a sign of code smell.
21 > // -----------------------------------------------------------------------------------------------------------------------
22 > const _enableDisposeWithListenerWarning = false
23 > // || Boolean("TRUE") // causes a linter warning so that it cannot be pushed
24 > ;
25 >
26 >
27 > // -----------------------------------------------------------------------------------------------------------------------
28 > // Uncomment the next line to print warnings whenever a snapshotted event is used repeatedly without cleanup.
29 > // See https://github.com/microsoft/vscode/issues/142851
30 > // -----------------------------------------------------------------------------------------------------------------------
31 > const _enableSnapshotPotentialLeakWarning = false
32 > // || Boolean("TRUE") // causes a linter warning so that it cannot be pushed
33 > ;
34 >
35 >
36 > const _bufferLeakWarnCountThreshold = 100;
37 > const _bufferLeakWarnTimeThreshold = 60_000; // 1 minute
38 >
39 function _isBufferLeakWarningEnabled(): boolean {
40 return !!env['VSCODE_DEV'];
41 }
42 > event.ts
43 > /**
44 > * An event with zero or one parameters that can be subscribed to. The event is a function itself.
45 > */
46 > export interface Event<T> {
47 > (listener: (e: T) => unknown, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;
48 > }
49 >
50 > export namespace Event {
51 > export const None: Event<any> = () => Disposable.None;
52 >
53 > function _addLeakageTraceLogic(options: EmitterOptions) {
54 if (_enableSnapshotPotentialLeakWarning) {
55 const { onDidAddListener: origListenerDidAdd } = options;
65 }
66 }
67 > event.ts
68 > /**
69 > * Given an event, returns another event which debounces calls and defers the listeners to a later task via a shared
70 > * `setTimeout`. The event is converted into a signal (`Event<void>`) to avoid additional object creation as a
71 > * result of merging events and to try prevent race conditions that could arise when using related deferred and
72 > * non-deferred events.
73 > *
74 > * This is useful for deferring non-critical work (eg. general UI updates) to ensure it does not block critical work
75 > * (eg. latency of keypress to text rendered).
76 > *
77 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
78 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
79 > * returned event causes this utility to leak a listener on the original event.
80 > *
81 > * @param event The event source for the new event.
82 > * @param flushOnListenerRemove Whether to fire all debounced events when a listener is removed. If this is not
83 > * specified, some events could go missing. Use this if it's important that all events are processed, even if the
84 > * listener gets disposed before the debounced event fires.
85 > * @param disposable A disposable store to add the new EventEmitter to.
86 > */
87 > export function defer(event: Event<unknown>, flushOnListenerRemove?: boolean, disposable?: DisposableStore): Event<void> {
88 return debounce<unknown, void>(event, () => void 0, 0, undefined, flushOnListenerRemove ?? true, undefined, disposable);
89 }
90 > event.ts
91 > /**
92 > * Given an event, returns another event which only fires once.
93 > *
94 > * @param event The event source for the new event.
95 > */
96 > export function once<T>(event: Event<T>): Event<T> {
97 return (listener, thisArgs = null, disposables?) => {
98 // we need this, in case the event fires during the listener call
118 };
119 }
120 > event.ts
121 > /**
122 > * Given an event, returns another event which only fires once, and only when the condition is met.
123 > *
124 > * @param event The event source for the new event.
125 > */
126 > export function onceIf<T>(event: Event<T>, condition: (e: T) => boolean): Event<T> {
127 return Event.once(Event.filter(event, condition));
128 }
129 > event.ts
130 > /**
131 > * Maps an event of one type into an event of another type using a mapping function, similar to how
132 > * `Array.prototype.map` works.
133 > *
134 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
135 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
136 > * returned event causes this utility to leak a listener on the original event.
137 > *
138 > * @param event The event source for the new event.
139 > * @param map The mapping function.
140 > * @param disposable A disposable store to add the new EventEmitter to.
141 > */
142 > export function map<I, O>(event: Event<I>, map: (i: I) => O, disposable?: DisposableStore): Event<O> {
143 return snapshot((listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables), disposable);
144 }
145 > event.ts
146 > /**
147 > * Wraps an event in another event that performs some function on the event object before firing.
148 > *
149 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
150 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
151 > * returned event causes this utility to leak a listener on the original event.
152 > *
153 > * @param event The event source for the new event.
154 > * @param each The function to perform on the event object.
155 > * @param disposable A disposable store to add the new EventEmitter to.
156 > */
157 > export function forEach<I>(event: Event<I>, each: (i: I) => void, disposable?: DisposableStore): Event<I> {
158 return snapshot((listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables), disposable);
159 }
160 > event.ts
161 > /**
162 > * Wraps an event in another event that fires only when some condition is met.
163 > *
164 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
165 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
166 > * returned event causes this utility to leak a listener on the original event.
167 > *
168 > * @param event The event source for the new event.
169 > * @param filter The filter function that defines the condition. The event will fire for the object if this function
170 > * returns true.
171 > * @param disposable A disposable store to add the new EventEmitter to.
172 > */
173 > export function filter<T, U>(event: Event<T | U>, filter: (e: T | U) => e is T, disposable?: DisposableStore): Event<T>;
174 > export function filter<T>(event: Event<T>, filter: (e: T) => boolean, disposable?: DisposableStore): Event<T>;
175 > export function filter<T, R>(event: Event<T | R>, filter: (e: T | R) => e is R, disposable?: DisposableStore): Event<R>;
176 > export function filter<T>(event: Event<T>, filter: (e: T) => boolean, disposable?: DisposableStore): Event<T> {
177 return snapshot((listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables), disposable);
178 }
179 > event.ts
180 > /**
181 > * Given an event, returns the same event but typed as `Event<void>`.
182 > */
183 > export function signal<T>(event: Event<T>): Event<void> {
184 return event as Event<any> as Event<void>;
185 }
186 > event.ts
187 > /**
188 > * Given a collection of events, returns a single event which emits whenever any of the provided events emit.
189 > */
190 > export function any<T>(...events: Event<T>[]): Event<T>;
191 > export function any(...events: Event<any>[]): Event<void>;
192 > export function any<T>(...events: Event<T>[]): Event<T> {
193 return (listener, thisArgs = null, disposables?) => {
194 const disposable = combinedDisposable(...events.map(event => event(e => listener.call(thisArgs, e))));
196 };
197 }
198 > event.ts
199 > /**
200 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
201 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
202 > * returned event causes this utility to leak a listener on the original event.
203 > */
204 > export function reduce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, initial?: O, disposable?: DisposableStore): Event<O> {
205 let output: O | undefined = initial;
206
210 }, disposable);
211 }
212 > event.ts
213 > function snapshot<T>(event: Event<T>, disposable: DisposableStore | undefined): Event<T> {
214 let listener: IDisposable | undefined;
215
233 return emitter.event;
234 }
235 > event.ts
236 > /**
237 > * Adds the IDisposable to the store if it's set, and returns it. Useful to
238 > * Event function implementation.
239 > */
240 > function addAndReturnDisposable<T extends IDisposable>(d: T, store: DisposableStore | IDisposable[] | undefined): T {
241 if (store instanceof Array) {
242 store.push(d);
246 return d;
247 }
248 > event.ts
249 > /**
250 > * Given an event, creates a new emitter that event that will debounce events based on {@link delay} and give an
251 > * array event object of all events that fired.
252 > *
253 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
254 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
255 > * returned event causes this utility to leak a listener on the original event.
256 > *
257 > * @param event The original event to debounce.
258 > * @param merge A function that reduces all events into a single event.
259 > * @param delay The number of milliseconds to debounce.
260 > * @param leading Whether to fire a leading event without debouncing.
261 > * @param flushOnListenerRemove Whether to fire all debounced events when a listener is removed. If this is not
262 > * specified, some events could go missing. Use this if it's important that all events are processed, even if the
263 > * listener gets disposed before the debounced event fires.
264 > * @param leakWarningThreshold See {@link EmitterOptions.leakWarningThreshold}.
265 > * @param disposable A disposable store to register the debounce emitter to.
266 > */
267 > export function debounce<T>(event: Event<T>, merge: (last: T | undefined, event: T) => T, delay?: number | typeof MicrotaskDelay, leading?: boolean, flushOnListenerRemove?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event<T>;
268 > export function debounce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay?: number | typeof MicrotaskDelay, leading?: boolean, flushOnListenerRemove?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event<O>;
269 > export function debounce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay: number | typeof MicrotaskDelay = 100, leading = false, flushOnListenerRemove = false, leakWarningThreshold?: number, disposable?: DisposableStore): Event<O> {
270 let subscription: IDisposable;
271 let output: O | undefined = undefined;
330 return emitter.event;
331 }
332 > event.ts
333 > /**
334 > * Debounces an event, firing after some delay (default=0) with an array of all event original objects.
335 > *
336 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
337 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
338 > * returned event causes this utility to leak a listener on the original event.
339 > *
340 > * @param event The event source for the new event.
341 > * @param delay The number of milliseconds to debounce.
342 > * @param flushOnListenerRemove Whether to fire all debounced events when a listener is removed. If this is not
343 > * specified, some events could go missing. Use this if it's important that all events are processed, even if the
344 > * listener gets disposed before the debounced event fires.
345 > * @param disposable A disposable store to add the new EventEmitter to.
346 > */
347 > export function accumulate<T>(event: Event<T>, delay: number | typeof MicrotaskDelay = 0, flushOnListenerRemove?: boolean, disposable?: DisposableStore): Event<T[]> {
348 return Event.debounce<T, T[]>(event, (last, e) => {
349 if (!last) {
354 }, delay, undefined, flushOnListenerRemove ?? true, undefined, disposable);
355 }
356 > event.ts
357 > /**
358 > * Throttles an event, ensuring the event is fired at most once during the specified delay period.
359 > * Unlike debounce, throttle will fire immediately on the leading edge and/or after the delay on the trailing edge.
360 > *
361 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
362 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
363 > * returned event causes this utility to leak a listener on the original event.
364 > *
365 > * @param event The event source for the new event.
366 > * @param merge An accumulator function that merges events if multiple occur during the throttle period.
367 > * @param delay The number of milliseconds to throttle.
368 > * @param leading Whether to fire on the leading edge (immediately on first event).
369 > * @param trailing Whether to fire on the trailing edge (after delay with the last value).
370 > * @param leakWarningThreshold See {@link EmitterOptions.leakWarningThreshold}.
371 > * @param disposable A disposable store to register the throttle emitter to.
372 > */
373 > export function throttle<T>(event: Event<T>, merge: (last: T | undefined, event: T) => T, delay?: number | typeof MicrotaskDelay, leading?: boolean, trailing?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event<T>;
374 > export function throttle<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay?: number | typeof MicrotaskDelay, leading?: boolean, trailing?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event<O>;
375 > export function throttle<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay: number | typeof MicrotaskDelay = 100, leading = true, trailing = true, leakWarningThreshold?: number, disposable?: DisposableStore): Event<O> {
376 let subscription: IDisposable;
377 let output: O | undefined = undefined;
437 return emitter.event;
438 }
439 > event.ts
440 > /**
441 > * Filters an event such that some condition is _not_ met more than once in a row, effectively ensuring duplicate
442 > * event objects from different sources do not fire the same event object.
443 > *
444 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
445 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
446 > * returned event causes this utility to leak a listener on the original event.
447 > *
448 > * @param event The event source for the new event.
449 > * @param equals The equality condition.
450 > * @param disposable A disposable store to add the new EventEmitter to.
451 > *
452 > * @example
453 > * ```
454 > * // Fire only one time when a single window is opened or focused
455 > * Event.latch(Event.any(onDidOpenWindow, onDidFocusWindow))
456 > * ```
457 > */
458 > export function latch<T>(event: Event<T>, equals: (a: T, b: T) => boolean = (a, b) => a === b, disposable?: DisposableStore): Event<T> {
459 let firstCall = true;
460 let cache: T;
467 }, disposable);
468 }
469 > event.ts
470 > /**
471 > * Splits an event whose parameter is a union type into 2 separate events for each type in the union.
472 > *
473 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
474 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
475 > * returned event causes this utility to leak a listener on the original event.
476 > *
477 > * @example
478 > * ```
479 > * const event = new EventEmitter<number | undefined>().event;
480 > * const [numberEvent, undefinedEvent] = Event.split(event, isUndefined);
481 > * ```
482 > *
483 > * @param event The event source for the new event.
484 > * @param isT A function that determines what event is of the first type.
485 > * @param disposable A disposable store to add the new EventEmitter to.
486 > */
487 > export function split<T, U>(event: Event<T | U>, isT: (e: T | U) => e is T, disposable?: DisposableStore): [Event<T>, Event<U>] {
488 return [
489 Event.filter(event, isT, disposable),
491 ];
492 }
493 > event.ts
494 > /**
495 > * Buffers an event until it has a listener attached.
496 > *
497 > * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
498 > * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
499 > * returned event causes this utility to leak a listener on the original event.
500 > *
501 > * @param event The event source for the new event.
502 > * @param debugName A name for this buffer, used in leak detection warnings.
503 > * @param flushAfterTimeout Determines whether to flush the buffer after a timeout immediately or after a
504 > * `setTimeout` when the first event listener is added.
505 > * @param _buffer Internal: A source event array used for tests.
506 > *
507 > * @example
508 > * ```
509 > * // Start accumulating events, when the first listener is attached, flush
510 > * // the event after a timeout such that multiple listeners attached before
511 > * // the timeout would receive the event
512 > * this.onInstallExtension = Event.buffer(service.onInstallExtension, 'onInstallExtension', true);
513 > * ```
514 > */
515 > export function buffer<T>(event: Event<T>, debugName: string, flushAfterTimeout = false, _buffer: T[] = [], disposable?: DisposableStore): Event<T> {
516 let buffer: T[] | null = _buffer.slice();
517
600 return emitter.event;
601 }
602 > /** event.ts
603 > * Wraps the event in an {@link IChainableEvent}, allowing a more functional programming style.
604 > *
605 > * @example
606 > * ```
607 > * // Normal
608 > * const onEnterPressNormal = Event.filter(
609 > * Event.map(onKeyPress.event, e => new StandardKeyboardEvent(e)),
610 > * e.keyCode === KeyCode.Enter
611 > * ).event;
612 > *
613 > * // Using chain
614 > * const onEnterPressChain = Event.chain(onKeyPress.event, $ => $
615 > * .map(e => new StandardKeyboardEvent(e))
616 > * .filter(e => e.keyCode === KeyCode.Enter)
617 > * );
618 > * ```
619 > */
620 > export function chain<T, R>(event: Event<T>, sythensize: ($: IChainableSythensis<T>) => IChainableSythensis<R>): Event<R> {
621 const fn: Event<R> = (listener, thisArgs, disposables) => {
622 const cs = sythensize(new ChainableSynthesis()) as ChainableSynthesis;
631 return fn;
632 }
633 > event.ts
634 > const HaltChainable = Symbol('HaltChainable');
635 >
636 > class ChainableSynthesis implements IChainableSythensis<any> {
637 private readonly steps: ((input: any) => unknown)[] = [];
638 > event.ts
639 > map<O>(fn: (i: any) => O): this {
640 this.steps.push(fn);
641 return this;
642 }
643 > event.ts
644 > forEach(fn: (i: any) => void): this {
645 this.steps.push(v => {
646 fn(v);
649 return this;
650 }
651 > event.ts
652 > filter(fn: (e: any) => boolean): this {
653 this.steps.push(v => fn(v) ? v : HaltChainable);
654 return this;
655 }
656 > event.ts
657 > reduce<R>(merge: (last: R | undefined, event: any) => R, initial?: R | undefined): this {
658 let last = initial;
659 this.steps.push(v => {
663 return this;
664 }
665 > event.ts
666 > latch(equals: (a: any, b: any) => boolean = (a, b) => a === b): ChainableSynthesis {
667 let firstCall = true;
668 let cache: any;
676 return this;
677 }
678 > event.ts
679 > public evaluate(value: any) {
680 for (const step of this.steps) {
681 value = step(value);
687 return value;
688 }
689 > } event.ts
690 >
691 > export interface IChainableSythensis<T> {
692 > map<O>(fn: (i: T) => O): IChainableSythensis<O>;
693 > forEach(fn: (i: T) => void): IChainableSythensis<T>;
694 > filter<R extends T>(fn: (e: T) => e is R): IChainableSythensis<R>;
695 > filter(fn: (e: T) => boolean): IChainableSythensis<T>;
696 > reduce<R>(merge: (last: R, event: T) => R, initial: R): IChainableSythensis<R>;
697 > reduce<R>(merge: (last: R | undefined, event: T) => R): IChainableSythensis<R>;
698 > latch(equals?: (a: T, b: T) => boolean): IChainableSythensis<T>;
699 > }
700 >
701 > export interface NodeEventEmitter {
702 > on(event: string | symbol, listener: Function): unknown;
703 > removeListener(event: string | symbol, listener: Function): unknown;
704 > }
705 >
706 > /**
707 > * Creates an {@link Event} from a node event emitter.
708 > */
709 > export function fromNodeEventEmitter<T>(emitter: NodeEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event<T> {
710 const fn = (...args: unknown[]) => result.fire(map(...args));
711 const onFirstListenerAdd = () => emitter.on(eventName, fn);
715 return result.event;
716 }
717 > event.ts
718 > export interface DOMEventEmitter {
719 > addEventListener(event: string | symbol, listener: Function): void;
720 > removeEventListener(event: string | symbol, listener: Function): void;
721 > }
722 >
723 > /**
724 > * Creates an {@link Event} from a DOM event emitter.
725 > */
726 > export function fromDOMEventEmitter<T>(emitter: DOMEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event<T> {
727 const fn = (...args: unknown[]) => result.fire(map(...args));
728 const onFirstListenerAdd = () => emitter.addEventListener(eventName, fn);
732 return result.event;
733 }
734 > event.ts
735 > /**
736 > * Creates a promise out of an event, using the {@link Event.once} helper.
737 > */
738 > export function toPromise<T>(event: Event<T>, disposables?: IDisposable[] | DisposableStore): CancelablePromise<T> {
739 let cancelRef: () => void;
740 let listener: IDisposable;
756 return promise;
757 }
758 > event.ts
759 > /**
760 > * A convenience function for forwarding an event to another emitter which
761 > * improves readability.
762 > *
763 > * This is similar to {@link Relay} but allows instantiating and forwarding
764 > * on a single line and also allows for multiple source events.
765 > * @param from The event to forward.
766 > * @param to The emitter to forward the event to.
767 > * @example
768 > * Event.forward(event, emitter);
769 > * // equivalent to
770 > * event(e => emitter.fire(e));
771 > * // equivalent to
772 > * event(emitter.fire, emitter);
773 > */
774 > export function forward<T>(from: Event<T>, to: Emitter<T>): IDisposable {
775 return from(e => to.fire(e));
776 }
777 > event.ts
778 > /**
779 > * Adds a listener to an event and calls the listener immediately with undefined as the event object.
780 > *
781 > * @example
782 > * ```
783 > * // Initialize the UI and update it when dataChangeEvent fires
784 > * runAndSubscribe(dataChangeEvent, () => this._updateUI());
785 > * ```
786 > */
787 > export function runAndSubscribe<T>(event: Event<T>, handler: (e: T) => unknown, initial: T): IDisposable;
788 > export function runAndSubscribe<T>(event: Event<T>, handler: (e: T | undefined) => unknown): IDisposable;
789 > export function runAndSubscribe<T>(event: Event<T>, handler: (e: T | undefined) => unknown, initial?: T): IDisposable {
790 handler(initial);
791 return event(e => handler(e));
792 }
793 > event.ts
794 > class EmitterObserver<T> implements IObserver {
795 >
796 > readonly emitter: Emitter<T>;
797 >
798 > private _counter = 0;
799 > private _hasChanged = false;
800 >
801 > constructor(readonly _observable: IObservable<T>, store: DisposableStore | undefined) {
802 const options: EmitterOptions = {
803 onWillAddFirstListener: () => {
819 }
820 }
821 > event.ts
822 > beginUpdate<T>(_observable: IObservable<T>): void {
823 // assert(_observable === this.obs);
824 this._counter++;
825 }
826 > event.ts
827 > handlePossibleChange<T>(_observable: IObservable<T>): void {
828 // assert(_observable === this.obs);
829 }
830 > event.ts
831 > handleChange<T, TChange>(_observable: IObservableWithChange<T, TChange>, _change: TChange): void {
832 // assert(_observable === this.obs);
833 this._hasChanged = true;
834 }
835 > event.ts
836 > endUpdate<T>(_observable: IObservable<T>): void {
837 // assert(_observable === this.obs);
838 this._counter--;
845 }
846 }
847 > } event.ts
848 >
849 > /**
850 > * Creates an event emitter that is fired when the observable changes.
851 > * Each listeners subscribes to the emitter.
852 > */
853 > export function fromObservable<T>(obs: IObservable<T>, store?: DisposableStore): Event<T> {
854 const observer = new EmitterObserver(obs, store);
855 return observer.emitter.event;
856 }
857 > event.ts
858 > /**
859 > * Each listener is attached to the observable directly.
860 > */
861 > export function fromObservableLight(observable: IObservable<unknown>): Event<void> {
862 return (listener, thisArgs, disposables) => {
863 let count = 0;
897 };
898 }
899 > } event.ts
900 >
901 > export interface EmitterOptions {
902 > /**
903 > * Optional function that's called *before* the very first listener is added
904 > */
905 > onWillAddFirstListener?: Function;
906 > /**
907 > * Optional function that's called *after* the very first listener is added
908 > */
909 > onDidAddFirstListener?: Function;
910 > /**
911 > * Optional function that's called after a listener is added
912 > */
913 > onDidAddListener?: Function;
914 > /**
915 > * Optional function that's called *after* remove the very last listener
916 > */
917 > onDidRemoveLastListener?: Function;
918 > /**
919 > * Optional function that's called *before* a listener is removed
920 > */
921 > onWillRemoveListener?: Function;
922 > /**
923 > * Optional function that's called when a listener throws an error. Defaults to
924 > * {@link onUnexpectedError}
925 > */
926 > onListenerError?: (e: any) => void;
927 > /**
928 > * Number of listeners that are allowed before assuming a leak. Default to
929 > * a globally configured value
930 > *
931 > * @see setGlobalLeakWarningThreshold
932 > */
933 > leakWarningThreshold?: number;
934 > /**
935 > * Human-readable name for the emitter, included in leak warning error
936 > * messages to help identify which emitter is leaking in telemetry.
937 > */
938 > leakWarningName?: string;
939 > /**
940 > * Pass in a delivery queue, which is useful for ensuring
941 > * in order event delivery across multiple emitters.
942 > */
943 > deliveryQueue?: EventDeliveryQueue;
944 >
945 > /** ONLY enable this during development */
946 > _profName?: string;
947 > }
948 >
949 >
950 > export class EventProfiling {
951 >
952 > static readonly all = new Set<EventProfiling>();
953 >
954 > private static _idPool = 0;
955 >
956 > readonly name: string;
957 > public listenerCount: number = 0;
958 > public invocationCount = 0;
959 > public elapsedOverall = 0;
960 > public durations: number[] = [];
961 >
962 > private _stopWatch?: StopWatch;
963 >
964 > constructor(name: string) {
965 this.name = `${name}_${EventProfiling._idPool++}`;
966 EventProfiling.all.add(this);
967 }
968 > event.ts
969 > start(listenerCount: number): void {
970 this._stopWatch = new StopWatch();
971 this.listenerCount = listenerCount;
972 }
973 > event.ts
974 > stop(): void {
975 if (this._stopWatch) {
976 const elapsed = this._stopWatch.elapsed();
981 }
982 }
983 > } event.ts
984 >
985 > let _globalLeakWarningThreshold = -1;
986 > export function setGlobalLeakWarningThreshold(n: number): IDisposable {
987 const oldValue = _globalLeakWarningThreshold;
988 _globalLeakWarningThreshold = n;
993 };
994 }
995 > event.ts
996 > class LeakageMonitor {
997 >
998 > private static _idPool = 1;
999 >
1000 > private _stacks: Map<string, number> | undefined;
1001 > private _warnCountdown: number = 0;
1002 >
1003 > constructor(
1004 private readonly _errorHandler: (err: Error) => void,
1005 readonly threshold: number,
1006 readonly name: string = (LeakageMonitor._idPool++).toString(16).padStart(3, '0')
1007 ) { }
1008 > event.ts
1009 > dispose(): void {
1010 this._stacks?.clear();
1011 }
1012 > event.ts
1013 > check(stack: Stacktrace, listenerCount: number): undefined | (() => void) {
1014
1015 const threshold = this.threshold;
1046 };
1047 }
1048 > event.ts
1049 > getMostFrequentStack(): [string, number] | undefined {
1050 if (!this._stacks) {
1051 return undefined;
1061 return topStack;
1062 }
1063 > } event.ts
1064 >
1065 > class Stacktrace {
1066 >
1067 > static create() {
1068 > const err = new Error();
1069 > return new Stacktrace(err.stack ?? '');
1070 > }
1071 >
1072 > private constructor(readonly value: string) { }
1073 >
1074 > print() {
1075 console.warn(this.value.split('\n').slice(2).join('\n'));
1076 }
1077 > } event.ts
1078 >
1079 > // error that is logged when going over the configured listener threshold
1080 > export class ListenerLeakError extends Error {
1081 > readonly kind: string;
1082 > readonly listenerCount: number;
1083 > /**
1084 > * The detailed message including listener count and most frequent stack.
1085 > * Available locally for debugging but intentionally not used as the error
1086 > * `message`. When `emitterName` is provided, errors group by emitter name
1087 > * and kind in telemetry; otherwise they group by kind alone.
1088 > */
1089 > readonly details: string;
1090 > constructor(kind: 'dominated' | 'popular', details: string, stack: string, listenerCount: number, emitterName?: string) {
1091 super(emitterName
1092 ? `[${emitterName}] potential listener LEAK detected, ${kind}`
1098 this.stack = stack;
1099 }
1100 > event.ts
1101 > static is(err: unknown): err is ListenerLeakError {
1102 return err instanceof ListenerLeakError
1103 || (err instanceof Error && typeof (err as Error & { kind: unknown; listenerCount: unknown }).kind === 'string' && typeof (err as Error & { kind: unknown; listenerCount: unknown }).listenerCount === 'number');
1104 }
1105 > } event.ts
1106 >
1107 > // SEVERE error that is logged when having gone way over the configured listener
1108 > // threshold so that the emitter refuses to accept more listeners
1109 > export class ListenerRefusalError extends ListenerLeakError {
1110 > constructor(kind: 'dominated' | 'popular', details: string, stack: string, listenerCount: number, emitterName?: string) {
1111 super(kind, details, stack, listenerCount, emitterName);
1112 this.name = 'ListenerRefusalError';
1113 }
1114 > } event.ts
1115 >
1116 > let id = 0;
1117 > class UniqueContainer<T> {
1118 > stack?: Stacktrace;
1119 > public id = id++;
1120 > constructor(public readonly value: T) { }
1121 > }
1122 > const compactionThreshold = 2;
1123 >
1124 > type ListenerContainer<T> = UniqueContainer<(data: T) => void>;
1125 > type ListenerOrListeners<T> = (ListenerContainer<T> | undefined)[] | ListenerContainer<T>;
1126 >
1127 > const forEachListener = <T>(listeners: ListenerOrListeners<T>, fn: (c: ListenerContainer<T>) => void) => {
1128 if (listeners instanceof UniqueContainer) {
1129 fn(listeners);
1137 }
1138 };
1139 > event.ts
1140 > /**
1141 > * The Emitter can be used to expose an Event to the public
1142 > * to fire it from the insides.
1143 > * Sample:
1144 > class Document {
1145 >
1146 > private readonly _onDidChange = new Emitter<(value:string)=>any>();
1147 >
1148 > public onDidChange = this._onDidChange.event;
1149 >
1150 > // getter-style
1151 > // get onDidChange(): Event<(value:string)=>any> {
1152 > // return this._onDidChange.event;
1153 > // }
1154 >
1155 > private _doIt() {
1156 > //...
1157 > this._onDidChange.fire(value);
1158 > }
1159 > }
1160 > */
1161 > export class Emitter<T> {
1162 >
1163 > private readonly _options?: EmitterOptions;
1164 > private readonly _leakageMon?: LeakageMonitor;
1165 > private readonly _perfMon?: EventProfiling;
1166 > private _disposed?: true;
1167 > private _event?: Event<T>;
1168 >
1169 > /**
1170 > * A listener, or list of listeners. A single listener is the most common
1171 > * for event emitters (#185789), so we optimize that special case to avoid
1172 > * wrapping it in an array (just like Node.js itself.)
1173 > *
1174 > * A list of listeners never 'downgrades' back to a plain function if
1175 > * listeners are removed, for two reasons:
1176 > *
1177 > * 1. That's complicated (especially with the deliveryQueue)
1178 > * 2. A listener with >1 listener is likely to have >1 listener again at
1179 > * some point, and swapping between arrays and functions may[citation needed]
1180 > * introduce unnecessary work and garbage.
1181 > *
1182 > * The array listeners can be 'sparse', to avoid reallocating the array
1183 > * whenever any listener is added or removed. If more than `1 / compactionThreshold`
1184 > * of the array is empty, only then is it resized.
1185 > */
1186 > protected _listeners?: ListenerOrListeners<T>;
1187 >
1188 > /**
1189 > * Always to be defined if _listeners is an array. It's no longer a true
1190 > * queue, but holds the dispatching 'state'. If `fire()` is called on an
1191 > * emitter, any work left in the _deliveryQueue is finished first.
1192 > */
1193 > private _deliveryQueue?: EventDeliveryQueuePrivate;
1194 > protected _size = 0;
1195 >
1196 > constructor(options?: EmitterOptions) {
1197 this._options = options;
1198 this._leakageMon = (_globalLeakWarningThreshold > 0 || this._options?.leakWarningThreshold)
1202 this._deliveryQueue = this._options?.deliveryQueue as EventDeliveryQueuePrivate | undefined;
1203 }
1204 > event.ts
1205 > dispose() {
1206 if (!this._disposed) {
1207 this._disposed = true;
1235 }
1236 }
1237 > event.ts
1238 > /**
1239 > * For the public to allow to subscribe
1240 > * to events from this Emitter
1241 > */
1242 > get event(): Event<T> {
1243 this._event ??= (callback: (e: T) => unknown, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {
1244 if (this._leakageMon && this._size > this._leakageMon.threshold ** 2) {
1304 return this._event;
1305 }
1306 > event.ts
1307 > private _removeListener(listener: ListenerContainer<T>) {
1308 this._options?.onWillRemoveListener?.(this);
1309
1349 }
1350 }
1351 > event.ts
1352 > private _deliver(listener: undefined | UniqueContainer<(value: T) => void>, value: T) {
1353 if (!listener) {
1354 return;
1367 }
1368 }
1369 > event.ts
1370 > /** Delivers items in the queue. Assumes the queue is ready to go. */
1371 > private _deliverQueue(dq: EventDeliveryQueuePrivate) {
1372 const listeners = dq.current!._listeners! as (ListenerContainer<T> | undefined)[];
1373 while (dq.i < dq.end) {
1377 dq.reset();
1378 }
1379 > event.ts
1380 > /**
1381 > * To be kept private to fire an event to
1382 > * subscribers
1383 > */
1384 > fire(event: T): void {
1385 if (this._deliveryQueue?.current) {
1386 this._deliverQueue(this._deliveryQueue);
1402 this._perfMon?.stop();
1403 }
1404 > event.ts
1405 > hasListeners(): boolean {
1406 return this._size > 0;
1407 }
1408 > } event.ts
1409 >
1410 > export interface EventDeliveryQueue {
1411 > _isEventDeliveryQueue: true;
1412 > }
1413 >
1414 > export const createEventDeliveryQueue = (): EventDeliveryQueue => new EventDeliveryQueuePrivate();
1415 >
1416 class EventDeliveryQueuePrivate implements EventDeliveryQueue {
1417 declare _isEventDeliveryQueue: true;
1426 */
1427 public end = 0;
1428 > event.ts
1429 > /**
1430 > * Emitter currently being dispatched on. Emitter._listeners is always an array.
1431 > */
1432 > public current?: Emitter<any>;
1433 > /**
1434 > * Currently emitting value. Defined whenever `current` is.
1435 > */
1436 > public value?: unknown;
1437 >
1438 > public enqueue<T>(emitter: Emitter<T>, value: T, end: number) {
1439 this.i = 0;
1440 this.end = end;
1442 this.value = value;
1443 }
1444 > event.ts
1445 > public reset() {
1446 this.i = this.end; // force any current emission loop to stop, mainly for during dispose
1447 this.current = undefined;
1448 this.value = undefined;
1449 }
1450 > } event.ts
1451 >
1452 > export interface IWaitUntil {
1453 > token: CancellationToken;
1454 > waitUntil(thenable: Promise<unknown>): void;
1455 > }
1456 >
1457 > export type IWaitUntilData<T> = Omit<Omit<T, 'waitUntil'>, 'token'>;
1458 >
1459 > export class AsyncEmitter<T extends IWaitUntil> extends Emitter<T> {
1460 >
1461 > private _asyncDeliveryQueue?: LinkedList<[(ev: T) => void, IWaitUntilData<T>]>;
1462 >
1463 > async fireAsync(data: IWaitUntilData<T>, token: CancellationToken, promiseJoin?: (p: Promise<unknown>, listener: Function) => Promise<unknown>): Promise<void> {
1464 if (!this._listeners) {
1465 return;
1512 }
1513 }
1514 > } event.ts
1515 >
1516 >
1517 > export class PauseableEmitter<T> extends Emitter<T> {
1518 >
1519 > private _isPaused = 0;
1520 > protected _eventQueue = new LinkedList<T>();
1521 > private _mergeFn?: (input: T[]) => T;
1522 >
1523 > public get isPaused(): boolean {
1524 > return this._isPaused !== 0;
1525 > }
1526 >
1527 > constructor(options?: EmitterOptions & { merge?: (input: T[]) => T }) {
1528 super(options);
1529 this._mergeFn = options?.merge;
1530 }
1531 > event.ts
1532 > pause(): void {
1533 this._isPaused++;
1534 }
1535 > event.ts
1536 > resume(): void {
1537 if (this._isPaused !== 0 && --this._isPaused === 0) {
1538 if (this._mergeFn) {
1554 }
1555 }
1556 > event.ts
1557 > override fire(event: T): void {
1558 if (this._size) {
1559 if (this._isPaused !== 0) {
1564 }
1565 }
1566 > } event.ts
1567 >
1568 > export class DebounceEmitter<T> extends PauseableEmitter<T> {
1569 >
1570 > private readonly _delay: number;
1571 > private _handle: Timeout | undefined;
1572 >
1573 > constructor(options: EmitterOptions & { merge: (input: T[]) => T; delay?: number }) {
1574 super(options);
1575 this._delay = options.delay ?? 100;
1576 }
1577 > event.ts
1578 > override fire(event: T): void {
1579 if (!this._handle) {
1580 this.pause();
1586 super.fire(event);
1587 }
1588 > } event.ts
1589 >
1590 > /**
1591 > * An emitter which queue all events and then process them at the
1592 > * end of the event loop.
1593 > */
1594 > export class MicrotaskEmitter<T> extends Emitter<T> {
1595 > private _queuedEvents: T[] = [];
1596 > private _mergeFn?: (input: T[]) => T;
1597 >
1598 > constructor(options?: EmitterOptions & { merge?: (input: T[]) => T }) {
1599 super(options);
1600 this._mergeFn = options?.merge;
1601 }
1602 > override fire(event: T): void { event.ts
1603
1604 if (!this.hasListeners()) {
1618 }
1619 }
1620 > } event.ts
1621 >
1622 > /**
1623 > * An event emitter that multiplexes many events into a single event.
1624 > *
1625 > * @example Listen to the `onData` event of all `Thing`s, dynamically adding and removing `Thing`s
1626 > * to the multiplexer as needed.
1627 > *
1628 > * ```typescript
1629 > * const anythingDataMultiplexer = new EventMultiplexer<{ data: string }>();
1630 > *
1631 > * const thingListeners = DisposableMap<Thing, IDisposable>();
1632 > *
1633 > * thingService.onDidAddThing(thing => {
1634 > * thingListeners.set(thing, anythingDataMultiplexer.add(thing.onData);
1635 > * });
1636 > * thingService.onDidRemoveThing(thing => {
1637 > * thingListeners.deleteAndDispose(thing);
1638 > * });
1639 > *
1640 > * anythingDataMultiplexer.event(e => {
1641 > * console.log('Something fired data ' + e.data)
1642 > * });
1643 > * ```
1644 > */
1645 > export class EventMultiplexer<T> implements IDisposable {
1646 >
1647 > private readonly emitter: Emitter<T>;
1648 > private hasListeners = false;
1649 > private events: { event: Event<T>; listener: IDisposable | null }[] = [];
1650 >
1651 > constructor() {
1652 this.emitter = new Emitter<T>({
1653 onWillAddFirstListener: () => this.onFirstListenerAdd(),
1655 });
1656 }
1657 > event.ts
1658 > get event(): Event<T> {
1659 return this.emitter.event;
1660 }
1661 > event.ts
1662 > add(event: Event<T>): IDisposable {
1663 const e = { event: event, listener: null };
1664 this.events.push(e);
1679 return toDisposable(createSingleCallFunction(dispose));
1680 }
1681 > event.ts
1682 > private onFirstListenerAdd(): void {
1683 this.hasListeners = true;
1684 this.events.forEach(e => this.hook(e));
1685 }
1686 > event.ts
1687 > private onLastListenerRemove(): void {
1688 this.hasListeners = false;
1689 this.events.forEach(e => this.unhook(e));
1690 }
1691 > event.ts
1692 > private hook(e: { event: Event<T>; listener: IDisposable | null }): void {
1693 e.listener = e.event(r => this.emitter.fire(r));
1694 }
1695 > event.ts
1696 > private unhook(e: { event: Event<T>; listener: IDisposable | null }): void {
1697 e.listener?.dispose();
1698 e.listener = null;
1699 }
1700 > event.ts
1701 > dispose(): void {
1702 this.emitter.dispose();
1703
1707 this.events = [];
1708 }
1709 > } event.ts
1710 >
1711 > export interface IDynamicListEventMultiplexer<TEventType> extends IDisposable {
1712 > readonly event: Event<TEventType>;
1713 > }
1714 > export class DynamicListEventMultiplexer<TItem, TEventType> implements IDynamicListEventMultiplexer<TEventType> {
1715 > private readonly _store = new DisposableStore();
1716 >
1717 > readonly event: Event<TEventType>;
1718 >
1719 > constructor(
1720 items: TItem[],
1721 onAddItem: Event<TItem>,
1747 this.event = multiplexer.event;
1748 }
1749 > event.ts
1750 > dispose() {
1751 this._store.dispose();
1752 }
1753 > } event.ts
1754 >
1755 > /**
1756 > * The EventBufferer is useful in situations in which you want
1757 > * to delay firing your events during some code.
1758 > * You can wrap that code and be sure that the event will not
1759 > * be fired during that wrap.
1760 > *
1761 > * ```
1762 > * const emitter: Emitter;
1763 > * const delayer = new EventDelayer();
1764 > * const delayedEvent = delayer.wrapEvent(emitter.event);
1765 > *
1766 > * delayedEvent(console.log);
1767 > *
1768 > * delayer.bufferEvents(() => {
1769 > * emitter.fire(); // event will not be fired yet
1770 > * });
1771 > *
1772 > * // event will only be fired at this point
1773 > * ```
1774 > */
1775 > export class EventBufferer {
1776
1777 private data: { buffers: Function[] }[] = [];
1778 > event.ts
1779 > wrapEvent<T>(event: Event<T>): Event<T>;
1780 > wrapEvent<T>(event: Event<T>, reduce: (last: T | undefined, event: T) => T): Event<T>;
1781 > wrapEvent<T, O>(event: Event<T>, reduce: (last: O | undefined, event: T) => O, initial: O): Event<O>;
1782 > wrapEvent<T, O>(event: Event<T>, reduce?: (last: T | O | undefined, event: T) => T | O, initial?: O): Event<O | T> {
1783 return (listener, thisArgs?, disposables?) => {
1784 return event(i => {
1832 };
1833 }
1834 > event.ts
1835 > bufferEvents<R = void>(fn: () => R): R {
1836 const data = { buffers: new Array<Function>() };
1837 this.data.push(data);
1841 return r;
1842 }
1843 > } event.ts
1844 >
1845 > /**
1846 > * A Relay is an event forwarder which functions as a replugabble event pipe.
1847 > * Once created, you can connect an input event to it and it will simply forward
1848 > * events from that input event through its own `event` property. The `input`
1849 > * can be changed at any point in time.
1850 > */
1851 > export class Relay<T> implements IDisposable {
1852
1853 private listening = false;
1867
1868 readonly event: Event<T> = this.emitter.event;
1869 > event.ts
1870 > set input(event: Event<T>) {
1871 this.inputEvent = event;
1872
1876 }
1877 }
1878 > event.ts
1879 > dispose() {
1880 this.inputEventListener.dispose();
1881 this.emitter.dispose();
1882 }
1883 > } event.ts
1884 >
1885 > export interface IValueWithChangeEvent<T> {
1886 > readonly onDidChange: Event<void>;
1887 > get value(): T;
1888 > }
1889 >
1890 > export class ValueWithChangeEvent<T> implements IValueWithChangeEvent<T> {
1891 > public static const<T>(value: T): IValueWithChangeEvent<T> {
1892 > return new ConstValueWithChangeEvent(value);
1893 > }
1894 >
1895 > private readonly _onDidChange = new Emitter<void>();
1896 > readonly onDidChange: Event<void> = this._onDidChange.event;
1897 >
1898 > constructor(private _value: T) { }
1899 >
1900 > get value(): T {
1901 return this._value;
1902 }
1903 > event.ts
1904 > set value(value: T) {
1905 if (value !== this._value) {
1906 this._value = value;
1908 }
1909 }
1910 > } event.ts
1911 >
1912 > class ConstValueWithChangeEvent<T> implements IValueWithChangeEvent<T> {
1913 > public readonly onDidChange: Event<void> = Event.None;
1914 >
1915 > constructor(readonly value: T) { }
1916 > }
1917 >
1918 > /**
1919 > * @param handleItem Is called for each item in the set (but only the first time the item is seen in the set).
1920 > * The returned disposable is disposed if the item is no longer in the set.
1921 > */
1922 > export function trackSetChanges<T>(getData: () => ReadonlySet<T>, onDidChangeData: Event<unknown>, handleItem: (d: T) => IDisposable): IDisposable {
1923 const map = new DisposableMap<T, IDisposable>();
1924 let oldData = new Set(getData());
1942 return store;
1943 }
1944 > event.ts
1945 >
1946 function addToDisposables(result: IDisposable, disposables: DisposableStore | IDisposable[] | undefined) {
1947 if (disposables instanceof DisposableStore) {
1951 }
1952 }
1953 > event.ts
1954 function disposeAndRemove(result: IDisposable, disposables: DisposableStore | IDisposable[] | undefined) {
1955 if (disposables instanceof DisposableStore) {
src/vs/base/common/codiconsLibrary.ts 758 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- codiconsLibrary.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 > import { register } from './codiconsUtil.js';
6 >
7 >
8 > // This file is automatically generated by (microsoft/vscode-codicons)/scripts/export-to-ts.js
9 > // Please don't edit it, as your changes will be overwritten.
10 > // Instead, add mappings to codiconsDerived in codicons.ts.
11 > export const codiconsLibrary = {
12 > add: register('add', 0xea60),
13 > plus: register('plus', 0xea60),
14 > gistNew: register('gist-new', 0xea60),
15 > repoCreate: register('repo-create', 0xea60),
16 > lightbulb: register('lightbulb', 0xea61),
17 > lightBulb: register('light-bulb', 0xea61),
18 > repo: register('repo', 0xea62),
19 > repoDelete: register('repo-delete', 0xea62),
20 > gistFork: register('gist-fork', 0xea63),
21 > repoForked: register('repo-forked', 0xea63),
22 > gitPullRequest: register('git-pull-request', 0xea64),
23 > gitPullRequestAbandoned: register('git-pull-request-abandoned', 0xea64),
24 > recordKeys: register('record-keys', 0xea65),
25 > keyboard: register('keyboard', 0xea65),
26 > tag: register('tag', 0xea66),
27 > gitPullRequestLabel: register('git-pull-request-label', 0xea66),
28 > tagAdd: register('tag-add', 0xea66),
29 > tagRemove: register('tag-remove', 0xea66),
30 > person: register('person', 0xea67),
31 > personFollow: register('person-follow', 0xea67),
32 > personOutline: register('person-outline', 0xea67),
33 > personFilled: register('person-filled', 0xea67),
34 > sourceControl: register('source-control', 0xea68),
35 > mirror: register('mirror', 0xea69),
36 > mirrorPublic: register('mirror-public', 0xea69),
37 > star: register('star', 0xea6a),
38 > starAdd: register('star-add', 0xea6a),
39 > starDelete: register('star-delete', 0xea6a),
40 > starEmpty: register('star-empty', 0xea6a),
41 > comment: register('comment', 0xea6b),
42 > commentAdd: register('comment-add', 0xea6b),
43 > alert: register('alert', 0xea6c),
44 > warning: register('warning', 0xea6c),
45 > search: register('search', 0xea6d),
46 > searchSave: register('search-save', 0xea6d),
47 > logOut: register('log-out', 0xea6e),
48 > signOut: register('sign-out', 0xea6e),
49 > logIn: register('log-in', 0xea6f),
50 > signIn: register('sign-in', 0xea6f),
51 > eye: register('eye', 0xea70),
52 > eyeUnwatch: register('eye-unwatch', 0xea70),
53 > eyeWatch: register('eye-watch', 0xea70),
54 > circleFilled: register('circle-filled', 0xea71),
55 > primitiveDot: register('primitive-dot', 0xea71),
56 > closeDirty: register('close-dirty', 0xea71),
57 > debugBreakpoint: register('debug-breakpoint', 0xea71),
58 > debugBreakpointDisabled: register('debug-breakpoint-disabled', 0xea71),
59 > debugHint: register('debug-hint', 0xea71),
60 > terminalDecorationSuccess: register('terminal-decoration-success', 0xea71),
61 > primitiveSquare: register('primitive-square', 0xea72),
62 > edit: register('edit', 0xea73),
63 > pencil: register('pencil', 0xea73),
64 > info: register('info', 0xea74),
65 > issueOpened: register('issue-opened', 0xea74),
66 > gistPrivate: register('gist-private', 0xea75),
67 > gitForkPrivate: register('git-fork-private', 0xea75),
68 > lock: register('lock', 0xea75),
69 > mirrorPrivate: register('mirror-private', 0xea75),
70 > close: register('close', 0xea76),
71 > removeClose: register('remove-close', 0xea76),
72 > x: register('x', 0xea76),
73 > repoSync: register('repo-sync', 0xea77),
74 > sync: register('sync', 0xea77),
75 > clone: register('clone', 0xea78),
76 > desktopDownload: register('desktop-download', 0xea78),
77 > beaker: register('beaker', 0xea79),
78 > microscope: register('microscope', 0xea79),
79 > vm: register('vm', 0xea7a),
80 > deviceDesktop: register('device-desktop', 0xea7a),
81 > file: register('file', 0xea7b),
82 > more: register('more', 0xea7c),
83 > ellipsis: register('ellipsis', 0xea7c),
84 > kebabHorizontal: register('kebab-horizontal', 0xea7c),
85 > mailReply: register('mail-reply', 0xea7d),
86 > reply: register('reply', 0xea7d),
87 > organization: register('organization', 0xea7e),
88 > organizationFilled: register('organization-filled', 0xea7e),
89 > organizationOutline: register('organization-outline', 0xea7e),
90 > newFile: register('new-file', 0xea7f),
91 > fileAdd: register('file-add', 0xea7f),
92 > newFolder: register('new-folder', 0xea80),
93 > fileDirectoryCreate: register('file-directory-create', 0xea80),
94 > trash: register('trash', 0xea81),
95 > trashcan: register('trashcan', 0xea81),
96 > history: register('history', 0xea82),
97 > clock: register('clock', 0xea82),
98 > folder: register('folder', 0xea83),
99 > fileDirectory: register('file-directory', 0xea83),
100 > symbolFolder: register('symbol-folder', 0xea83),
101 > logoGithub: register('logo-github', 0xea84),
102 > markGithub: register('mark-github', 0xea84),
103 > github: register('github', 0xea84),
104 > terminal: register('terminal', 0xea85),
105 > console: register('console', 0xea85),
106 > repl: register('repl', 0xea85),
107 > zap: register('zap', 0xea86),
108 > symbolEvent: register('symbol-event', 0xea86),
109 > error: register('error', 0xea87),
110 > stop: register('stop', 0xea87),
111 > variable: register('variable', 0xea88),
112 > symbolVariable: register('symbol-variable', 0xea88),
113 > array: register('array', 0xea8a),
114 > symbolArray: register('symbol-array', 0xea8a),
115 > symbolModule: register('symbol-module', 0xea8b),
116 > symbolPackage: register('symbol-package', 0xea8b),
117 > symbolNamespace: register('symbol-namespace', 0xea8b),
118 > symbolObject: register('symbol-object', 0xea8b),
119 > symbolMethod: register('symbol-method', 0xea8c),
120 > symbolFunction: register('symbol-function', 0xea8c),
121 > symbolConstructor: register('symbol-constructor', 0xea8c),
122 > symbolBoolean: register('symbol-boolean', 0xea8f),
123 > symbolNull: register('symbol-null', 0xea8f),
124 > symbolNumeric: register('symbol-numeric', 0xea90),
125 > symbolNumber: register('symbol-number', 0xea90),
126 > symbolStructure: register('symbol-structure', 0xea91),
127 > symbolStruct: register('symbol-struct', 0xea91),
128 > symbolParameter: register('symbol-parameter', 0xea92),
129 > symbolTypeParameter: register('symbol-type-parameter', 0xea92),
130 > symbolKey: register('symbol-key', 0xea93),
131 > symbolText: register('symbol-text', 0xea93),
132 > symbolReference: register('symbol-reference', 0xea94),
133 > goToFile: register('go-to-file', 0xea94),
134 > symbolEnum: register('symbol-enum', 0xea95),
135 > symbolValue: register('symbol-value', 0xea95),
136 > symbolRuler: register('symbol-ruler', 0xea96),
137 > symbolUnit: register('symbol-unit', 0xea96),
138 > activateBreakpoints: register('activate-breakpoints', 0xea97),
139 > archive: register('archive', 0xea98),
140 > arrowBoth: register('arrow-both', 0xea99),
141 > arrowDown: register('arrow-down', 0xea9a),
142 > arrowLeft: register('arrow-left', 0xea9b),
143 > arrowRight: register('arrow-right', 0xea9c),
144 > arrowSmallDown: register('arrow-small-down', 0xea9d),
145 > arrowSmallLeft: register('arrow-small-left', 0xea9e),
146 > arrowSmallRight: register('arrow-small-right', 0xea9f),
147 > arrowSmallUp: register('arrow-small-up', 0xeaa0),
148 > arrowUp: register('arrow-up', 0xeaa1),
149 > bell: register('bell', 0xeaa2),
150 > bold: register('bold', 0xeaa3),
151 > book: register('book', 0xeaa4),
152 > bookmark: register('bookmark', 0xeaa5),
153 > debugBreakpointConditionalUnverified: register('debug-breakpoint-conditional-unverified', 0xeaa6),
154 > debugBreakpointConditional: register('debug-breakpoint-conditional', 0xeaa7),
155 > debugBreakpointConditionalDisabled: register('debug-breakpoint-conditional-disabled', 0xeaa7),
156 > debugBreakpointDataUnverified: register('debug-breakpoint-data-unverified', 0xeaa8),
157 > debugBreakpointData: register('debug-breakpoint-data', 0xeaa9),
158 > debugBreakpointDataDisabled: register('debug-breakpoint-data-disabled', 0xeaa9),
159 > debugBreakpointLogUnverified: register('debug-breakpoint-log-unverified', 0xeaaa),
160 > debugBreakpointLog: register('debug-breakpoint-log', 0xeaab),
161 > debugBreakpointLogDisabled: register('debug-breakpoint-log-disabled', 0xeaab),
162 > briefcase: register('briefcase', 0xeaac),
163 > broadcast: register('broadcast', 0xeaad),
164 > browser: register('browser', 0xeaae),
165 > bug: register('bug', 0xeaaf),
166 > calendar: register('calendar', 0xeab0),
167 > caseSensitive: register('case-sensitive', 0xeab1),
168 > check: register('check', 0xeab2),
169 > checklist: register('checklist', 0xeab3),
170 > chevronDown: register('chevron-down', 0xeab4),
171 > chevronLeft: register('chevron-left', 0xeab5),
172 > chevronRight: register('chevron-right', 0xeab6),
173 > chevronUp: register('chevron-up', 0xeab7),
174 > chromeClose: register('chrome-close', 0xeab8),
175 > chromeMaximize: register('chrome-maximize', 0xeab9),
176 > chromeMinimize: register('chrome-minimize', 0xeaba),
177 > chromeRestore: register('chrome-restore', 0xeabb),
178 > circleOutline: register('circle-outline', 0xeabc),
179 > circle: register('circle', 0xeabc),
180 > debugBreakpointUnverified: register('debug-breakpoint-unverified', 0xeabc),
181 > terminalDecorationIncomplete: register('terminal-decoration-incomplete', 0xeabc),
182 > circleSlash: register('circle-slash', 0xeabd),
183 > circuitBoard: register('circuit-board', 0xeabe),
184 > clearAll: register('clear-all', 0xeabf),
185 > clippy: register('clippy', 0xeac0),
186 > closeAll: register('close-all', 0xeac1),
187 > cloudDownload: register('cloud-download', 0xeac2),
188 > cloudUpload: register('cloud-upload', 0xeac3),
189 > code: register('code', 0xeac4),
190 > collapseAll: register('collapse-all', 0xeac5),
191 > colorMode: register('color-mode', 0xeac6),
192 > commentDiscussion: register('comment-discussion', 0xeac7),
193 > creditCard: register('credit-card', 0xeac9),
194 > dash: register('dash', 0xeacc),
195 > dashboard: register('dashboard', 0xeacd),
196 > database: register('database', 0xeace),
197 > debugContinue: register('debug-continue', 0xeacf),
198 > debugDisconnect: register('debug-disconnect', 0xead0),
199 > debugPause: register('debug-pause', 0xead1),
200 > debugRestart: register('debug-restart', 0xead2),
201 > debugStart: register('debug-start', 0xead3),
202 > debugStepInto: register('debug-step-into', 0xead4),
203 > debugStepOut: register('debug-step-out', 0xead5),
204 > debugStepOver: register('debug-step-over', 0xead6),
205 > debugStop: register('debug-stop', 0xead7),
206 > debug: register('debug', 0xead8),
207 > deviceCameraVideo: register('device-camera-video', 0xead9),
208 > deviceCamera: register('device-camera', 0xeada),
209 > deviceMobile: register('device-mobile', 0xeadb),
210 > diffAdded: register('diff-added', 0xeadc),
211 > diffIgnored: register('diff-ignored', 0xeadd),
212 > diffModified: register('diff-modified', 0xeade),
213 > diffRemoved: register('diff-removed', 0xeadf),
214 > diffRenamed: register('diff-renamed', 0xeae0),
215 > diff: register('diff', 0xeae1),
216 > diffSidebyside: register('diff-sidebyside', 0xeae1),
217 > discard: register('discard', 0xeae2),
218 > editorLayout: register('editor-layout', 0xeae3),
219 > emptyWindow: register('empty-window', 0xeae4),
220 > exclude: register('exclude', 0xeae5),
221 > extensions: register('extensions', 0xeae6),
222 > eyeClosed: register('eye-closed', 0xeae7),
223 > fileBinary: register('file-binary', 0xeae8),
224 > fileCode: register('file-code', 0xeae9),
225 > fileMedia: register('file-media', 0xeaea),
226 > filePdf: register('file-pdf', 0xeaeb),
227 > fileSubmodule: register('file-submodule', 0xeaec),
228 > fileSymlinkDirectory: register('file-symlink-directory', 0xeaed),
229 > fileSymlinkFile: register('file-symlink-file', 0xeaee),
230 > fileZip: register('file-zip', 0xeaef),
231 > files: register('files', 0xeaf0),
232 > filter: register('filter', 0xeaf1),
233 > flame: register('flame', 0xeaf2),
234 > foldDown: register('fold-down', 0xeaf3),
235 > foldUp: register('fold-up', 0xeaf4),
236 > fold: register('fold', 0xeaf5),
237 > folderActive: register('folder-active', 0xeaf6),
238 > folderOpened: register('folder-opened', 0xeaf7),
239 > gear: register('gear', 0xeaf8),
240 > gift: register('gift', 0xeaf9),
241 > gistSecret: register('gist-secret', 0xeafa),
242 > gist: register('gist', 0xeafb),
243 > gitCommit: register('git-commit', 0xeafc),
244 > gitCompare: register('git-compare', 0xeafd),
245 > compareChanges: register('compare-changes', 0xeafd),
246 > gitMerge: register('git-merge', 0xeafe),
247 > githubAction: register('github-action', 0xeaff),
248 > githubAlt: register('github-alt', 0xeb00),
249 > globe: register('globe', 0xeb01),
250 > grabber: register('grabber', 0xeb02),
251 > graph: register('graph', 0xeb03),
252 > gripper: register('gripper', 0xeb04),
253 > heart: register('heart', 0xeb05),
254 > home: register('home', 0xeb06),
255 > horizontalRule: register('horizontal-rule', 0xeb07),
256 > hubot: register('hubot', 0xeb08),
257 > inbox: register('inbox', 0xeb09),
258 > issueReopened: register('issue-reopened', 0xeb0b),
259 > issues: register('issues', 0xeb0c),
260 > italic: register('italic', 0xeb0d),
261 > jersey: register('jersey', 0xeb0e),
262 > json: register('json', 0xeb0f),
263 > bracket: register('bracket', 0xeb0f),
264 > kebabVertical: register('kebab-vertical', 0xeb10),
265 > key: register('key', 0xeb11),
266 > law: register('law', 0xeb12),
267 > lightbulbAutofix: register('lightbulb-autofix', 0xeb13),
268 > linkExternal: register('link-external', 0xeb14),
269 > link: register('link', 0xeb15),
270 > listOrdered: register('list-ordered', 0xeb16),
271 > listUnordered: register('list-unordered', 0xeb17),
272 > liveShare: register('live-share', 0xeb18),
273 > loading: register('loading', 0xeb19),
274 > location: register('location', 0xeb1a),
275 > mailRead: register('mail-read', 0xeb1b),
276 > mail: register('mail', 0xeb1c),
277 > markdown: register('markdown', 0xeb1d),
278 > megaphone: register('megaphone', 0xeb1e),
279 > mention: register('mention', 0xeb1f),
280 > milestone: register('milestone', 0xeb20),
281 > gitPullRequestMilestone: register('git-pull-request-milestone', 0xeb20),
282 > mortarBoard: register('mortar-board', 0xeb21),
283 > move: register('move', 0xeb22),
284 > multipleWindows: register('multiple-windows', 0xeb23),
285 > mute: register('mute', 0xeb24),
286 > noNewline: register('no-newline', 0xeb25),
287 > note: register('note', 0xeb26),
288 > octoface: register('octoface', 0xeb27),
289 > openPreview: register('open-preview', 0xeb28),
290 > package: register('package', 0xeb29),
291 > paintcan: register('paintcan', 0xeb2a),
292 > pin: register('pin', 0xeb2b),
293 > play: register('play', 0xeb2c),
294 > run: register('run', 0xeb2c),
295 > plug: register('plug', 0xeb2d),
296 > preserveCase: register('preserve-case', 0xeb2e),
297 > preview: register('preview', 0xeb2f),
298 > project: register('project', 0xeb30),
299 > pulse: register('pulse', 0xeb31),
300 > question: register('question', 0xeb32),
301 > quote: register('quote', 0xeb33),
302 > radioTower: register('radio-tower', 0xeb34),
303 > reactions: register('reactions', 0xeb35),
304 > references: register('references', 0xeb36),
305 > refresh: register('refresh', 0xeb37),
306 > regex: register('regex', 0xeb38),
307 > remoteExplorer: register('remote-explorer', 0xeb39),
308 > remote: register('remote', 0xeb3a),
309 > remove: register('remove', 0xeb3b),
310 > replaceAll: register('replace-all', 0xeb3c),
311 > replace: register('replace', 0xeb3d),
312 > repoClone: register('repo-clone', 0xeb3e),
313 > repoForcePush: register('repo-force-push', 0xeb3f),
314 > repoPull: register('repo-pull', 0xeb40),
315 > repoPush: register('repo-push', 0xeb41),
316 > report: register('report', 0xeb42),
317 > requestChanges: register('request-changes', 0xeb43),
318 > rocket: register('rocket', 0xeb44),
319 > rootFolderOpened: register('root-folder-opened', 0xeb45),
320 > rootFolder: register('root-folder', 0xeb46),
321 > rss: register('rss', 0xeb47),
322 > ruby: register('ruby', 0xeb48),
323 > saveAll: register('save-all', 0xeb49),
324 > saveAs: register('save-as', 0xeb4a),
325 > save: register('save', 0xeb4b),
326 > screenFull: register('screen-full', 0xeb4c),
327 > screenNormal: register('screen-normal', 0xeb4d),
328 > searchStop: register('search-stop', 0xeb4e),
329 > server: register('server', 0xeb50),
330 > settingsGear: register('settings-gear', 0xeb51),
331 > settings: register('settings', 0xeb52),
332 > shield: register('shield', 0xeb53),
333 > smiley: register('smiley', 0xeb54),
334 > sortPrecedence: register('sort-precedence', 0xeb55),
335 > splitHorizontal: register('split-horizontal', 0xeb56),
336 > splitVertical: register('split-vertical', 0xeb57),
337 > squirrel: register('squirrel', 0xeb58),
338 > starFull: register('star-full', 0xeb59),
339 > starHalf: register('star-half', 0xeb5a),
340 > symbolClass: register('symbol-class', 0xeb5b),
341 > symbolColor: register('symbol-color', 0xeb5c),
342 > symbolConstant: register('symbol-constant', 0xeb5d),
343 > symbolEnumMember: register('symbol-enum-member', 0xeb5e),
344 > symbolField: register('symbol-field', 0xeb5f),
345 > symbolFile: register('symbol-file', 0xeb60),
346 > symbolInterface: register('symbol-interface', 0xeb61),
347 > symbolKeyword: register('symbol-keyword', 0xeb62),
348 > symbolMisc: register('symbol-misc', 0xeb63),
349 > symbolOperator: register('symbol-operator', 0xeb64),
350 > symbolProperty: register('symbol-property', 0xeb65),
351 > wrench: register('wrench', 0xeb65),
352 > wrenchSubaction: register('wrench-subaction', 0xeb65),
353 > symbolSnippet: register('symbol-snippet', 0xeb66),
354 > tasklist: register('tasklist', 0xeb67),
355 > telescope: register('telescope', 0xeb68),
356 > textSize: register('text-size', 0xeb69),
357 > threeBars: register('three-bars', 0xeb6a),
358 > thumbsdown: register('thumbsdown', 0xeb6b),
359 > thumbsup: register('thumbsup', 0xeb6c),
360 > tools: register('tools', 0xeb6d),
361 > triangleDown: register('triangle-down', 0xeb6e),
362 > triangleLeft: register('triangle-left', 0xeb6f),
363 > triangleRight: register('triangle-right', 0xeb70),
364 > triangleUp: register('triangle-up', 0xeb71),
365 > twitter: register('twitter', 0xeb72),
366 > unfold: register('unfold', 0xeb73),
367 > unlock: register('unlock', 0xeb74),
368 > unmute: register('unmute', 0xeb75),
369 > unverified: register('unverified', 0xeb76),
370 > verified: register('verified', 0xeb77),
371 > versions: register('versions', 0xeb78),
372 > vmActive: register('vm-active', 0xeb79),
373 > vmOutline: register('vm-outline', 0xeb7a),
374 > vmRunning: register('vm-running', 0xeb7b),
375 > watch: register('watch', 0xeb7c),
376 > whitespace: register('whitespace', 0xeb7d),
377 > wholeWord: register('whole-word', 0xeb7e),
378 > window: register('window', 0xeb7f),
379 > wordWrap: register('word-wrap', 0xeb80),
380 > zoomIn: register('zoom-in', 0xeb81),
381 > zoomOut: register('zoom-out', 0xeb82),
382 > listFilter: register('list-filter', 0xeb83),
383 > listFlat: register('list-flat', 0xeb84),
384 > listSelection: register('list-selection', 0xeb85),
385 > selection: register('selection', 0xeb85),
386 > listTree: register('list-tree', 0xeb86),
387 > debugBreakpointFunctionUnverified: register('debug-breakpoint-function-unverified', 0xeb87),
388 > debugBreakpointFunction: register('debug-breakpoint-function', 0xeb88),
389 > debugBreakpointFunctionDisabled: register('debug-breakpoint-function-disabled', 0xeb88),
390 > debugStackframeActive: register('debug-stackframe-active', 0xeb89),
391 > circleSmallFilled: register('circle-small-filled', 0xeb8a),
392 > debugStackframeDot: register('debug-stackframe-dot', 0xeb8a),
393 > terminalDecorationMark: register('terminal-decoration-mark', 0xeb8a),
394 > debugStackframe: register('debug-stackframe', 0xeb8b),
395 > debugStackframeFocused: register('debug-stackframe-focused', 0xeb8b),
396 > debugBreakpointUnsupported: register('debug-breakpoint-unsupported', 0xeb8c),
397 > symbolString: register('symbol-string', 0xeb8d),
398 > debugReverseContinue: register('debug-reverse-continue', 0xeb8e),
399 > debugStepBack: register('debug-step-back', 0xeb8f),
400 > debugRestartFrame: register('debug-restart-frame', 0xeb90),
401 > debugAlt: register('debug-alt', 0xeb91),
402 > callIncoming: register('call-incoming', 0xeb92),
403 > callOutgoing: register('call-outgoing', 0xeb93),
404 > menu: register('menu', 0xeb94),
405 > expandAll: register('expand-all', 0xeb95),
406 > feedback: register('feedback', 0xeb96),
407 > gitPullRequestReviewer: register('git-pull-request-reviewer', 0xeb96),
408 > groupByRefType: register('group-by-ref-type', 0xeb97),
409 > ungroupByRefType: register('ungroup-by-ref-type', 0xeb98),
410 > account: register('account', 0xeb99),
411 > gitPullRequestAssignee: register('git-pull-request-assignee', 0xeb99),
412 > bellDot: register('bell-dot', 0xeb9a),
413 > debugConsole: register('debug-console', 0xeb9b),
414 > library: register('library', 0xeb9c),
415 > output: register('output', 0xeb9d),
416 > runAll: register('run-all', 0xeb9e),
417 > syncIgnored: register('sync-ignored', 0xeb9f),
418 > pinned: register('pinned', 0xeba0),
419 > githubInverted: register('github-inverted', 0xeba1),
420 > serverProcess: register('server-process', 0xeba2),
421 > serverEnvironment: register('server-environment', 0xeba3),
422 > pass: register('pass', 0xeba4),
423 > issueClosed: register('issue-closed', 0xeba4),
424 > stopCircle: register('stop-circle', 0xeba5),
425 > playCircle: register('play-circle', 0xeba6),
426 > record: register('record', 0xeba7),
427 > debugAltSmall: register('debug-alt-small', 0xeba8),
428 > vmConnect: register('vm-connect', 0xeba9),
429 > cloud: register('cloud', 0xebaa),
430 > merge: register('merge', 0xebab),
431 > export: register('export', 0xebac),
432 > graphLeft: register('graph-left', 0xebad),
433 > magnet: register('magnet', 0xebae),
434 > notebook: register('notebook', 0xebaf),
435 > redo: register('redo', 0xebb0),
436 > checkAll: register('check-all', 0xebb1),
437 > pinnedDirty: register('pinned-dirty', 0xebb2),
438 > passFilled: register('pass-filled', 0xebb3),
439 > circleLargeFilled: register('circle-large-filled', 0xebb4),
440 > circleLarge: register('circle-large', 0xebb5),
441 > circleLargeOutline: register('circle-large-outline', 0xebb5),
442 > combine: register('combine', 0xebb6),
443 > gather: register('gather', 0xebb6),
444 > table: register('table', 0xebb7),
445 > variableGroup: register('variable-group', 0xebb8),
446 > typeHierarchy: register('type-hierarchy', 0xebb9),
447 > typeHierarchySub: register('type-hierarchy-sub', 0xebba),
448 > typeHierarchySuper: register('type-hierarchy-super', 0xebbb),
449 > gitPullRequestCreate: register('git-pull-request-create', 0xebbc),
450 > runAbove: register('run-above', 0xebbd),
451 > runBelow: register('run-below', 0xebbe),
452 > notebookTemplate: register('notebook-template', 0xebbf),
453 > debugRerun: register('debug-rerun', 0xebc0),
454 > workspaceTrusted: register('workspace-trusted', 0xebc1),
455 > workspaceUntrusted: register('workspace-untrusted', 0xebc2),
456 > workspaceUnknown: register('workspace-unknown', 0xebc3),
457 > terminalCmd: register('terminal-cmd', 0xebc4),
458 > terminalDebian: register('terminal-debian', 0xebc5),
459 > terminalLinux: register('terminal-linux', 0xebc6),
460 > terminalPowershell: register('terminal-powershell', 0xebc7),
461 > terminalTmux: register('terminal-tmux', 0xebc8),
462 > terminalUbuntu: register('terminal-ubuntu', 0xebc9),
463 > terminalBash: register('terminal-bash', 0xebca),
464 > arrowSwap: register('arrow-swap', 0xebcb),
465 > copy: register('copy', 0xebcc),
466 > personAdd: register('person-add', 0xebcd),
467 > filterFilled: register('filter-filled', 0xebce),
468 > wand: register('wand', 0xebcf),
469 > debugLineByLine: register('debug-line-by-line', 0xebd0),
470 > inspect: register('inspect', 0xebd1),
471 > layers: register('layers', 0xebd2),
472 > layersDot: register('layers-dot', 0xebd3),
473 > layersActive: register('layers-active', 0xebd4),
474 > compass: register('compass', 0xebd5),
475 > compassDot: register('compass-dot', 0xebd6),
476 > compassActive: register('compass-active', 0xebd7),
477 > azure: register('azure', 0xebd8),
478 > issueDraft: register('issue-draft', 0xebd9),
479 > gitPullRequestClosed: register('git-pull-request-closed', 0xebda),
480 > gitPullRequestDraft: register('git-pull-request-draft', 0xebdb),
481 > debugAll: register('debug-all', 0xebdc),
482 > debugCoverage: register('debug-coverage', 0xebdd),
483 > runErrors: register('run-errors', 0xebde),
484 > folderLibrary: register('folder-library', 0xebdf),
485 > debugContinueSmall: register('debug-continue-small', 0xebe0),
486 > beakerStop: register('beaker-stop', 0xebe1),
487 > graphLine: register('graph-line', 0xebe2),
488 > graphScatter: register('graph-scatter', 0xebe3),
489 > pieChart: register('pie-chart', 0xebe4),
490 > bracketDot: register('bracket-dot', 0xebe5),
491 > bracketError: register('bracket-error', 0xebe6),
492 > lockSmall: register('lock-small', 0xebe7),
493 > azureDevops: register('azure-devops', 0xebe8),
494 > verifiedFilled: register('verified-filled', 0xebe9),
495 > newline: register('newline', 0xebea),
496 > layout: register('layout', 0xebeb),
497 > layoutActivitybarLeft: register('layout-activitybar-left', 0xebec),
498 > layoutActivitybarRight: register('layout-activitybar-right', 0xebed),
499 > layoutPanelLeft: register('layout-panel-left', 0xebee),
500 > layoutPanelCenter: register('layout-panel-center', 0xebef),
501 > layoutPanelJustify: register('layout-panel-justify', 0xebf0),
502 > layoutPanelRight: register('layout-panel-right', 0xebf1),
503 > layoutPanel: register('layout-panel', 0xebf2),
504 > layoutSidebarLeft: register('layout-sidebar-left', 0xebf3),
505 > layoutSidebarRight: register('layout-sidebar-right', 0xebf4),
506 > layoutStatusbar: register('layout-statusbar', 0xebf5),
507 > layoutMenubar: register('layout-menubar', 0xebf6),
508 > layoutCentered: register('layout-centered', 0xebf7),
509 > target: register('target', 0xebf8),
510 > indent: register('indent', 0xebf9),
511 > recordSmall: register('record-small', 0xebfa),
512 > errorSmall: register('error-small', 0xebfb),
513 > terminalDecorationError: register('terminal-decoration-error', 0xebfb),
514 > arrowCircleDown: register('arrow-circle-down', 0xebfc),
515 > arrowCircleLeft: register('arrow-circle-left', 0xebfd),
516 > arrowCircleRight: register('arrow-circle-right', 0xebfe),
517 > arrowCircleUp: register('arrow-circle-up', 0xebff),
518 > layoutSidebarRightOff: register('layout-sidebar-right-off', 0xec00),
519 > layoutPanelOff: register('layout-panel-off', 0xec01),
520 > layoutSidebarLeftOff: register('layout-sidebar-left-off', 0xec02),
521 > blank: register('blank', 0xec03),
522 > heartFilled: register('heart-filled', 0xec04),
523 > map: register('map', 0xec05),
524 > mapHorizontal: register('map-horizontal', 0xec05),
525 > foldHorizontal: register('fold-horizontal', 0xec05),
526 > mapFilled: register('map-filled', 0xec06),
527 > mapHorizontalFilled: register('map-horizontal-filled', 0xec06),
528 > foldHorizontalFilled: register('fold-horizontal-filled', 0xec06),
529 > circleSmall: register('circle-small', 0xec07),
530 > bellSlash: register('bell-slash', 0xec08),
531 > bellSlashDot: register('bell-slash-dot', 0xec09),
532 > commentUnresolved: register('comment-unresolved', 0xec0a),
533 > gitPullRequestGoToChanges: register('git-pull-request-go-to-changes', 0xec0b),
534 > gitPullRequestNewChanges: register('git-pull-request-new-changes', 0xec0c),
535 > searchFuzzy: register('search-fuzzy', 0xec0d),
536 > commentDraft: register('comment-draft', 0xec0e),
537 > send: register('send', 0xec0f),
538 > sparkle: register('sparkle', 0xec10),
539 > insert: register('insert', 0xec11),
540 > mic: register('mic', 0xec12),
541 > thumbsdownFilled: register('thumbsdown-filled', 0xec13),
542 > thumbsupFilled: register('thumbsup-filled', 0xec14),
543 > coffee: register('coffee', 0xec15),
544 > snake: register('snake', 0xec16),
545 > game: register('game', 0xec17),
546 > vr: register('vr', 0xec18),
547 > chip: register('chip', 0xec19),
548 > piano: register('piano', 0xec1a),
549 > music: register('music', 0xec1b),
550 > micFilled: register('mic-filled', 0xec1c),
551 > repoFetch: register('repo-fetch', 0xec1d),
552 > copilot: register('copilot', 0xec1e),
553 > lightbulbSparkle: register('lightbulb-sparkle', 0xec1f),
554 > robot: register('robot', 0xec20),
555 > sparkleFilled: register('sparkle-filled', 0xec21),
556 > diffSingle: register('diff-single', 0xec22),
557 > diffMultiple: register('diff-multiple', 0xec23),
558 > surroundWith: register('surround-with', 0xec24),
559 > share: register('share', 0xec25),
560 > gitStash: register('git-stash', 0xec26),
561 > gitStashApply: register('git-stash-apply', 0xec27),
562 > gitStashPop: register('git-stash-pop', 0xec28),
563 > vscode: register('vscode', 0xec29),
564 > vscodeInsiders: register('vscode-insiders', 0xec2a),
565 > codeOss: register('code-oss', 0xec2b),
566 > runCoverage: register('run-coverage', 0xec2c),
567 > runAllCoverage: register('run-all-coverage', 0xec2d),
568 > coverage: register('coverage', 0xec2e),
569 > githubProject: register('github-project', 0xec2f),
570 > mapVertical: register('map-vertical', 0xec30),
571 > foldVertical: register('fold-vertical', 0xec30),
572 > mapVerticalFilled: register('map-vertical-filled', 0xec31),
573 > foldVerticalFilled: register('fold-vertical-filled', 0xec31),
574 > goToSearch: register('go-to-search', 0xec32),
575 > percentage: register('percentage', 0xec33),
576 > sortPercentage: register('sort-percentage', 0xec33),
577 > attach: register('attach', 0xec34),
578 > goToEditingSession: register('go-to-editing-session', 0xec35),
579 > editSession: register('edit-session', 0xec36),
580 > codeReview: register('code-review', 0xec37),
581 > copilotWarning: register('copilot-warning', 0xec38),
582 > python: register('python', 0xec39),
583 > copilotLarge: register('copilot-large', 0xec3a),
584 > copilotWarningLarge: register('copilot-warning-large', 0xec3b),
585 > keyboardTab: register('keyboard-tab', 0xec3c),
586 > copilotBlocked: register('copilot-blocked', 0xec3d),
587 > copilotNotConnected: register('copilot-not-connected', 0xec3e),
588 > flag: register('flag', 0xec3f),
589 > lightbulbEmpty: register('lightbulb-empty', 0xec40),
590 > symbolMethodArrow: register('symbol-method-arrow', 0xec41),
591 > copilotUnavailable: register('copilot-unavailable', 0xec42),
592 > repoPinned: register('repo-pinned', 0xec43),
593 > keyboardTabAbove: register('keyboard-tab-above', 0xec44),
594 > keyboardTabBelow: register('keyboard-tab-below', 0xec45),
595 > gitPullRequestDone: register('git-pull-request-done', 0xec46),
596 > mcp: register('mcp', 0xec47),
597 > extensionsLarge: register('extensions-large', 0xec48),
598 > layoutPanelDock: register('layout-panel-dock', 0xec49),
599 > layoutSidebarLeftDock: register('layout-sidebar-left-dock', 0xec4a),
600 > layoutSidebarRightDock: register('layout-sidebar-right-dock', 0xec4b),
601 > copilotInProgress: register('copilot-in-progress', 0xec4c),
602 > copilotError: register('copilot-error', 0xec4d),
603 > copilotSuccess: register('copilot-success', 0xec4e),
604 > chatSparkle: register('chat-sparkle', 0xec4f),
605 > searchSparkle: register('search-sparkle', 0xec50),
606 > editSparkle: register('edit-sparkle', 0xec51),
607 > copilotSnooze: register('copilot-snooze', 0xec52),
608 > sendToRemoteAgent: register('send-to-remote-agent', 0xec53),
609 > commentDiscussionSparkle: register('comment-discussion-sparkle', 0xec54),
610 > chatSparkleWarning: register('chat-sparkle-warning', 0xec55),
611 > chatSparkleError: register('chat-sparkle-error', 0xec56),
612 > collection: register('collection', 0xec57),
613 > newCollection: register('new-collection', 0xec58),
614 > thinking: register('thinking', 0xec59),
615 > build: register('build', 0xec5a),
616 > commentDiscussionQuote: register('comment-discussion-quote', 0xec5b),
617 > cursor: register('cursor', 0xec5c),
618 > eraser: register('eraser', 0xec5d),
619 > fileText: register('file-text', 0xec5e),
620 > quotes: register('quotes', 0xec60),
621 > rename: register('rename', 0xec61),
622 > runWithDeps: register('run-with-deps', 0xec62),
623 > debugConnected: register('debug-connected', 0xec63),
624 > strikethrough: register('strikethrough', 0xec64),
625 > openInProduct: register('open-in-product', 0xec65),
626 > indexZero: register('index-zero', 0xec66),
627 > agent: register('agent', 0xec67),
628 > editCode: register('edit-code', 0xec68),
629 > repoSelected: register('repo-selected', 0xec69),
630 > skip: register('skip', 0xec6a),
631 > mergeInto: register('merge-into', 0xec6b),
632 > gitBranchChanges: register('git-branch-changes', 0xec6c),
633 > gitBranchStagedChanges: register('git-branch-staged-changes', 0xec6d),
634 > gitBranchConflicts: register('git-branch-conflicts', 0xec6e),
635 > gitBranch: register('git-branch', 0xec6f),
636 > gitBranchCreate: register('git-branch-create', 0xec6f),
637 > gitBranchDelete: register('git-branch-delete', 0xec6f),
638 > searchLarge: register('search-large', 0xec70),
639 > terminalGitBash: register('terminal-git-bash', 0xec71),
640 > windowActive: register('window-active', 0xec72),
641 > forward: register('forward', 0xec73),
642 > download: register('download', 0xec74),
643 > clockface: register('clockface', 0xec75),
644 > unarchive: register('unarchive', 0xec76),
645 > sessionInProgress: register('session-in-progress', 0xec77),
646 > collectionSmall: register('collection-small', 0xec78),
647 > vmSmall: register('vm-small', 0xec79),
648 > cloudSmall: register('cloud-small', 0xec7a),
649 > addSmall: register('add-small', 0xec7b),
650 > removeSmall: register('remove-small', 0xec7c),
651 > worktreeSmall: register('worktree-small', 0xec7d),
652 > worktree: register('worktree', 0xec7e),
653 > screenCut: register('screen-cut', 0xec7f),
654 > ask: register('ask', 0xec80),
655 > openai: register('openai', 0xec81),
656 > claude: register('claude', 0xec82),
657 > openInWindow: register('open-in-window', 0xec83),
658 > newSession: register('new-session', 0xec84),
659 > terminalSecure: register('terminal-secure', 0xec85),
660 > chatImport: register('chat-import', 0xec86),
661 > chatExport: register('chat-export', 0xec87),
662 > shareWindow: register('share-window', 0xec88),
663 > circleSlashCompact: register('circle-slash-compact', 0xec89),
664 > copilotCompact: register('copilot-compact', 0xec8a),
665 > folderOpenedCompact: register('folder-opened-compact', 0xec8b),
666 > folderCompact: register('folder-compact', 0xec8c),
667 > gearCompact: register('gear-compact', 0xec8d),
668 > gitBranchCompact: register('git-branch-compact', 0xec8e),
669 > libraryCompact: register('library-compact', 0xec8f),
670 > recordKeysCompact: register('record-keys-compact', 0xec90),
671 > remoteCompact: register('remote-compact', 0xec91),
672 > repoForkedCompact: register('repo-forked-compact', 0xec92),
673 > repoCompact: register('repo-compact', 0xec93),
674 > shieldCompact: register('shield-compact', 0xec94),
675 > sparkleCompact: register('sparkle-compact', 0xec95),
676 > symbolColorCompact: register('symbol-color-compact', 0xec96),
677 > windowCompact: register('window-compact', 0xec97),
678 > errorCompact: register('error-compact', 0xec98),
679 > warningCompact: register('warning-compact', 0xec99),
680 > passCompact: register('pass-compact', 0xec9a),
681 > important: register('important', 0xec9b),
682 > importantCompact: register('important-compact', 0xec9c),
683 > rocketCompact: register('rocket-compact', 0xec9d),
684 > unpin: register('unpin', 0xec9e),
685 > addCompact: register('add-compact', 0xec9f),
686 > attachCompact: register('attach-compact', 0xeca0),
687 > beakerCompact: register('beaker-compact', 0xeca1),
688 > checkCompact: register('check-compact', 0xeca2),
689 > checklistCompact: register('checklist-compact', 0xeca3),
690 > chevronDownCompact: register('chevron-down-compact', 0xeca4),
691 > chevronLeftCompact: register('chevron-left-compact', 0xeca5),
692 > chevronRightCompact: register('chevron-right-compact', 0xeca6),
693 > chevronUpCompact: register('chevron-up-compact', 0xeca7),
694 > circleFilledCompact: register('circle-filled-compact', 0xeca8),
695 > circleSmallFilledCompact: register('circle-small-filled-compact', 0xeca9),
696 > closeCompact: register('close-compact', 0xecaa),
697 > collapseAllCompact: register('collapse-all-compact', 0xecab),
698 > commentCompact: register('comment-compact', 0xecac),
699 > commentUnresolvedCompact: register('comment-unresolved-compact', 0xecad),
700 > debugConnectedCompact: register('debug-connected-compact', 0xecae),
701 > debugDisconnectCompact: register('debug-disconnect-compact', 0xecaf),
702 > editCompact: register('edit-compact', 0xecb0),
703 > fileMediaCompact: register('file-media-compact', 0xecb1),
704 > gitFetch: register('git-fetch', 0xecb2),
705 > lightbulbCompact: register('lightbulb-compact', 0xecb3),
706 > loadingCompact: register('loading-compact', 0xecb4),
707 > passFilledCompact: register('pass-filled-compact', 0xecb5),
708 > projectCompact: register('project-compact', 0xecb6),
709 > refreshCompact: register('refresh-compact', 0xecb7),
710 > searchCompact: register('search-compact', 0xecb8),
711 > sessionInProgressCompact: register('session-in-progress-compact', 0xecb9),
712 > syncCompact: register('sync-compact', 0xecba),
713 > terminalCompact: register('terminal-compact', 0xecbb),
714 > vmPending: register('vm-pending', 0xecbc),
715 > worktreeCompact: register('worktree-compact', 0xecbd),
716 > developerTools: register('developer-tools', 0xecbe),
717 > cloudCompact: register('cloud-compact', 0xecbf),
718 > agentCompact: register('agent-compact', 0xecc0),
719 > askCompact: register('ask-compact', 0xecc1),
720 > settingsCompact: register('settings-compact', 0xecc2),
721 > vmCompact: register('vm-compact', 0xecc3),
722 > runCompact: register('run-compact', 0xecc4),
723 > gitPullRequestComment: register('git-pull-request-comment', 0xecc5),
724 > gitPullRequestError: register('git-pull-request-error', 0xecc6),
725 > rightPanelHide: register('right-panel-hide', 0xecc7),
726 > rightPanelShow: register('right-panel-show', 0xecc8),
727 > vscodeInsidersOutline: register('vscode-insiders-outline', 0xecc9),
728 > vscodeOutline: register('vscode-outline', 0xecca),
729 > voiceMode: register('voice-mode', 0xeccb),
730 > voiceModeCompact: register('voice-mode-compact', 0xeccc),
731 > micDownload: register('mic-download', 0xeccd),
732 > micDownloadCompact: register('mic-download-compact', 0xecce),
733 > voiceModeDownload: register('voice-mode-download', 0xeccf),
734 > voiceModeDownloadCompact: register('voice-mode-download-compact', 0xecd0),
735 > googleGemini: register('google-gemini', 0xecd1),
736 > kimi: register('kimi', 0xecd2),
737 > microsoft: register('microsoft', 0xecd3),
738 > fish1Happy: register('fish1-happy', 0xecd4),
739 > fish1Neutral: register('fish1-neutral', 0xecd5),
740 > fish1Sad: register('fish1-sad', 0xecd6),
741 > fish1VerySad: register('fish1-very-sad', 0xecd7),
742 > fish2Happy: register('fish2-happy', 0xecd8),
743 > fish2Neutral: register('fish2-neutral', 0xecd9),
744 > fish2Sad: register('fish2-sad', 0xecda),
745 > fish2VerySad: register('fish2-very-sad', 0xecdb),
746 > fish3Happy: register('fish3-happy', 0xecdc),
747 > fish3Neutral: register('fish3-neutral', 0xecdd),
748 > fish3Sad: register('fish3-sad', 0xecde),
749 > fish3VerySad: register('fish3-very-sad', 0xecdf),
750 > fish4Happy: register('fish4-happy', 0xece0),
751 > fish4Neutral: register('fish4-neutral', 0xece1),
752 > fish4Sad: register('fish4-sad', 0xece2),
753 > fish4VerySad: register('fish4-very-sad', 0xece3),
754 > personVoice: register('person-voice', 0xece4),
755 > personVoiceCompact: register('person-voice-compact', 0xece5),
756 > personVoiceFilled: register('person-voice-filled', 0xece6),
757 > personVoiceFilledCompact: register('person-voice-filled-compact', 0xece7),
758 > } as const;
src/vs/sessions/services/sessions/common/session.ts 703 covered LOC · 21 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- session.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CancellationToken } from '../../../../base/common/cancellation.js';
7 > import { IMarkdownString } from '../../../../base/common/htmlContent.js';
8 > import { IObservable, IReader } from '../../../../base/common/observable.js';
9 > import { isEqual } from '../../../../base/common/resources.js';
10 > import { ThemeIcon } from '../../../../base/common/themables.js';
11 > import { URI } from '../../../../base/common/uri.js';
12 > import { localize } from '../../../../nls.js';
13 > import { IChatSessionFileChange, IChatSessionFileChange2, isIChatSessionFileChange2 } from '../../../../workbench/contrib/chat/common/chatSessionsService.js';
14 >
15 > export interface ISessionType {
16 > /** Unique identifier (e.g., 'copilot-cli', 'copilot-cloud', 'claude-code'). */
17 > readonly id: string;
18 > /** Display label (e.g., 'Copilot CLI', 'Cloud'). */
19 > readonly label: string;
20 > /** Icon for this session type. */
21 > readonly icon: ThemeIcon;
22 > /** Whether new sessions of this type support Worktree isolation and base-branch selection. */
23 > readonly supportsWorktreeConfiguration?: boolean;
24 > /**
25 > * The workbench chat session type (contribution id) this session type maps
26 > * to, when it differs from {@link id}. Agent-host providers use a bare agent
27 > * provider name as {@link id} (e.g. `claude`) but register their chat session
28 > * contribution and models under `agent-host-<provider>`, so they set this to
29 > * bridge the two (e.g. for entitlement/model availability lookups). Defaults
30 > * to {@link id} when omitted.
31 > */
32 > readonly chatSessionType?: string;
33 > }
34 >
35 > export const GITHUB_REMOTE_FILE_SCHEME = 'github-remote-file';
36 >
37 > /**
38 > * Status of an agent session as reported by the sessions provider.
39 > */
40 > export const enum SessionStatus {
41 > /** Session has not been sent yet (new/untitled). */
42 > Untitled = 0,
43 > /** Agent is actively working. */
44 > InProgress = 1,
45 > /** Agent is waiting for user input. */
46 > NeedsInput = 2,
47 > /** Session has completed successfully. */
48 > Completed = 3,
49 > /** Session encountered an error. */
50 > Error = 4,
51 > }
52 >
53 > /** Whether a session still has active work, including work blocked on user input. */
54 > export function isActiveSessionStatus(status: SessionStatus): boolean {
55 return status === SessionStatus.InProgress || status === SessionStatus.NeedsInput;
56 }
57 > session.ts
58 > /**
59 > * Provider-agnostic interactivity of a chat within a session. Mirrors the agent
60 > * host protocol's notion of chat interactivity but is decoupled from it so that
61 > * non-agent-host providers can report it too.
62 > *
63 > * Supports the agent-team pattern where a lead chat is fully interactive while
64 > * worker chats are read-only (visible for observability) or hidden (internal
65 > * implementation detail).
66 > */
67 > export const enum ChatInteractivity {
68 > /** The user can send messages to the chat (default when unspecified). */
69 > Full = 'full',
70 > /** The chat is visible but read-only — the user can watch but not send messages. */
71 > ReadOnly = 'read-only',
72 > /** The chat is an internal worker that should not be shown in the UI at all. */
73 > Hidden = 'hidden',
74 > }
75 >
76 > /**
77 > * The effective interactivity of a chat given its session's archived state.
78 > *
79 > * An archived session is read-only: its interactive chats must hide their
80 > * composer. `Hidden` chats are internal workers filtered out of the UI, so they
81 > * stay hidden — archiving only downgrades `Full` chats to `ReadOnly`. When not
82 > * archived, the chat keeps its own interactivity.
83 > */
84 > export function effectiveChatInteractivity(isArchived: boolean, interactivity: ChatInteractivity): ChatInteractivity {
85 if (interactivity === ChatInteractivity.Hidden) {
86 return ChatInteractivity.Hidden;
88 return isArchived ? ChatInteractivity.ReadOnly : interactivity;
89 }
90 > session.ts
91 > export interface ISessionGitRepository {
92 > /** The source repository URI. */
93 > readonly uri: URI;
94 > /** The working directory URI (e.g., a git worktree or checkout path). */
95 > readonly workTreeUri: URI | undefined;
96 > /** Current branch name. */
97 > readonly branchName?: string;
98 > /** Name of the base branch. */
99 > readonly baseBranchName: string | undefined;
100 > /** Whether the base branch is protected (drives PR vs merge workflow). */
101 > readonly baseBranchProtected?: boolean;
102 > /** Whether the repository has a github.com remote. */
103 > readonly hasGitHubRemote?: boolean;
104 > /** Upstream tracking branch name (e.g. `origin/feature`). */
105 > readonly upstreamBranchName?: string;
106 > /** Number of commits the upstream branch is ahead of the local branch. */
107 > readonly incomingChanges?: number;
108 > /** Number of commits the local branch is ahead of the upstream branch. */
109 > readonly outgoingChanges?: number;
110 > /** Number of files with uncommitted changes. */
111 > readonly uncommittedChanges?: number;
112 > /** Whether a Git operation is currently in progress. */
113 > readonly hasGitOperationInProgress?: boolean;
114 > /** GitHub information associated with the repository. */
115 > readonly gitHubInfo: IObservable<IGitHubInfo | undefined>;
116 > }
117 >
118 > /**
119 > * A folder within a session workspace.
120 > */
121 > export interface ISessionFolder {
122 > /** Canonical URI of the folder. */
123 > readonly root: URI;
124 > /** Working directory used for file operations. */
125 > readonly workingDirectory: URI;
126 > /** Display name for the folder (e.g., repository or directory basename). */
127 > readonly name: string;
128 > /** Optional description shown alongside the name (e.g., parent folder path). */
129 > readonly description: string | undefined;
130 > /** Git repository information associated with this folder. */
131 > readonly gitRepository?: ISessionGitRepository;
132 > }
133 >
134 > /**
135 > * Workspace information for a session, encapsulating one or more repositories.
136 > */
137 > export interface ISessionWorkspace {
138 > /** URI identifying the workspace. */
139 > readonly uri: URI;
140 > /** Display label for the workspace (e.g., "my-app", "org/repo", "host:/path"). */
141 > readonly label: string;
142 > /** Optional description shown alongside the label (e.g., parent folder path "~/work"). */
143 > readonly description?: string;
144 > /**
145 > * Optional group label for categorizing this workspace in pickers. The
146 > * workspace picker uses this to bucket entries into top-level tabs
147 > * (e.g. `"Local"`, `"Cloud"`, `"Remote"`). Providers contribute the
148 > * label — the picker just renders whatever values are present.
149 > */
150 > readonly group?: string;
151 > /** Icon for the workspace. */
152 > readonly icon: ThemeIcon;
153 > /** Folders in this session workspace. */
154 > readonly folders: ISessionFolder[];
155 > /** Whether the session requires workspace trust to operate. */
156 > readonly requiresWorkspaceTrust: boolean;
157 > /**
158 > * Whether this workspace is a virtual
159 > */
160 > readonly isVirtualWorkspace: boolean;
161 > }
162 >
163 > /**
164 > * GitHub information associated with a session.
165 > */
166 > export interface IGitHubInfo {
167 > /** GitHub repository owner. */
168 > readonly owner: string;
169 > /** GitHub repository name. */
170 > readonly repo: string;
171 > /** Pull request associated with this session, if any. */
172 > readonly pullRequest?: {
173 > /** Pull request number. */
174 > readonly number: number;
175 > /** URI of the pull request. */
176 > readonly uri: URI;
177 > /** Icon reflecting the PR state. */
178 > readonly icon?: ThemeIcon;
179 > /** Object ID of the base ref (merge target) commit. */
180 > readonly baseRefOid?: string;
181 > /** Object ID of the head ref (PR branch) commit. */
182 > readonly headRefOid?: string;
183 > };
184 > }
185 >
186 > export interface ISessionChangesSummary {
187 > readonly files: number;
188 > readonly additions: number;
189 > readonly deletions: number;
190 > }
191 >
192 > export type ISessionFileChange = IChatSessionFileChange | IChatSessionFileChange2;
193 >
194 > /**
195 > * The kind of change applied to a {@link ISessionFile}.
196 > *
197 > * A file that is first created and then edited during the session is reported
198 > * as {@link Created}. A file that is deleted is reported as {@link Deleted}
199 > * regardless of any earlier creation or edit.
200 > */
201 > export const enum SessionFileOperation {
202 > /** The file was created during the session (and possibly edited afterwards). */
203 > Created = 'created',
204 > /** The file existed before the session and was modified during it. */
205 > Modified = 'modified',
206 > /** The file was deleted during the session. */
207 > Deleted = 'deleted',
208 > }
209 >
210 > /**
211 > * A file that was created, edited or deleted **outside** the session workspace
212 > * folders during the session. These are surfaced separately from
213 > * {@link ISession.changes} because they are not part of the workspace and will
214 > * not be committed.
215 > */
216 > export interface ISessionFile {
217 > /** The file URI (after-state for create/modify, the deleted path for delete). */
218 > readonly uri: URI;
219 > /** The kind of change applied to the file during the session. */
220 > readonly operation: SessionFileOperation;
221 > /**
222 > * URI from which the file's pre-session content can be read, when known.
223 > * Used to render a diff for {@link SessionFileOperation.Modified} files.
224 > */
225 > readonly originalUri?: URI;
226 > }
227 >
228 > /**
229 > * Well-known id of the changeset that holds the diff between a session's branch
230 > * and its base (e.g. `main...feature`). Shared so that consumers which always
231 > * want the branch diff — regardless of the changeset currently selected in the
232 > * Changes view — can locate it in {@link ISession.changesets} by id.
233 > */
234 > export const BRANCH_CHANGES_CHANGESET_ID = 'branchChanges';
235 >
236 > /**
237 > * Well-known id of the changeset that holds the diff made during the session's
238 > * **last turn** only (as opposed to the cumulative session diff). Consumers that
239 > * want to reflect just the most recent turn — e.g. the chat input status pills —
240 > * can locate it in {@link ISession.changesets} by id.
241 > *
242 > * Must match the agent host provider's `ChangesetKind.Turn` value.
243 > */
244 > export const TURN_CHANGES_CHANGESET_ID = 'turn';
245 >
246 > export interface ISessionChangeset {
247 > /** Unique identifier for the changeset. */
248 > readonly id: string;
249 > /** Display label for the changeset. */
250 > readonly label: string;
251 > /** Optional description for the changeset. */
252 > readonly description?: string;
253 > /** Optional category for the changeset. */
254 > readonly category?: string;
255 > /** Whether the changeset is enabled. */
256 > readonly isEnabled: IObservable<boolean>;
257 > /**
258 > * Whether this changeset should be selected by default when the UI
259 > * switches to its session. May change with session state (e.g. an
260 > * archived session may default to a snapshot changeset rather than a
261 > * live one). Producers should ensure at most one changeset in a
262 > * session reports `true` at any time.
263 > */
264 > readonly isDefault: IObservable<boolean>;
265 > /**
266 > * Whether this changeset is currently loading its file changes.
267 > */
268 > readonly isLoadingChanges: IObservable<boolean>;
269 > /** Observable for the file changes in this changeset. */
270 > readonly changes: IObservable<readonly ISessionFileChange[]>;
271 > /** Observable for the operations in this changeset. */
272 > readonly operations: IObservable<readonly ISessionChangesetOperation[]>;
273 > /** Reference to the original checkpoint for this changeset. */
274 > readonly originalCheckpointRef: IObservable<string | undefined>;
275 > /** Reference to the modified checkpoint for this changeset. */
276 > readonly modifiedCheckpointRef: IObservable<string | undefined>;
277 > /** The capabilities of this changeset. */
278 > readonly capabilities?: ISessionChangesetCapabilities;
279 >
280 > /**
281 > * Invoke an operation declared in {@link operations}. `target` must be
282 > * provided for resource-scoped operations and omitted for changeset-
283 > * scoped ones — implementations are expected to validate this against
284 > * the corresponding {@link ISessionChangesetOperation.scopes}.
285 > */
286 > invokeOperation(operationId: string, target?: ISessionChangesetOperationTarget): Promise<void>;
287 >
288 > /**
289 > * Sets the review state for a list of resources when the changeset supports review.
290 > */
291 > setReviewState?(resources: readonly URI[], reviewed: boolean): void;
292 > }
293 >
294 > export type ISessionChangesetOperationTarget =
295 > | { readonly kind: 'resource'; readonly resource: URI };
296 >
297 > export const enum SessionChangesetOperationScope {
298 > Changeset = 'changeset',
299 > Resource = 'resource',
300 > Range = 'range',
301 > }
302 >
303 > /**
304 > * Execution status of a changeset operation.
305 > */
306 > export const enum SessionChangesetOperationStatus {
307 > /** The operation is ready to be invoked. */
308 > Idle = 'idle',
309 > /** An invocation is currently in flight. */
310 > Running = 'running',
311 > /** The most recent invocation failed. */
312 > Error = 'error',
313 > /** The operation is currently disabled and cannot be invoked. */
314 > Disabled = 'disabled',
315 > }
316 >
317 > export interface ISessionChangesetOperation {
318 > /** Unique identifier for the operation. */
319 > readonly id: string;
320 > /** Display label for the operation. */
321 > readonly label: string;
322 > /** Optional description for the operation. */
323 > readonly description?: string;
324 > /** Optional icon for the operation. */
325 > readonly icon?: ThemeIcon;
326 > /** Optional group identifier, used to group related operations together. */
327 > readonly group?: string;
328 > /** The scopes to which this operation applies. */
329 > readonly scopes: SessionChangesetOperationScope[];
330 > /** Current execution status for this operation. */
331 > readonly status: SessionChangesetOperationStatus;
332 > /**
333 > * Optional confirmation prompt to display before invoking the operation.
334 > * When present, callers MUST show this message to the user (typically in
335 > * a confirmation dialog) and only invoke the operation after the user
336 > * accepts. The presence of this field also signals that the operation
337 > * is destructive — callers SHOULD style the affirmative button
338 > * accordingly. The message may contain `{0}` which will be substituted
339 > * with the target resource's basename when applicable.
340 > */
341 > readonly confirmation?: string | IMarkdownString;
342 > }
343 >
344 > export interface ISessionChangesetCapabilities {
345 > /** Whether the changeset supports review workflow. */
346 > readonly review?: boolean;
347 > }
348 >
349 > /**
350 > * A custom agent reference used by session-level selection. Mirrors the Agent
351 > * Host protocol's `AgentSelection` shape but lives in the sessions layer so the
352 > * sessions service API does not leak the protocol type to non-Agent-Host
353 > * consumers.
354 > */
355 > export interface ISessionAgentRef {
356 > /** Stable agent URI (matches the contributing customization's agent ref). */
357 > readonly uri: string;
358 > /** Agent name. */
359 > readonly name: string;
360 > }
361 >
362 > export interface IChatCheckpoints {
363 > /** Reference to the first checkpoint in the chat. */
364 > readonly firstCheckpointRef: string;
365 > /** Reference to the last checkpoint in the chat. */
366 > readonly lastCheckpointRef: string;
367 > }
368 >
369 > export const enum ChatOriginKind {
370 > Tool = 'tool',
371 > User = 'user',
372 > Fork = 'fork',
373 > SideChat = 'sideChat',
374 > }
375 >
376 > export interface ISideChatSelection {
377 > readonly text: string;
378 > readonly responsePartId?: string;
379 > }
380 >
381 > export interface IChatOrigin {
382 > readonly kind: ChatOriginKind;
383 > /**
384 > * For a chat spawned by another chat (e.g. a subagent worker chat, kind
385 > * {@link ChatOriginKind.Tool}, or a {@link ChatOriginKind.Fork}), the
386 > * resource of the chat that spawned it. Undefined for user-originated chats.
387 > */
388 > readonly parentChat?: URI;
389 > readonly selection?: ISideChatSelection;
390 > }
391 >
392 > /**
393 > * Per-chat capabilities. Consumers gate chat-management UI (rename, delete) on
394 > * these flags rather than on the chat's origin/provider, so the affordances are
395 > * offered exactly where the backing chat supports them. A worker (subagent)
396 > * chat, for example, is neither renameable nor deletable.
397 > */
398 > export interface IChatCapabilities {
399 > /** Whether this chat's title can be renamed. */
400 > readonly canRename: boolean;
401 > /** Whether this chat can be permanently deleted. */
402 > readonly canDelete: boolean;
403 > }
404 >
405 > /** Capabilities assumed for a chat that does not advertise its own. */
406 > export const DEFAULT_CHAT_CAPABILITIES: IChatCapabilities = { canRename: true, canDelete: true };
407 >
408 > /**
409 > * A single chat within a session, produced by the sessions management layer.
410 > */
411 > export interface IChat {
412 > /** Resource URI identifying this chat. */
413 > readonly resource: URI;
414 > /** When the chat was created. */
415 > readonly createdAt: Date;
416 >
417 > // Reactive properties
418 >
419 > /** Chat display title (changes when auto-titled or renamed). */
420 > readonly title: IObservable<string>;
421 > /** When the chat was last updated. */
422 > readonly updatedAt: IObservable<Date>;
423 > /** Current chat status. */
424 > readonly status: IObservable<SessionStatus>;
425 > /** File changes produced by the chat. */
426 > readonly changes: IObservable<readonly ISessionFileChange[]>;
427 > /**
428 > * File changes produced by the chat's **last turn** only (as opposed to the
429 > * cumulative chat {@link changes}). Derived from the chat's live output
430 > * stream so consumers — e.g. the chat input status pills — can reflect just
431 > * what the most recent request produced. Providers that cannot determine
432 > * this omit the observable.
433 > */
434 > readonly lastTurnChanges?: IObservable<readonly ISessionFileChange[]>;
435 > /** Checkpoints associated with the chat. */
436 > readonly checkpoints: IObservable<IChatCheckpoints | undefined>;
437 > /** Currently selected model identifier. */
438 > readonly modelId: IObservable<string | undefined>;
439 > /** Currently selected mode identifier and kind. */
440 > readonly mode: IObservable<{ readonly id: string; readonly kind: string } | undefined>;
441 > /** Whether the chat is archived. */
442 > readonly isArchived: IObservable<boolean>;
443 > /** Whether the chat has been read. */
444 > readonly isRead: IObservable<boolean>;
445 > /**
446 > * Whether and how the user can interact with this chat. Providers that do
447 > * not distinguish read-only chats report {@link ChatInteractivity.Full}.
448 > *
449 > * - {@link ChatInteractivity.Full}: the user can send messages (default).
450 > * - {@link ChatInteractivity.ReadOnly}: the chat is shown but the composer is
451 > * hidden (e.g. an agent-team worker chat the user can watch but not steer).
452 > * - {@link ChatInteractivity.Hidden}: the chat is an internal worker that
453 > * should not be surfaced in the UI at all; the visible session model filters
454 > * these out of the tab strip and never makes them the active chat.
455 > */
456 > readonly interactivity: IObservable<ChatInteractivity>;
457 > /** Status description shown while the chat is active (e.g., current agent action). */
458 > readonly description: IObservable<IMarkdownString | undefined>;
459 > /** Timestamp of when the last agent turn ended, if any. */
460 > readonly lastTurnEnd: IObservable<Date | undefined>;
461 > /** How the chat came into existence, if provided by the backend. */
462 > readonly origin?: IChatOrigin;
463 > /**
464 > * Capabilities of this chat (rename/delete). Absent means the chat inherits
465 > * {@link DEFAULT_CHAT_CAPABILITIES} (fully capable); read via
466 > * {@link getChatCapabilities}.
467 > */
468 > readonly capabilities?: IObservable<IChatCapabilities>;
469 > }
470 >
471 > /**
472 > * Resolve a chat's effective capabilities. Combines the chat's own advertised
473 > * {@link IChat.capabilities} (falling back to {@link DEFAULT_CHAT_CAPABILITIES})
474 > * with the session-level invariant that a session's main chat can never be
475 > * deleted — it lives and dies with the session. Pass the owning session so the
476 > * main-chat rule applies; omit it to read only the chat's own capabilities.
477 > */
478 > export function getChatCapabilities(chat: IChat, session: ISession | undefined, reader: IReader | undefined): IChatCapabilities {
479 const own = chat.capabilities?.read(reader) ?? DEFAULT_CHAT_CAPABILITIES;
480 if (session && isEqual(chat.resource, session.mainChat.read(reader).resource)) {
483 return own;
484 }
485 > session.ts
486 > /**
487 > * A session groups one or more chats together.
488 > * All {@link ISessionData} fields are propagated from the primary (first) chat.
489 > */
490 > export interface ISession {
491 > /** Globally unique session ID (`providerId:localId`). */
492 > readonly sessionId: string;
493 > /** Resource URI identifying this session. */
494 > readonly resource: URI;
495 > /** ID of the provider that owns this session. */
496 > readonly providerId: string;
497 > /** Session type ID (e.g., 'copilot-cli', 'copilot-cloud', 'local'). */
498 > readonly sessionType: string;
499 > /** Icon for this session. */
500 > readonly icon: ThemeIcon;
501 > /** When the session was created. */
502 > readonly createdAt: Date;
503 > /** Workspace this session operates on. */
504 > readonly workspace: IObservable<ISessionWorkspace | undefined>;
505 > /** Whether the session has a usable Git repository. Providers may refine this beyond workspace metadata. */
506 > readonly hasGitRepository?: IObservable<boolean>;
507 > /** Whether this is a workspace-less "quick chat". Only quick-chat-capable providers set this; absent means `false`. */
508 > readonly isQuickChat?: IObservable<boolean>;
509 >
510 > // Reactive properties
511 >
512 > /** Session display title (changes when auto-titled or renamed). */
513 > readonly title: IObservable<string>;
514 > /** When the session was last updated. */
515 > readonly updatedAt: IObservable<Date>;
516 > /** Current session status. */
517 > readonly status: IObservable<SessionStatus>;
518 > /** Summary of file changes produced by the session. */
519 > readonly changesSummary?: IObservable<ISessionChangesSummary | undefined>;
520 > /** File changes produced by the session. */
521 > readonly changes: IObservable<readonly ISessionFileChange[]>;
522 > /** Changesets produced by the session. */
523 > readonly changesets: IObservable<readonly ISessionChangeset[] | undefined>;
524 > /**
525 > * Files created, edited or deleted **outside** the session workspace folders
526 > * during the session (e.g. config files in the user's home directory). These
527 > * are not part of {@link changes} and will not be committed. Providers that
528 > * cannot determine this report an empty array (or omit the observable).
529 > */
530 > readonly externalChanges?: IObservable<readonly ISessionFile[]>;
531 > /** Currently selected model identifier. */
532 > readonly modelId: IObservable<string | undefined>;
533 > readonly mode: IObservable<{ readonly id: string; readonly kind: string } | undefined>;
534 > /** Whether the session is still initializing (e.g., resolving git repository). */
535 > readonly loading: IObservable<boolean>;
536 > /** Whether the session is archived. */
537 > readonly isArchived: IObservable<boolean>;
538 > /** Whether the session has been read. */
539 > readonly isRead: IObservable<boolean>;
540 > /** Status description shown while the session is active (e.g., current agent action). */
541 > readonly description: IObservable<IMarkdownString | undefined>;
542 > /** Timestamp of when the last agent turn ended, if any. */
543 > readonly lastTurnEnd: IObservable<Date | undefined>;
544 > /** The chats belonging to this session group. */
545 > readonly chats: IObservable<readonly IChat[]>;
546 > /** The main (first) chat of this session. Providers may replace it for a new session via {@link ISessionsProvider.createNewChat}. */
547 > readonly mainChat: IObservable<IChat>;
548 > /**
549 > * Capabilities of this session. Observable so consumers (context keys, chat
550 > * catalog) react when a provider's advertised capabilities hydrate or change
551 > * after the session is first surfaced (e.g. an agent host whose root state
552 > * arrives after the session's first state update).
553 > */
554 > readonly capabilities: IObservable<ISessionCapabilities>;
555 > }
556 >
557 > /**
558 > * Build the canonical {@link ISession.sessionId} from a provider id and
559 > * session resource URI.
560 > *
561 > * This is the single source of truth for the `providerId:resourceUri`
562 > * string format used by every sessions provider (agent-host and
563 > * Copilot chat sessions). Consumers that only have a provider id and a
564 > * resource URI (e.g. a filesystem provider reconstructing a sessionId
565 > * from a synthetic URI) should call this rather than rebuilding the
566 > * string inline.
567 > */
568 > export function toSessionId(providerId: string, resource: URI): string {
569 return `${providerId}:${resource.toString()}`;
570 }
571 > session.ts
572 > /**
573 > * Capabilities declared per session.
574 > * Consumers check these before surfacing session-specific features in the UI.
575 > */
576 > export interface ISessionCapabilities {
577 > /** Whether this session supports multiple chats. */
578 > readonly supportsMultipleChats: boolean;
579 > /**
580 > * Whether this session supports forking a chat from a turn into a new peer
581 > * chat. The agents-window fork gesture gates on this flag rather than on the
582 > * provider id, so fork is offered exactly where the backing agent supports
583 > * it. Defaults to falsy (no fork) when omitted.
584 > */
585 > readonly supportsFork?: boolean;
586 > /**
587 > * Whether this session supports creating a side chat from a turn (via
588 > * `/btw`). Side chats inherit the source chat's model/agent and are shown
589 > * as ordinary peer chats in the session's standard chat tabs. Defaults to
590 > * falsy (no side chat) when omitted.
591 > */
592 > readonly supportsSideChat?: boolean;
593 > /**
594 > * Whether this session's title can be renamed. The agents-window UI
595 > * (session header inline edit, sessions-list `Rename...` action) gates
596 > * editing on this flag rather than on the provider id, so that rename is
597 > * offered exactly where the backing provider actually supports it.
598 > * Defaults to falsy (not renameable) when omitted.
599 > */
600 > readonly supportsRename?: boolean;
601 > /**
602 > * Whether this session can be deleted. The agents-window sessions-list
603 > * `Delete...` action gates on this flag rather than on the provider id,
604 > * so delete is offered exactly where the backing provider supports it.
605 > * Defaults to falsy (not deletable) when omitted.
606 > */
607 > readonly supportsDelete?: boolean;
608 > /**
609 > * Whether the session's underlying runtime (e.g. a cloud agent host)
610 > * already runs `runOptions.runOn === 'worktreeCreated'` tasks during
611 > * environment provisioning. When `true`, the agents-window
612 > * client-side dispatcher must NOT run those tasks itself to avoid
613 > * double-execution. Defaults to `false` for sessions backed by local
614 > * or remote agent hosts, where the client is the only thing that
615 > * could trigger them.
616 > */
617 > readonly runsWorktreeCreatedTasks?: boolean;
618 > }
619 >
620 > /**
621 > * Well-known workspace group labels used by the workspace picker to bucket
622 > * recents and browse actions into top-level tabs. Providers contribute one
623 > * of these (or any custom string) on each `ISessionWorkspace` and
624 > * `ISessionWorkspaceBrowseAction`; the picker discovers tabs from the union
625 > * of contributed values.
626 > */
627 > export const SESSION_WORKSPACE_GROUP_LOCAL = localize('sessionWorkspaceGroup.local', "Local");
628 > export const SESSION_WORKSPACE_GROUP_REMOTE = localize('sessionWorkspaceGroup.remote', "Remote");
629 >
630 > /**
631 > * The fallback title for an untitled session: "New Chat" for a quick chat,
632 > * otherwise "New Session". Callers pass the boolean so they control how they
633 > * read `isQuickChat` (reader-tracked vs `.get()`).
634 > */
635 > export function getUntitledSessionTitle(isQuickChat: boolean): string {
636 return isQuickChat
637 ? localize('agentSessions.newChat', "New Chat")
638 : localize('agentSessions.newSession', "New Session");
639 }
640 > session.ts
641 > export interface ISessionWorkspaceBrowseAction {
642 > /** Display label for the browse action. */
643 > readonly label: string;
644 > /** Optional description shown alongside the label in the workspace picker. */
645 > readonly description?: string;
646 > /**
647 > * Optional group label used by the workspace picker to bucket browse
648 > * actions into top-level tabs (e.g. `"Local"`, `"Cloud"`, `"Remote"`).
649 > * Providers contribute the label — the picker dynamically renders tabs
650 > * for whichever values are present and filters items accordingly.
651 > */
652 > readonly group?: string;
653 > /** Icon for the browse action. */
654 > readonly icon: ThemeIcon;
655 > /** The provider that owns this action. */
656 > readonly providerId: string;
657 > /** Execute the browse action and return the selected workspace, or undefined if cancelled. */
658 > run(): Promise<ISessionWorkspace | undefined>;
659 > /**
660 > * Optional method to enumerate folders inline (e.g. for a phone-friendly
661 > * picker that shows a folder list with search-as-you-type instead of
662 > * opening a separate file dialog). Implementations should respect the
663 > * cancellation token so stale queries can be aborted as the user types.
664 > *
665 > * @param query Case-insensitive substring filter (empty string returns the default set).
666 > * @param token Cancellation token; the implementation should resolve with
667 > * a partial result or empty array once cancelled.
668 > */
669 > listFolders?(query: string, token: CancellationToken): Promise<readonly ISessionWorkspace[]>;
670 > }
671 >
672 > /**
673 > * Structural equality for arrays of {@link ISessionFileChange}. Used as an
674 > * `equalsFn` on the `changes` observables so that providers can re-publish a
675 > * freshly-built array without notifying observers when the underlying file
676 > * changes have not actually changed.
677 > */
678 > export function sessionFileChangesEqual(a: readonly ISessionFileChange[], b: readonly ISessionFileChange[]): boolean {
679 > if (a === b) { session.ts
680 return true;
681 }
682 > session.ts
683 > if (a.length !== b.length) {
684 return false;
685 }
686 > session.ts
687 > for (let i = 0; i < a.length; i++) {
688 > const x = a[i], y = b[i]; session.ts
689 > if (x === y) {
690 continue;
691 }
692 > session.ts
693 > if (x.insertions !== y.insertions || x.deletions !== y.deletions) { session.ts
694 return false;
695 }
696 > session.ts
697 > const xIsIChatSessionFileChange2 = isIChatSessionFileChange2(x);
698 > const yIsIChatSessionFileChange2 = isIChatSessionFileChange2(y);
699 > if (xIsIChatSessionFileChange2 !== yIsIChatSessionFileChange2) {
700 > return false; session.ts
701 > }
702
703 > const xUri = xIsIChatSessionFileChange2 ? x.uri : x.modifiedUri; session.ts
704 > const yUri = yIsIChatSessionFileChange2 ? y.uri : y.modifiedUri;
705 > if (!isEqual(xUri, yUri)) {
706 return false;
707 }
708
709 > const xModified = xIsIChatSessionFileChange2 ? x.modifiedUri : undefined; session.ts
710 > const yModified = yIsIChatSessionFileChange2 ? y.modifiedUri : undefined;
711 > if (!isEqual(xModified, yModified)) {
712 return false;
713 }
720 return false;
721 }
722 > } session.ts
723
724 return true;
725 }
726 > session.ts
727 > /**
728 > * Structural equality for {@link IGitHubInfo}. Used as an `equalsFn` on the `gitHubInfo` observable
729 > * so that providers can re-publish updated info without notifying observers when the underlying GitHub
730 > * info has not actually changed.
731 > */
732 > export function gitHubInfoEqual(a: IGitHubInfo | undefined, b: IGitHubInfo | undefined): boolean {
733 if (a === b) {
734 return true;
750 a.pullRequest?.headRefOid === b.pullRequest?.headRefOid;
751 }
752 > session.ts
753 > /**
754 > * Structural equality for {@link ISessionWorkspace}.
755 > */
756 > export function sessionWorkspaceEqual(a: ISessionWorkspace | undefined, b: ISessionWorkspace | undefined): boolean {
757 if (a === b) {
758 return true;
776 return true;
777 }
778 > session.ts
779 > /**
780 > * Structural equality for {@link ISessionFolder}.
781 > */
782 > export function sessionFolderEqual(a: ISessionFolder, b: ISessionFolder): boolean {
783 return isEqual(a.root, b.root)
784 && isEqual(a.workingDirectory, b.workingDirectory)
787 && sessionGitRepositoryEqual(a.gitRepository, b.gitRepository);
788 }
789 > session.ts
790 > /**
791 > * Structural equality for {@link ISessionGitRepository}.
792 > */
793 > export function sessionGitRepositoryEqual(a: ISessionGitRepository | undefined, b: ISessionGitRepository | undefined): boolean {
794 if (a === b) {
795 return true;
src/vs/base/common/lifecycle.ts 479 covered LOC · 98 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lifecycle.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { compareBy, numberComparator } from './arrays.js';
7 > import { groupBy } from './collections.js';
8 > import { SetMap, ResourceMap } from './map.js';
9 > import { URI } from './uri.js';
10 > import { createSingleCallFunction } from './functional.js';
11 > import { Iterable } from './iterator.js';
12 > import { BugIndicatingError, onUnexpectedError } from './errors.js';
13 >
14 > // #region Disposable Tracking
15 >
16 > /**
17 > * Enables logging of potentially leaked disposables.
18 > *
19 > * A disposable is considered leaked if it is not disposed or not registered as the child of
20 > * another disposable. This tracking is very simple an only works for classes that either
21 > * extend Disposable or use a DisposableStore. This means there are a lot of false positives.
22 > */
23 > const TRACK_DISPOSABLES = false;
24 > let disposableTracker: IDisposableTracker | null = null;
25 >
26 > export interface IDisposableTracker {
27 > /**
28 > * Is called on construction of a disposable.
29 > */
30 > trackDisposable(disposable: IDisposable): void;
31 >
32 > /**
33 > * Is called when a disposable is registered as child of another disposable (e.g. {@link DisposableStore}).
34 > * If parent is `null`, the disposable is removed from its former parent.
35 > */
36 > setParent(child: IDisposable, parent: IDisposable | null): void;
37 >
38 > /**
39 > * Is called after a disposable is disposed.
40 > */
41 > markAsDisposed(disposable: IDisposable): void;
42 >
43 > /**
44 > * Indicates that the given object is a singleton which does not need to be disposed.
45 > */
46 > markAsSingleton(disposable: IDisposable): void;
47 > }
48 >
49 > export class GCBasedDisposableTracker implements IDisposableTracker {
50
51 private readonly _registry = new FinalizationRegistry<string>(heldValue => {
52 console.warn(`[LEAKED DISPOSABLE] ${heldValue}`);
53 });
55 > trackDisposable(disposable: IDisposable): void {
56 const stack = new Error('CREATED via:').stack!;
57 this._registry.register(disposable, stack, disposable);
58 }
60 > setParent(child: IDisposable, parent: IDisposable | null): void {
61 if (parent) {
62 this._registry.unregister(child);
65 }
66 }
68 > markAsDisposed(disposable: IDisposable): void {
69 this._registry.unregister(disposable);
70 }
72 > markAsSingleton(disposable: IDisposable): void {
73 this._registry.unregister(disposable);
74 }
75 > } lifecycle.ts
76 >
77 > export interface DisposableInfo {
78 > value: IDisposable;
79 > source: string | null;
80 > parent: IDisposable | null;
81 > isSingleton: boolean;
82 > idx: number;
83 > }
84 >
85 > export class DisposableTracker implements IDisposableTracker {
86 > private static idx = 0; lifecycle.ts
87 >
88 > private readonly livingDisposables = new Map<IDisposable, DisposableInfo>();
90 > private getDisposableData(d: IDisposable): DisposableInfo {
91 let val = this.livingDisposables.get(d);
92 if (!val) {
96 return val;
97 }
99 > trackDisposable(d: IDisposable): void {
100 const data = this.getDisposableData(d);
101 if (!data.source) {
104 }
105 }
106 > lifecycle.ts
107 > setParent(child: IDisposable, parent: IDisposable | null): void {
108 const data = this.getDisposableData(child);
109 data.parent = parent;
110 }
111 > lifecycle.ts
112 > markAsDisposed(x: IDisposable): void {
113 > this.livingDisposables.delete(x); lifecycle.ts
114 > }
115 > lifecycle.ts
116 > markAsSingleton(disposable: IDisposable): void {
117 this.getDisposableData(disposable).isSingleton = true;
118 }
119 > lifecycle.ts
120 > private getRootParent(data: DisposableInfo, cache: Map<DisposableInfo, DisposableInfo>): DisposableInfo {
121 const cacheValue = cache.get(data);
122 if (cacheValue) {
128 return result;
129 }
130 > lifecycle.ts
131 > getTrackedDisposables(): IDisposable[] {
132 const rootParentCache = new Map<DisposableInfo, DisposableInfo>();
133
138 return leaking;
139 }
140 > lifecycle.ts
141 > computeLeakingDisposables(maxReported = 10, preComputedLeaks?: DisposableInfo[]): { leaks: DisposableInfo[]; details: string } | undefined {
142 > let uncoveredLeakingObjs: DisposableInfo[] | undefined; lifecycle.ts
143 > if (preComputedLeaks) {
144 uncoveredLeakingObjs = preComputedLeaks;
145 > } else { lifecycle.ts
146 > const rootParentCache = new Map<DisposableInfo, DisposableInfo>();
147 >
148 > const leakingObjects = [...this.livingDisposables.values()]
149 > .filter((info) => info.source !== null && !this.getRootParent(info, rootParentCache).isSingleton);
150 >
151 > if (leakingObjects.length === 0) {
152 > return; lifecycle.ts
153 > }
154 const leakingObjsSet = new Set(leakingObjects.map(o => o.value));
155
162 throw new Error('There are cyclic diposable chains!');
163 }
164 > } lifecycle.ts
165
166 if (!uncoveredLeakingObjs) {
224
225 return { leaks: uncoveredLeakingObjs, details: message };
226 > } lifecycle.ts
227 > } lifecycle.ts
228 >
229 > export function setDisposableTracker(tracker: IDisposableTracker | null): void {
230 > disposableTracker = tracker; lifecycle.ts
231 > }
232 > lifecycle.ts
233 > if (TRACK_DISPOSABLES) {
234 const __is_disposable_tracked__ = '__is_disposable_tracked__';
235 setDisposableTracker(new class implements IDisposableTracker {
268 });
269 }
270 > lifecycle.ts
271 > export function trackDisposable<T extends IDisposable>(x: T): T {
272 > disposableTracker?.trackDisposable(x); lifecycle.ts
273 > return x;
274 > }
275 > lifecycle.ts
276 > export function markAsDisposed(disposable: IDisposable): void {
277 > disposableTracker?.markAsDisposed(disposable); lifecycle.ts
278 > }
279 > lifecycle.ts
280 function setParentOfDisposable(child: IDisposable, parent: IDisposable | null): void {
281 disposableTracker?.setParent(child, parent);
282 }
283 > lifecycle.ts
284 function setParentOfDisposables(children: IDisposable[], parent: IDisposable | null): void {
285 if (!disposableTracker) {
290 }
291 }
292 > lifecycle.ts
293 > /**
294 > * Indicates that the given object is a singleton which does not need to be disposed.
295 > */
296 > export function markAsSingleton<T extends IDisposable>(singleton: T): T {
297 disposableTracker?.markAsSingleton(singleton);
298 return singleton;
299 }
300 > lifecycle.ts
301 > // #endregion
302 >
303 > /**
304 > * An object that performs a cleanup operation when `.dispose()` is called.
305 > *
306 > * Some examples of how disposables are used:
307 > *
308 > * - An event listener that removes itself when `.dispose()` is called.
309 > * - A resource such as a file system watcher that cleans up the resource when `.dispose()` is called.
310 > * - The return value from registering a provider. When `.dispose()` is called, the provider is unregistered.
311 > */
312 > export interface IDisposable {
313 > dispose(): void;
314 > }
315 >
316 > /**
317 > * Check if `thing` is {@link IDisposable disposable}.
318 > */
319 > export function isDisposable<E>(thing: E): thing is E & IDisposable {
320 // eslint-disable-next-line local/code-no-any-casts
321 return typeof thing === 'object' && thing !== null && typeof (<IDisposable><any>thing).dispose === 'function' && (<IDisposable><any>thing).dispose.length === 0;
322 }
323 > lifecycle.ts
324 > /**
325 > * Disposes of the value(s) passed in.
326 > */
327 > export function dispose<T extends IDisposable>(disposable: T): T;
328 > export function dispose<T extends IDisposable>(disposable: T | undefined): T | undefined;
329 > export function dispose<T extends IDisposable, A extends Iterable<T> = Iterable<T>>(disposables: A): A;
330 > export function dispose<T extends IDisposable>(disposables: Array<T>): Array<T>;
331 > export function dispose<T extends IDisposable>(disposables: ReadonlyArray<T>): ReadonlyArray<T>;
332 > export function dispose<T extends IDisposable>(arg: T | Iterable<T> | undefined): any {
333 if (Iterable.is(arg)) {
334 const errors: any[] = [];
356 }
357 }
358 > lifecycle.ts
359 > export function disposeIfDisposable<T extends IDisposable | object>(disposables: Array<T>): Array<T> {
360 for (const d of disposables) {
361 if (isDisposable(d)) {
365 return [];
366 }
367 > lifecycle.ts
368 > /**
369 > * Combine multiple disposable values into a single {@link IDisposable}.
370 > */
371 > export function combinedDisposable(...disposables: IDisposable[]): IDisposable {
372 const parent = toDisposable(() => dispose(disposables));
373 setParentOfDisposables(disposables, parent);
374 return parent;
375 }
376 > lifecycle.ts
377 > class FunctionDisposable implements IDisposable {
378 > private _isDisposed: boolean;
379 > private readonly _fn: () => void;
380 >
381 > constructor(fn: () => void) {
382 this._isDisposed = false;
383 this._fn = fn;
384 trackDisposable(this);
385 }
386 > lifecycle.ts
387 > dispose() {
388 if (this._isDisposed) {
389 return;
396 this._fn();
397 }
398 > } lifecycle.ts
399 >
400 > /**
401 > * Turn a function that implements dispose into an {@link IDisposable}.
402 > *
403 > * @param fn Clean up function, guaranteed to be called only **once**.
404 > */
405 > export function toDisposable(fn: () => void): IDisposable {
406 return new FunctionDisposable(fn);
407 }
408 > lifecycle.ts
409 > /**
410 > * Manages a collection of disposable values.
411 > *
412 > * This is the preferred way to manage multiple disposables. A `DisposableStore` is safer to work with than an
413 > * `IDisposable[]` as it considers edge cases, such as registering the same value multiple times or adding an item to a
414 > * store that has already been disposed of.
415 > */
416 > export class DisposableStore implements IDisposable {
417 >
418 > static DISABLE_DISPOSED_WARNING = false;
419 >
420 > private readonly _toDispose = new Set<IDisposable>();
421 > private _isDisposed = false;
422 >
423 > constructor() {
424 > trackDisposable(this); lifecycle.ts
425 > }
426 > lifecycle.ts
427 > /**
428 > * Dispose of all registered disposables and mark this object as disposed.
429 > *
430 > * Any future disposables added to this object will be disposed of on `add`.
431 > */
432 > public dispose(): void {
433 > if (this._isDisposed) { lifecycle.ts
434 return;
435 }
436 > lifecycle.ts
437 > markAsDisposed(this);
438 > this._isDisposed = true;
439 > this.clear();
440 > }
441 > lifecycle.ts
442 > /**
443 > * @return `true` if this object has been disposed of.
444 > */
445 > public get isDisposed(): boolean {
446 return this._isDisposed;
447 }
448 > lifecycle.ts
449 > /**
450 > * Dispose of all registered disposables but do not mark this object as disposed.
451 > */
452 > public clear(): void {
453 > if (this._toDispose.size === 0) { lifecycle.ts
454 > return; lifecycle.ts
455 > }
456
457 try {
460 this._toDispose.clear();
461 }
462 > } lifecycle.ts
463 > lifecycle.ts
464 > /**
465 > * Add a new {@link IDisposable disposable} to the collection.
466 > */
467 > public add<T extends IDisposable>(o: T): T {
468 if (!o || o === Disposable.None) {
469 return o;
484 return o;
485 }
486 > lifecycle.ts
487 > /**
488 > * Deletes a disposable from store and disposes of it. This will not throw or warn and proceed to dispose the
489 > * disposable even when the disposable is not part in the store.
490 > */
491 > public delete<T extends IDisposable>(o: T): void {
492 if (!o) {
493 return;
499 o.dispose();
500 }
501 > lifecycle.ts
502 > /**
503 > * Deletes the value from the store, but does not dispose it.
504 > */
505 > public deleteAndLeak<T extends IDisposable>(o: T): void {
506 if (!o) {
507 return;
511 }
512 }
513 > lifecycle.ts
514 > public assertNotDisposed(): void {
515 if (this._isDisposed) {
516 onUnexpectedError(new BugIndicatingError('Object disposed'));
517 }
518 }
519 > } lifecycle.ts
520 >
521 > /**
522 > * Abstract base class for a {@link IDisposable disposable} object.
523 > *
524 > * Subclasses can {@linkcode _register} disposables that will be automatically cleaned up when this object is disposed of.
525 > */
526 > export abstract class Disposable implements IDisposable {
527 >
528 > /**
529 > * A disposable that does nothing when it is disposed of.
530 > *
531 > * TODO: This should not be a static property.
532 > */
533 > static readonly None = Object.freeze<IDisposable>({ dispose() { } });
534 >
535 > protected readonly _store = new DisposableStore();
536 >
537 > constructor() {
538 trackDisposable(this);
539 setParentOfDisposable(this._store, this);
540 }
541 > lifecycle.ts
542 > public dispose(): void {
543 markAsDisposed(this);
544
545 this._store.dispose();
546 }
547 > lifecycle.ts
548 > /**
549 > * Adds `o` to the collection of disposables managed by this object.
550 > */
551 > protected _register<T extends IDisposable>(o: T): T {
552 if ((o as unknown as Disposable) === this) {
553 throw new Error('Cannot register a disposable on itself!');
555 return this._store.add(o);
556 }
557 > } lifecycle.ts
558 >
559 > /**
560 > * Manages the lifecycle of a disposable value that may be changed.
561 > *
562 > * This ensures that when the disposable value is changed, the previously held disposable is disposed of. You can
563 > * also register a `MutableDisposable` on a `Disposable` to ensure it is automatically cleaned up.
564 > */
565 > export class MutableDisposable<T extends IDisposable> implements IDisposable {
566 > private _value?: T;
567 > private _isDisposed = false;
568 >
569 > constructor() {
570 trackDisposable(this);
571 }
572 > lifecycle.ts
573 > /**
574 > * Get the currently held disposable value, or `undefined` if this MutableDisposable has been disposed
575 > */
576 > get value(): T | undefined {
577 return this._isDisposed ? undefined : this._value;
578 }
579 > lifecycle.ts
580 > /**
581 > * Set a new disposable value.
582 > *
583 > * Behaviour:
584 > * - If the MutableDisposable has been disposed, the setter is a no-op.
585 > * - If the new value is strictly equal to the current value, the setter is a no-op.
586 > * - Otherwise the previous value (if any) is disposed and the new value is stored.
587 > *
588 > * Related helpers:
589 > * - clear() resets the value to `undefined` (and disposes the previous value).
590 > * - clearAndLeak() returns the old value without disposing it and removes its parent.
591 > */
592 > set value(value: T | undefined) {
593 if (this._isDisposed || value === this._value) {
594 return;
601 this._value = value;
602 }
603 > lifecycle.ts
604 > /**
605 > * Resets the stored value and disposed of the previously stored value.
606 > */
607 > clear(): void {
608 this.value = undefined;
609 }
610 > lifecycle.ts
611 > dispose(): void {
612 this._isDisposed = true;
613 markAsDisposed(this);
615 this._value = undefined;
616 }
617 > lifecycle.ts
618 > /**
619 > * Clears the value, but does not dispose it.
620 > * The old value is returned.
621 > */
622 > clearAndLeak(): T | undefined {
623 const oldValue = this._value;
624 this._value = undefined;
628 return oldValue;
629 }
630 > } lifecycle.ts
631 >
632 > /**
633 > * Manages the lifecycle of a disposable value that may be changed like {@link MutableDisposable}, but the value must
634 > * exist and cannot be undefined.
635 > */
636 > export class MandatoryMutableDisposable<T extends IDisposable> implements IDisposable {
637 > private readonly _disposable = new MutableDisposable<T>();
638 > private _isDisposed = false;
639 >
640 > constructor(initialValue: T) {
641 this._disposable.value = initialValue;
642 }
643 > lifecycle.ts
644 > get value(): T {
645 return this._disposable.value!;
646 }
647 > lifecycle.ts
648 > set value(value: T) {
649 if (this._isDisposed || value === this._disposable.value) {
650 return;
652 this._disposable.value = value;
653 }
654 > lifecycle.ts
655 > dispose() {
656 this._isDisposed = true;
657 this._disposable.dispose();
658 }
659 > } lifecycle.ts
660 >
661 > export class RefCountedDisposable {
662 >
663 > private _counter: number = 1;
664 >
665 > constructor(
666 private readonly _disposable: IDisposable,
667 ) { }
668 > lifecycle.ts
669 > acquire() {
670 this._counter++;
671 return this;
672 }
673 > lifecycle.ts
674 > release() {
675 if (--this._counter === 0) {
676 this._disposable.dispose();
678 return this;
679 }
680 > } lifecycle.ts
681 >
682 > export interface IReference<T> extends IDisposable {
683 > readonly object: T;
684 > }
685 >
686 > export abstract class ReferenceCollection<T> {
687
688 private readonly references: Map<string, { readonly object: T; counter: number }> = new Map();
689 > lifecycle.ts
690 > acquire(key: string, ...args: unknown[]): IReference<T> {
691 let reference = this.references.get(key);
692
708 return { object, dispose };
709 }
710 > lifecycle.ts
711 > protected abstract createReferencedObject(key: string, ...args: unknown[]): T;
712 > protected abstract destroyReferencedObject(key: string, object: T): void;
713 > }
714 >
715 > /**
716 > * Unwraps a reference collection of promised values. Makes sure
717 > * references are disposed whenever promises get rejected.
718 > */
719 > export class AsyncReferenceCollection<T> {
720 >
721 > constructor(private referenceCollection: ReferenceCollection<Promise<T>>) { }
722 >
723 > async acquire(key: string, ...args: unknown[]): Promise<IReference<T>> {
724 const ref = this.referenceCollection.acquire(key, ...args);
725
736 }
737 }
738 > } lifecycle.ts
739 >
740 > export class ImmortalReference<T> implements IReference<T> {
741 > constructor(public object: T) { }
742 > dispose(): void { /* noop */ }
743 > }
744 >
745 > export function disposeOnReturn(fn: (store: DisposableStore) => void): void {
746 const store = new DisposableStore();
747 try {
751 }
752 }
753 > lifecycle.ts
754 > /**
755 > * A map the manages the lifecycle of the values that it stores.
756 > */
757 > export class DisposableMap<K, V extends IDisposable = IDisposable> implements IDisposable {
758 >
759 > private readonly _store: Map<K, V>;
760 > private _isDisposed = false;
761 >
762 > constructor(store: Map<K, V> = new Map<K, V>()) {
763 this._store = store;
764 trackDisposable(this);
765 }
766 > lifecycle.ts
767 > /**
768 > * Disposes of all stored values and mark this object as disposed.
769 > *
770 > * Trying to use this object after it has been disposed of is an error.
771 > */
772 > dispose(): void {
773 markAsDisposed(this);
774 this._isDisposed = true;
775 this.clearAndDisposeAll();
776 }
777 > lifecycle.ts
778 > /**
779 > * Disposes of all stored values and clear the map, but DO NOT mark this object as disposed.
780 > */
781 > clearAndDisposeAll(): void {
782 if (!this._store.size) {
783 return;
790 }
791 }
792 > lifecycle.ts
793 > has(key: K): boolean {
794 return this._store.has(key);
795 }
796 > lifecycle.ts
797 > get size(): number {
798 return this._store.size;
799 }
800 > lifecycle.ts
801 > get(key: K): V | undefined {
802 return this._store.get(key);
803 }
804 > lifecycle.ts
805 > set(key: K, value: V, skipDisposeOnOverwrite = false): void {
806 if (this._isDisposed) {
807 console.warn(new Error('Trying to add a disposable to a DisposableMap that has already been disposed of. The added object will be leaked!').stack);
815 setParentOfDisposable(value, this);
816 }
817 > lifecycle.ts
818 > /**
819 > * Delete the value stored for `key` from this map and also dispose of it.
820 > */
821 > deleteAndDispose(key: K): void {
822 this._store.get(key)?.dispose();
823 this._store.delete(key);
824 }
825 > lifecycle.ts
826 > /**
827 > * Delete the value stored for `key` from this map but return it. The caller is
828 > * responsible for disposing of the value.
829 > */
830 > deleteAndLeak(key: K): V | undefined {
831 const value = this._store.get(key);
832 if (value) {
836 return value;
837 }
838 > lifecycle.ts
839 > keys(): IterableIterator<K> {
840 return this._store.keys();
841 }
842 > lifecycle.ts
843 > values(): IterableIterator<V> {
844 return this._store.values();
845 }
846 > lifecycle.ts
847 > [Symbol.iterator](): IterableIterator<[K, V]> {
848 return this._store[Symbol.iterator]();
849 }
850 > } lifecycle.ts
851 >
852 > /**
853 > * A set that manages the lifecycle of the values that it stores.
854 > */
855 > export class DisposableSet<V extends IDisposable = IDisposable> implements IDisposable {
856 >
857 > private readonly _store: Set<V>;
858 > private _isDisposed = false;
859 >
860 > constructor(store: Set<V> = new Set<V>()) {
861 this._store = store;
862 trackDisposable(this);
863 }
864 > lifecycle.ts
865 > /**
866 > * Disposes of all stored values and mark this object as disposed.
867 > *
868 > * Trying to use this object after it has been disposed of is an error.
869 > */
870 > dispose(): void {
871 markAsDisposed(this);
872 this._isDisposed = true;
873 this.clearAndDisposeAll();
874 }
875 > lifecycle.ts
876 > /**
877 > * Disposes of all stored values and clear the set, but DO NOT mark this object as disposed.
878 > */
879 > clearAndDisposeAll(): void {
880 if (!this._store.size) {
881 return;
888 }
889 }
890 > lifecycle.ts
891 > has(value: V): boolean {
892 return this._store.has(value);
893 }
894 > lifecycle.ts
895 > get size(): number {
896 return this._store.size;
897 }
898 > lifecycle.ts
899 > add(value: V): void {
900 if (this._isDisposed) {
901 console.warn(new Error('Trying to add a disposable to a DisposableSet that has already been disposed of. The added object will be leaked!').stack);
905 setParentOfDisposable(value, this);
906 }
907 > lifecycle.ts
908 > /**
909 > * Delete the value from this set and also dispose of it.
910 > */
911 > deleteAndDispose(value: V): void {
912 if (this._store.delete(value)) {
913 value.dispose();
914 }
915 }
916 > lifecycle.ts
917 > /**
918 > * Delete the value from this set but return it. The caller is
919 > * responsible for disposing of the value.
920 > */
921 > deleteAndLeak(value: V): V | undefined {
922 if (this._store.delete(value)) {
923 setParentOfDisposable(value, null);
926 return undefined;
927 }
928 > lifecycle.ts
929 > values(): IterableIterator<V> {
930 return this._store.values();
931 }
932 > lifecycle.ts
933 > [Symbol.iterator](): IterableIterator<V> {
934 return this._store[Symbol.iterator]();
935 }
936 > } lifecycle.ts
937 >
938 > /**
939 > * Call `then` on a Promise, unless the returned disposable is disposed.
940 > */
941 > export function thenIfNotDisposed<T>(promise: Promise<T>, then: (result: T) => void): IDisposable {
942 let disposed = false;
943 promise.then(result => {
951 });
952 }
953 > lifecycle.ts
954 > /**
955 > * Call `then` on a promise that resolves to a {@link IDisposable}, then either register the
956 > * disposable or register it to the {@link DisposableStore}, depending on whether the store is
957 > * disposed or not.
958 > */
959 > export function thenRegisterOrDispose<T extends IDisposable>(promise: Promise<T>, store: DisposableStore): Promise<T> {
960 return promise.then(disposable => {
961 if (store.isDisposed) {
967 });
968 }
969 > lifecycle.ts
970 > export class DisposableResourceMap<V extends IDisposable = IDisposable> extends DisposableMap<URI, V> {
971 > constructor() {
972 super(new ResourceMap());
973 }
974 > } lifecycle.ts
src/vs/base/common/strings.ts 454 covered LOC · 101 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- strings.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { LRUCachedFunction } from './cache.js';
7 > import { CharCode } from './charCode.js';
8 > import { Lazy } from './lazy.js';
9 > import { Constants } from './uint.js';
10 >
11 > export function isFalsyOrWhitespace(str: string | undefined): boolean {
12 if (!str || typeof str !== 'string') {
13 return true;
15 return str.trim().length === 0;
16 }
17 > strings.ts
18 > const _formatRegexp = /{(\d+)}/g;
19 >
20 > /**
21 > * Helper to produce a string with a variable number of arguments. Insert variable segments
22 > * into the string using the {n} notation where N is the index of the argument following the string.
23 > * @param value string to which formatting is applied
24 > * @param args replacements for {n}-entries
25 > */
26 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
27 > export function format(value: string, ...args: any[]): string {
28 if (args.length === 0) {
29 return value;
36 });
37 }
38 > strings.ts
39 > const _format2Regexp = /{([^}]+)}/g;
40 >
41 > /**
42 > * Helper to create a string from a template and a string record.
43 > * Similar to `format` but with objects instead of positional arguments.
44 > */
45 > export function format2(template: string, values: Record<string, unknown>): string {
46 if (Object.keys(values).length === 0) {
47 return template;
49 return template.replace(_format2Regexp, (match, group) => (values[group] ?? match) as string);
50 }
51 > strings.ts
52 > /**
53 > * Encodes the given value so that it can be used as literal value in html attributes.
54 > *
55 > * In other words, computes `$val`, such that `attr` in `<div attr="$val" />` has the runtime value `value`.
56 > * This prevents XSS injection.
57 > */
58 > export function htmlAttributeEncodeValue(value: string): string {
59 return value.replace(/[<>"'&]/g, ch => {
60 switch (ch) {
68 });
69 }
70 > strings.ts
71 > /**
72 > * Converts HTML characters inside the string to use entities instead. Makes the string safe from
73 > * being used e.g. in HTMLElement.innerHTML.
74 > */
75 > export function escape(html: string): string {
76 return html.replace(/[<>&]/g, function (match) {
77 switch (match) {
83 });
84 }
85 > strings.ts
86 > /**
87 > * Escapes regular expression characters in a given string
88 > */
89 > export function escapeRegExpCharacters(value: string): string {
90 return value.replace(/[\\\{\}\*\+\?\|\^\$\.\[\]\(\)]/g, '\\$&');
91 }
92 > strings.ts
93 > /**
94 > * Counts how often `substr` occurs inside `value`.
95 > */
96 > export function count(value: string, substr: string): number {
97 let result = 0;
98 let index = value.indexOf(substr);
103 return result;
104 }
105 > strings.ts
106 > export function truncate(value: string, maxLength: number, suffix = Ellipsis): string {
107 if (value.length <= maxLength) {
108 return value;
111 return `${value.substr(0, maxLength)}${suffix}`;
112 }
113 > strings.ts
114 > export function truncateMiddle(value: string, maxLength: number, suffix = Ellipsis): string {
115 if (value.length <= maxLength) {
116 return value;
122 return `${value.substr(0, prefixLength)}${suffix}${value.substr(value.length - suffixLength)}`;
123 }
124 > strings.ts
125 > /**
126 > * Removes all occurrences of needle from the beginning and end of haystack.
127 > * @param haystack string to trim
128 > * @param needle the thing to trim (default is a blank)
129 > */
130 > export function trim(haystack: string, needle: string = ' '): string {
131 const trimmed = ltrim(haystack, needle);
132 return rtrim(trimmed, needle);
133 }
134 > strings.ts
135 > /**
136 > * Removes all occurrences of needle from the beginning of haystack.
137 > * @param haystack string to trim
138 > * @param needle the thing to trim
139 > */
140 > export function ltrim(haystack: string, needle: string): string {
141 if (!haystack || !needle) {
142 return haystack;
157 return haystack.substring(offset);
158 }
159 > strings.ts
160 > /**
161 > * Removes all occurrences of needle from the end of haystack.
162 > * @param haystack string to trim
163 > * @param needle the thing to trim
164 > */
165 > export function rtrim(haystack: string, needle: string): string {
166 if (!haystack || !needle) {
167 return haystack;
187 return haystack.substring(0, offset);
188 }
189 > strings.ts
190 > export function convertSimple2RegExpPattern(pattern: string): string {
191 return pattern.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&').replace(/[\*]/g, '.*');
192 }
193 > strings.ts
194 > export interface RegExpOptions {
195 > matchCase?: boolean;
196 > wholeWord?: boolean;
197 > multiline?: boolean;
198 > global?: boolean;
199 > unicode?: boolean;
200 > }
201 >
202 > export function createRegExp(searchString: string, isRegex: boolean, options: RegExpOptions = {}): RegExp {
203 if (!searchString) {
204 throw new Error('Cannot create regex from empty string');
231 return new RegExp(searchString, modifiers);
232 }
233 > strings.ts
234 > export function regExpLeadsToEndlessLoop(regexp: RegExp): boolean {
235 // Exit early if it's one of these special cases which are meant to match
236 // against an empty string
244 return !!(match && regexp.lastIndex === 0);
245 }
246 > strings.ts
247 > export function joinStrings(items: (string | undefined | null | false)[], separator: string): string {
248 return items.filter(item => item !== undefined && item !== null && item !== false).join(separator);
249 }
250 > strings.ts
251 > export function splitLines(str: string): string[] {
252 return str.split(/\r\n|\r|\n/);
253 }
254 > strings.ts
255 > export function splitLinesIncludeSeparators(str: string): string[] {
256 const linesWithSeparators: string[] = [];
257 const splitLinesAndSeparators = str.split(/(\r\n|\r|\n)/);
261 return linesWithSeparators;
262 }
263 > strings.ts
264 > export function indexOfPattern(str: string, re: RegExp) {
265 const match = re.exec(str);
266 if (match) {
269 return -1;
270 }
271 > strings.ts
272 > /**
273 > * Returns first index of the string that is not whitespace.
274 > * If string is empty or contains only whitespaces, returns -1
275 > */
276 > export function firstNonWhitespaceIndex(str: string): number {
277 for (let i = 0, len = str.length; i < len; i++) {
278 const chCode = str.charCodeAt(i);
283 return -1;
284 }
285 > strings.ts
286 > /**
287 > * Returns the leading whitespace of the string.
288 > * If the string contains only whitespaces, returns entire string
289 > */
290 > export function getLeadingWhitespace(str: string, start: number = 0, end: number = str.length): string {
291 for (let i = start; i < end; i++) {
292 const chCode = str.charCodeAt(i);
297 return str.substring(start, end);
298 }
299 > strings.ts
300 > /**
301 > * Returns last index of the string that is not whitespace.
302 > * If string is empty or contains only whitespaces, returns -1
303 > */
304 > export function lastNonWhitespaceIndex(str: string, startIndex: number = str.length - 1): number {
305 for (let i = startIndex; i >= 0; i--) {
306 const chCode = str.charCodeAt(i);
311 return -1;
312 }
313 > strings.ts
314 > export function getIndentationLength(str: string): number {
315 const idx = firstNonWhitespaceIndex(str);
316 if (idx === -1) { return str.length; }
317 return idx;
318 }
319 > strings.ts
320 > /**
321 > * Function that works identically to String.prototype.replace, except, the
322 > * replace function is allowed to be async and return a Promise.
323 > */
324 > export function replaceAsync(str: string, search: RegExp, replacer: (match: string, ...args: unknown[]) => Promise<string>): Promise<string> {
325 const parts: (string | Promise<string>)[] = [];
326
340 return Promise.all(parts).then(p => p.join(''));
341 }
342 > strings.ts
343 > export function compare(a: string, b: string): number {
344 if (a < b) {
345 return -1;
350 }
351 }
352 > strings.ts
353 > export function compareSubstring(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {
354 for (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {
355 const codeA = a.charCodeAt(aStart);
370 return 0;
371 }
372 > strings.ts
373 > export function compareIgnoreCase(a: string, b: string): number {
374 return compareSubstringIgnoreCase(a, b, 0, a.length, 0, b.length);
375 }
376 > strings.ts
377 > export function compareSubstringIgnoreCase(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {
378
379 for (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {
421 return 0;
422 }
423 > strings.ts
424 > export function isAsciiDigit(code: number): boolean {
425 return code >= CharCode.Digit0 && code <= CharCode.Digit9;
426 }
427 > strings.ts
428 > export function isLowerAsciiLetter(code: number): boolean {
429 return code >= CharCode.a && code <= CharCode.z;
430 }
431 > strings.ts
432 > export function isUpperAsciiLetter(code: number): boolean {
433 return code >= CharCode.A && code <= CharCode.Z;
434 }
435 > strings.ts
436 > export function equalsIgnoreCase(a: string, b: string): boolean {
437 return a.length === b.length && compareSubstringIgnoreCase(a, b) === 0;
438 }
439 > strings.ts
440 > export function equals(a: string | undefined, b: string | undefined, ignoreCase?: boolean): boolean {
441 return a === b || (!!ignoreCase && a !== undefined && b !== undefined && equalsIgnoreCase(a, b));
442 }
443 > strings.ts
444 > export function startsWithIgnoreCase(str: string, candidate: string): boolean {
445 const len = candidate.length;
446 return len <= str.length && compareSubstringIgnoreCase(str, candidate, 0, len) === 0;
447 }
448 > strings.ts
449 > export function endsWithIgnoreCase(str: string, candidate: string): boolean {
450 const len = str.length;
451 const start = len - candidate.length;
452 return start >= 0 && compareSubstringIgnoreCase(str, candidate, start, len) === 0;
453 }
454 > strings.ts
455 > /**
456 > * @returns the length of the common prefix of the two strings.
457 > */
458 > export function commonPrefixLength(a: string, b: string): number {
459
460 const len = Math.min(a.length, b.length);
469 return len;
470 }
471 > strings.ts
472 > /**
473 > * @returns the length of the common suffix of the two strings.
474 > */
475 > export function commonSuffixLength(a: string, b: string): number {
476
477 const len = Math.min(a.length, b.length);
489 return len;
490 }
491 > strings.ts
492 > /**
493 > * See http://en.wikipedia.org/wiki/Surrogate_pair
494 > */
495 > export function isHighSurrogate(charCode: number): boolean {
496 return (0xD800 <= charCode && charCode <= 0xDBFF);
497 }
498 > strings.ts
499 > /**
500 > * See http://en.wikipedia.org/wiki/Surrogate_pair
501 > */
502 > export function isLowSurrogate(charCode: number): boolean {
503 return (0xDC00 <= charCode && charCode <= 0xDFFF);
504 }
505 > strings.ts
506 > /**
507 > * See http://en.wikipedia.org/wiki/Surrogate_pair
508 > */
509 > export function computeCodePoint(highSurrogate: number, lowSurrogate: number): number {
510 return ((highSurrogate - 0xD800) << 10) + (lowSurrogate - 0xDC00) + 0x10000;
511 }
512 > strings.ts
513 > /**
514 > * get the code point that begins at offset `offset`
515 > */
516 > export function getNextCodePoint(str: string, len: number, offset: number): number {
517 const charCode = str.charCodeAt(offset);
518 if (isHighSurrogate(charCode) && offset + 1 < len) {
524 return charCode;
525 }
526 > strings.ts
527 > /**
528 > * get the code point that ends right before offset `offset`
529 > */
530 function getPrevCodePoint(str: string, offset: number): number {
531 const charCode = str.charCodeAt(offset - 1);
538 return charCode;
539 }
540 > strings.ts
541 > export class CodePointIterator {
542 >
543 > private readonly _str: string;
544 > private readonly _len: number;
545 > private _offset: number;
546 >
547 > public get offset(): number {
548 return this._offset;
549 }
550 > strings.ts
551 > constructor(str: string, offset: number = 0) {
552 this._str = str;
553 this._len = str.length;
554 this._offset = offset;
555 }
556 > strings.ts
557 > public setOffset(offset: number): void {
558 this._offset = offset;
559 }
560 > strings.ts
561 > public prevCodePoint(): number {
562 const codePoint = getPrevCodePoint(this._str, this._offset);
563 this._offset -= (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);
564 return codePoint;
565 }
566 > strings.ts
567 > public nextCodePoint(): number {
568 const codePoint = getNextCodePoint(this._str, this._len, this._offset);
569 this._offset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);
570 return codePoint;
571 }
572 > strings.ts
573 > public eol(): boolean {
574 return (this._offset >= this._len);
575 }
576 > } strings.ts
577 >
578 > export class GraphemeIterator {
579 >
580 > private readonly _iterator: CodePointIterator;
581 >
582 > public get offset(): number {
583 return this._iterator.offset;
584 }
585 > strings.ts
586 > constructor(str: string, offset: number = 0) {
587 this._iterator = new CodePointIterator(str, offset);
588 }
589 > strings.ts
590 > public nextGraphemeLength(): number {
591 const graphemeBreakTree = GraphemeBreakTree.getInstance();
592 const iterator = this._iterator;
606 return (iterator.offset - initialOffset);
607 }
608 > strings.ts
609 > public prevGraphemeLength(): number {
610 const graphemeBreakTree = GraphemeBreakTree.getInstance();
611 const iterator = this._iterator;
625 return (initialOffset - iterator.offset);
626 }
627 > strings.ts
628 > public eol(): boolean {
629 return this._iterator.eol();
630 }
631 > } strings.ts
632 >
633 > export function nextCharLength(str: string, initialOffset: number): number {
634 const iterator = new GraphemeIterator(str, initialOffset);
635 return iterator.nextGraphemeLength();
636 }
637 > strings.ts
638 > export function prevCharLength(str: string, initialOffset: number): number {
639 const iterator = new GraphemeIterator(str, initialOffset);
640 return iterator.prevGraphemeLength();
641 }
642 > strings.ts
643 > export function getCharContainingOffset(str: string, offset: number): [number, number] {
644 if (offset > 0 && isLowSurrogate(str.charCodeAt(offset))) {
645 offset--;
649 return [startOffset, endOffset];
650 }
651 > strings.ts
652 > export function charCount(str: string): number {
653 const iterator = new GraphemeIterator(str);
654 let length = 0;
659 return length;
660 }
661 > strings.ts
662 > let CONTAINS_RTL: RegExp | undefined = undefined;
663 >
664 function makeContainsRtl() {
665 // Generated using https://github.com/alexdima/unicode-utils/blob/main/rtl-test.js
666 return /(?:[\u05BE\u05C0\u05C3\u05C6\u05D0-\u05F4\u0608\u060B\u060D\u061B-\u064A\u066D-\u066F\u0671-\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u0710\u0712-\u072F\u074D-\u07A5\u07B1-\u07EA\u07F4\u07F5\u07FA\u07FE-\u0815\u081A\u0824\u0828\u0830-\u0858\u085E-\u088E\u08A0-\u08C9\u200F\uFB1D\uFB1F-\uFB28\uFB2A-\uFD3D\uFD50-\uFDC7\uFDF0-\uFDFC\uFE70-\uFEFC]|\uD802[\uDC00-\uDD1B\uDD20-\uDE00\uDE10-\uDE35\uDE40-\uDEE4\uDEEB-\uDF35\uDF40-\uDFFF]|\uD803[\uDC00-\uDD23\uDE80-\uDEA9\uDEAD-\uDF45\uDF51-\uDF81\uDF86-\uDFF6]|\uD83A[\uDC00-\uDCCF\uDD00-\uDD43\uDD4B-\uDFFF]|\uD83B[\uDC00-\uDEBB])/;
667 }
668 > strings.ts
669 > /**
670 > * Returns true if `str` contains any Unicode character that is classified as "R" or "AL".
671 > */
672 > export function containsRTL(str: string): boolean {
673 if (!CONTAINS_RTL) {
674 CONTAINS_RTL = makeContainsRtl();
677 return CONTAINS_RTL.test(str);
678 }
679 > strings.ts
680 > const IS_BASIC_ASCII = /^[\t\n\r\x20-\x7E]*$/;
681 > /**
682 > * Returns true if `str` contains only basic ASCII characters in the range 32 - 126 (including 32 and 126) or \n, \r, \t
683 > */
684 > export function isBasicASCII(str: string): boolean {
685 return IS_BASIC_ASCII.test(str);
686 }
687 > strings.ts
688 > export const UNUSUAL_LINE_TERMINATORS = /[\u2028\u2029]/; // LINE SEPARATOR (LS) or PARAGRAPH SEPARATOR (PS)
689 > /**
690 > * Returns true if `str` contains unusual line terminators, like LS or PS
691 > */
692 > export function containsUnusualLineTerminators(str: string): boolean {
693 return UNUSUAL_LINE_TERMINATORS.test(str);
694 }
695 > strings.ts
696 > export function isFullWidthCharacter(charCode: number): boolean {
697 // Do a cheap trick to better support wrapping of wide characters, treat them as 2 columns
698 // http://jrgraphix.net/research/unicode_blocks.php
741 );
742 }
743 > strings.ts
744 > /**
745 > * A fast function (therefore imprecise) to check if code points are emojis.
746 > * Generated using https://github.com/alexdima/unicode-utils/blob/main/emoji-test.js
747 > */
748 > export function isEmojiImprecise(x: number): boolean {
749 return (
750 (x >= 0x1F1E6 && x <= 0x1F1FF) || (x === 8986) || (x === 8987) || (x === 9200)
755 );
756 }
757 > strings.ts
758 > /**
759 > * Given a string and a max length returns a shorted version. Shorting
760 > * happens at favorable positions - such as whitespace or punctuation characters.
761 > * The return value can be longer than the given value of `n`. Leading whitespace is always trimmed.
762 > */
763 > export function lcut(text: string, n: number, prefix = ''): string {
764 const trimmed = text.trimStart();
765
785 return prefix + trimmed.substring(i).trimStart();
786 }
787 > strings.ts
788 > /**
789 > * Given a string and a max length returns a shortened version keeping the beginning.
790 > * Shortening happens at favorable positions - such as whitespace or punctuation characters.
791 > * Trailing whitespace is always trimmed.
792 > */
793 > export function rcut(text: string, n: number, suffix = ''): string {
794 const trimmed = text.trimEnd();
795
832 return result + suffix;
833 }
834 > strings.ts
835 > // Defacto standard: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
836 > const CSI_SEQUENCE = /(?:\x1b\[|\x9b)[=?>!]?[\d;:]*["$#'* ]?[a-zA-Z@^`{}|~]/;
837 > const OSC_SEQUENCE = /(?:\x1b\]|\x9d).*?(?:\x1b\\|\x07|\x9c)/;
838 > const ESC_SEQUENCE = /\x1b(?:[ #%\(\)\*\+\-\.\/]?[a-zA-Z0-9\|}~@])/;
839 > const CONTROL_SEQUENCES = new RegExp('(?:' + [
840 > CSI_SEQUENCE.source,
841 > OSC_SEQUENCE.source,
842 > ESC_SEQUENCE.source,
843 > ].join('|') + ')', 'g');
844 >
845 > /** Iterates over parts of a string with CSI sequences */
846 > export function* forAnsiStringParts(str: string) {
847 let last = 0;
848 for (const match of str.matchAll(CONTROL_SEQUENCES)) {
859 }
860 }
861 > strings.ts
862 > /**
863 > * Strips ANSI escape sequences from a string.
864 > * @param str The dastringa stringo strip the ANSI escape sequences from.
865 > *
866 > * @example
867 > * removeAnsiEscapeCodes('\u001b[31mHello, World!\u001b[0m');
868 > * // 'Hello, World!'
869 > */
870 > export function removeAnsiEscapeCodes(str: string): string {
871 if (str) {
872 str = str.replace(CONTROL_SEQUENCES, '');
875 return str;
876 }
877 > strings.ts
878 > const PROMPT_NON_PRINTABLE = /\\\[.*?\\\]/g;
879 >
880 > /**
881 > * Strips ANSI escape sequences from a UNIX-style prompt string (eg. `$PS1`).
882 > * @param str The string to strip the ANSI escape sequences from.
883 > *
884 > * @example
885 > * removeAnsiEscapeCodesFromPrompt('\n\\[\u001b[01;34m\\]\\w\\[\u001b[00m\\]\n\\[\u001b[1;32m\\]> \\[\u001b[0m\\]');
886 > * // '\n\\w\n> '
887 > */
888 > export function removeAnsiEscapeCodesFromPrompt(str: string): string {
889 return removeAnsiEscapeCodes(str).replace(PROMPT_NON_PRINTABLE, '');
890 }
891 > strings.ts
892 >
893 > // -- UTF-8 BOM
894 >
895 > export const UTF8_BOM_CHARACTER = String.fromCharCode(CharCode.UTF8_BOM);
896 >
897 > export function startsWithUTF8BOM(str: string): boolean {
898 return !!(str && str.length > 0 && str.charCodeAt(0) === CharCode.UTF8_BOM);
899 }
900 > strings.ts
901 > export function stripUTF8BOM(str: string): string {
902 return startsWithUTF8BOM(str) ? str.substr(1) : str;
903 }
904 > strings.ts
905 > /**
906 > * Checks if the characters of the provided query string are included in the
907 > * target string. The characters do not have to be contiguous within the string.
908 > */
909 > export function fuzzyContains(target: string, query: string): boolean {
910 if (!target || !query) {
911 return false; // return early if target or query are undefined
936 return true;
937 }
938 > strings.ts
939 > export function containsUppercaseCharacter(target: string, ignoreEscapedChars = false): boolean {
940 if (!target) {
941 return false;
948 return target.toLowerCase() !== target;
949 }
950 > strings.ts
951 > export function uppercaseFirstLetter(str: string): string {
952 return str.charAt(0).toUpperCase() + str.slice(1);
953 }
954 > strings.ts
955 > export function getNLines(str: string, n = 1): string {
956 if (n === 0) {
957 return '';
974 return str.substr(0, idx);
975 }
976 > strings.ts
977 > /**
978 > * Produces 'a'-'z', followed by 'A'-'Z'... followed by 'a'-'z', etc.
979 > */
980 > export function singleLetterHash(n: number): string {
981 const LETTERS_CNT = (CharCode.Z - CharCode.A + 1);
982
989 return String.fromCharCode(CharCode.A + n - LETTERS_CNT);
990 }
991 > strings.ts
992 > //#region Unicode Grapheme Break
993 >
994 > export function getGraphemeBreakType(codePoint: number): GraphemeBreakType {
995 const graphemeBreakTree = GraphemeBreakTree.getInstance();
996 return graphemeBreakTree.getGraphemeBreakType(codePoint);
997 }
998 > strings.ts
999 function breakBetweenGraphemeBreakType(breakTypeA: GraphemeBreakType, breakTypeB: GraphemeBreakType): boolean {
1000 // http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules
1076 return true;
1077 }
1078 > strings.ts
1079 > export const enum GraphemeBreakType {
1080 > Other = 0,
1081 > Prepend = 1,
1082 > CR = 2,
1083 > LF = 3,
1084 > Control = 4,
1085 > Extend = 5,
1086 > Regional_Indicator = 6,
1087 > SpacingMark = 7,
1088 > L = 8,
1089 > V = 9,
1090 > T = 10,
1091 > LV = 11,
1092 > LVT = 12,
1093 > ZWJ = 13,
1094 > Extended_Pictographic = 14
1095 > }
1096 >
1097 > class GraphemeBreakTree {
1098 >
1099 > private static _INSTANCE: GraphemeBreakTree | null = null;
1100 > public static getInstance(): GraphemeBreakTree {
1101 if (!GraphemeBreakTree._INSTANCE) {
1102 GraphemeBreakTree._INSTANCE = new GraphemeBreakTree();
1104 return GraphemeBreakTree._INSTANCE;
1105 }
1106 > strings.ts
1107 > private readonly _data: number[];
1108 >
1109 > constructor() {
1110 this._data = getGraphemeBreakRawData();
1111 }
1112 > strings.ts
1113 > public getGraphemeBreakType(codePoint: number): GraphemeBreakType {
1114 // !!! Let's make 7bit ASCII a bit faster: 0..31
1115 if (codePoint < 32) {
1145 return GraphemeBreakType.Other;
1146 }
1147 > } strings.ts
1148 >
1149 function getGraphemeBreakRawData(): number[] {
1150 // generated using https://github.com/alexdima/unicode-utils/blob/main/grapheme-break.js
1151 return JSON.parse('[0,0,0,51229,51255,12,44061,44087,12,127462,127487,6,7083,7085,5,47645,47671,12,54813,54839,12,128678,128678,14,3270,3270,5,9919,9923,14,45853,45879,12,49437,49463,12,53021,53047,12,71216,71218,7,128398,128399,14,129360,129374,14,2519,2519,5,4448,4519,9,9742,9742,14,12336,12336,14,44957,44983,12,46749,46775,12,48541,48567,12,50333,50359,12,52125,52151,12,53917,53943,12,69888,69890,5,73018,73018,5,127990,127990,14,128558,128559,14,128759,128760,14,129653,129655,14,2027,2035,5,2891,2892,7,3761,3761,5,6683,6683,5,8293,8293,4,9825,9826,14,9999,9999,14,43452,43453,5,44509,44535,12,45405,45431,12,46301,46327,12,47197,47223,12,48093,48119,12,48989,49015,12,49885,49911,12,50781,50807,12,51677,51703,12,52573,52599,12,53469,53495,12,54365,54391,12,65279,65279,4,70471,70472,7,72145,72147,7,119173,119179,5,127799,127818,14,128240,128244,14,128512,128512,14,128652,128652,14,128721,128722,14,129292,129292,14,129445,129450,14,129734,129743,14,1476,1477,5,2366,2368,7,2750,2752,7,3076,3076,5,3415,3415,5,4141,4144,5,6109,6109,5,6964,6964,5,7394,7400,5,9197,9198,14,9770,9770,14,9877,9877,14,9968,9969,14,10084,10084,14,43052,43052,5,43713,43713,5,44285,44311,12,44733,44759,12,45181,45207,12,45629,45655,12,46077,46103,12,46525,46551,12,46973,46999,12,47421,47447,12,47869,47895,12,48317,48343,12,48765,48791,12,49213,49239,12,49661,49687,12,50109,50135,12,50557,50583,12,51005,51031,12,51453,51479,12,51901,51927,12,52349,52375,12,52797,52823,12,53245,53271,12,53693,53719,12,54141,54167,12,54589,54615,12,55037,55063,12,69506,69509,5,70191,70193,5,70841,70841,7,71463,71467,5,72330,72342,5,94031,94031,5,123628,123631,5,127763,127765,14,127941,127941,14,128043,128062,14,128302,128317,14,128465,128467,14,128539,128539,14,128640,128640,14,128662,128662,14,128703,128703,14,128745,128745,14,129004,129007,14,129329,129330,14,129402,129402,14,129483,129483,14,129686,129704,14,130048,131069,14,173,173,4,1757,1757,1,2200,2207,5,2434,2435,7,2631,2632,5,2817,2817,5,3008,3008,5,3201,3201,5,3387,3388,5,3542,3542,5,3902,3903,7,4190,4192,5,6002,6003,5,6439,6440,5,6765,6770,7,7019,7027,5,7154,7155,7,8205,8205,13,8505,8505,14,9654,9654,14,9757,9757,14,9792,9792,14,9852,9853,14,9890,9894,14,9937,9937,14,9981,9981,14,10035,10036,14,11035,11036,14,42654,42655,5,43346,43347,7,43587,43587,5,44006,44007,7,44173,44199,12,44397,44423,12,44621,44647,12,44845,44871,12,45069,45095,12,45293,45319,12,45517,45543,12,45741,45767,12,45965,45991,12,46189,46215,12,46413,46439,12,46637,46663,12,46861,46887,12,47085,47111,12,47309,47335,12,47533,47559,12,47757,47783,12,47981,48007,12,48205,48231,12,48429,48455,12,48653,48679,12,48877,48903,12,49101,49127,12,49325,49351,12,49549,49575,12,49773,49799,12,49997,50023,12,50221,50247,12,50445,50471,12,50669,50695,12,50893,50919,12,51117,51143,12,51341,51367,12,51565,51591,12,51789,51815,12,52013,52039,12,52237,52263,12,52461,52487,12,52685,52711,12,52909,52935,12,53133,53159,12,53357,53383,12,53581,53607,12,53805,53831,12,54029,54055,12,54253,54279,12,54477,54503,12,54701,54727,12,54925,54951,12,55149,55175,12,68101,68102,5,69762,69762,7,70067,70069,7,70371,70378,5,70720,70721,7,71087,71087,5,71341,71341,5,71995,71996,5,72249,72249,7,72850,72871,5,73109,73109,5,118576,118598,5,121505,121519,5,127245,127247,14,127568,127569,14,127777,127777,14,127872,127891,14,127956,127967,14,128015,128016,14,128110,128172,14,128259,128259,14,128367,128368,14,128424,128424,14,128488,128488,14,128530,128532,14,128550,128551,14,128566,128566,14,128647,128647,14,128656,128656,14,128667,128673,14,128691,128693,14,128715,128715,14,128728,128732,14,128752,128752,14,128765,128767,14,129096,129103,14,129311,129311,14,129344,129349,14,129394,129394,14,129413,129425,14,129466,129471,14,129511,129535,14,129664,129666,14,129719,129722,14,129760,129767,14,917536,917631,5,13,13,2,1160,1161,5,1564,1564,4,1807,1807,1,2085,2087,5,2307,2307,7,2382,2383,7,2497,2500,5,2563,2563,7,2677,2677,5,2763,2764,7,2879,2879,5,2914,2915,5,3021,3021,5,3142,3144,5,3263,3263,5,3285,3286,5,3398,3400,7,3530,3530,5,3633,3633,5,3864,3865,5,3974,3975,5,4155,4156,7,4229,4230,5,5909,5909,7,6078,6085,7,6277,6278,5,6451,6456,7,6744,6750,5,6846,6846,5,6972,6972,5,7074,7077,5,7146,7148,7,7222,7223,5,7416,7417,5,8234,8238,4,8417,8417,5,9000,9000,14,9203,9203,14,9730,9731,14,9748,9749,14,9762,9763,14,9776,9783,14,9800,9811,14,9831,9831,14,9872,9873,14,9882,9882,14,9900,9903,14,9929,9933,14,9941,9960,14,9974,9974,14,9989,9989,14,10006,10006,14,10062,10062,14,10160,10160,14,11647,11647,5,12953,12953,14,43019,43019,5,43232,43249,5,43443,43443,5,43567,43568,7,43696,43696,5,43765,43765,7,44013,44013,5,44117,44143,12,44229,44255,12,44341,44367,12,44453,44479,12,44565,44591,12,44677,44703,12,44789,44815,12,44901,44927,12,45013,45039,12,45125,45151,12,45237,45263,12,45349,45375,12,45461,45487,12,45573,45599,12,45685,45711,12,45797,45823,12,45909,45935,12,46021,46047,12,46133,46159,12,46245,46271,12,46357,46383,12,46469,46495,12,46581,46607,12,46693,46719,12,46805,46831,12,46917,46943,12,47029,47055,12,47141,47167,12,47253,47279,12,47365,47391,12,47477,47503,12,47589,47615,12,47701,47727,12,47813,47839,12,47925,47951,12,48037,48063,12,48149,48175,12,48261,48287,12,48373,48399,12,48485,48511,12,48597,48623,12,48709,48735,12,48821,48847,12,48933,48959,12,49045,49071,12,49157,49183,12,49269,49295,12,49381,49407,12,49493,49519,12,49605,49631,12,49717,49743,12,49829,49855,12,49941,49967,12,50053,50079,12,50165,50191,12,50277,50303,12,50389,50415,12,50501,50527,12,50613,50639,12,50725,50751,12,50837,50863,12,50949,50975,12,51061,51087,12,51173,51199,12,51285,51311,12,51397,51423,12,51509,51535,12,51621,51647,12,51733,51759,12,51845,51871,12,51957,51983,12,52069,52095,12,52181,52207,12,52293,52319,12,52405,52431,12,52517,52543,12,52629,52655,12,52741,52767,12,52853,52879,12,52965,52991,12,53077,53103,12,53189,53215,12,53301,53327,12,53413,53439,12,53525,53551,12,53637,53663,12,53749,53775,12,53861,53887,12,53973,53999,12,54085,54111,12,54197,54223,12,54309,54335,12,54421,54447,12,54533,54559,12,54645,54671,12,54757,54783,12,54869,54895,12,54981,55007,12,55093,55119,12,55243,55291,10,66045,66045,5,68325,68326,5,69688,69702,5,69817,69818,5,69957,69958,7,70089,70092,5,70198,70199,5,70462,70462,5,70502,70508,5,70750,70750,5,70846,70846,7,71100,71101,5,71230,71230,7,71351,71351,5,71737,71738,5,72000,72000,7,72160,72160,5,72273,72278,5,72752,72758,5,72882,72883,5,73031,73031,5,73461,73462,7,94192,94193,7,119149,119149,7,121403,121452,5,122915,122916,5,126980,126980,14,127358,127359,14,127535,127535,14,127759,127759,14,127771,127771,14,127792,127793,14,127825,127867,14,127897,127899,14,127945,127945,14,127985,127986,14,128000,128007,14,128021,128021,14,128066,128100,14,128184,128235,14,128249,128252,14,128266,128276,14,128335,128335,14,128379,128390,14,128407,128419,14,128444,128444,14,128481,128481,14,128499,128499,14,128526,128526,14,128536,128536,14,128543,128543,14,128556,128556,14,128564,128564,14,128577,128580,14,128643,128645,14,128649,128649,14,128654,128654,14,128660,128660,14,128664,128664,14,128675,128675,14,128686,128689,14,128695,128696,14,128705,128709,14,128717,128719,14,128725,128725,14,128736,128741,14,128747,128748,14,128755,128755,14,128762,128762,14,128981,128991,14,129009,129023,14,129160,129167,14,129296,129304,14,129320,129327,14,129340,129342,14,129356,129356,14,129388,129392,14,129399,129400,14,129404,129407,14,129432,129442,14,129454,129455,14,129473,129474,14,129485,129487,14,129648,129651,14,129659,129660,14,129671,129679,14,129709,129711,14,129728,129730,14,129751,129753,14,129776,129782,14,917505,917505,4,917760,917999,5,10,10,3,127,159,4,768,879,5,1471,1471,5,1536,1541,1,1648,1648,5,1767,1768,5,1840,1866,5,2070,2073,5,2137,2139,5,2274,2274,1,2363,2363,7,2377,2380,7,2402,2403,5,2494,2494,5,2507,2508,7,2558,2558,5,2622,2624,7,2641,2641,5,2691,2691,7,2759,2760,5,2786,2787,5,2876,2876,5,2881,2884,5,2901,2902,5,3006,3006,5,3014,3016,7,3072,3072,5,3134,3136,5,3157,3158,5,3260,3260,5,3266,3266,5,3274,3275,7,3328,3329,5,3391,3392,7,3405,3405,5,3457,3457,5,3536,3537,7,3551,3551,5,3636,3642,5,3764,3772,5,3895,3895,5,3967,3967,7,3993,4028,5,4146,4151,5,4182,4183,7,4226,4226,5,4253,4253,5,4957,4959,5,5940,5940,7,6070,6070,7,6087,6088,7,6158,6158,4,6432,6434,5,6448,6449,7,6679,6680,5,6742,6742,5,6754,6754,5,6783,6783,5,6912,6915,5,6966,6970,5,6978,6978,5,7042,7042,7,7080,7081,5,7143,7143,7,7150,7150,7,7212,7219,5,7380,7392,5,7412,7412,5,8203,8203,4,8232,8232,4,8265,8265,14,8400,8412,5,8421,8432,5,8617,8618,14,9167,9167,14,9200,9200,14,9410,9410,14,9723,9726,14,9733,9733,14,9745,9745,14,9752,9752,14,9760,9760,14,9766,9766,14,9774,9774,14,9786,9786,14,9794,9794,14,9823,9823,14,9828,9828,14,9833,9850,14,9855,9855,14,9875,9875,14,9880,9880,14,9885,9887,14,9896,9897,14,9906,9916,14,9926,9927,14,9935,9935,14,9939,9939,14,9962,9962,14,9972,9972,14,9978,9978,14,9986,9986,14,9997,9997,14,10002,10002,14,10017,10017,14,10055,10055,14,10071,10071,14,10133,10135,14,10548,10549,14,11093,11093,14,12330,12333,5,12441,12442,5,42608,42610,5,43010,43010,5,43045,43046,5,43188,43203,7,43302,43309,5,43392,43394,5,43446,43449,5,43493,43493,5,43571,43572,7,43597,43597,7,43703,43704,5,43756,43757,5,44003,44004,7,44009,44010,7,44033,44059,12,44089,44115,12,44145,44171,12,44201,44227,12,44257,44283,12,44313,44339,12,44369,44395,12,44425,44451,12,44481,44507,12,44537,44563,12,44593,44619,12,44649,44675,12,44705,44731,12,44761,44787,12,44817,44843,12,44873,44899,12,44929,44955,12,44985,45011,12,45041,45067,12,45097,45123,12,45153,45179,12,45209,45235,12,45265,45291,12,45321,45347,12,45377,45403,12,45433,45459,12,45489,45515,12,45545,45571,12,45601,45627,12,45657,45683,12,45713,45739,12,45769,45795,12,45825,45851,12,45881,45907,12,45937,45963,12,45993,46019,12,46049,46075,12,46105,46131,12,46161,46187,12,46217,46243,12,46273,46299,12,46329,46355,12,46385,46411,12,46441,46467,12,46497,46523,12,46553,46579,12,46609,46635,12,46665,46691,12,46721,46747,12,46777,46803,12,46833,46859,12,46889,46915,12,46945,46971,12,47001,47027,12,47057,47083,12,47113,47139,12,47169,47195,12,47225,47251,12,47281,47307,12,47337,47363,12,47393,47419,12,47449,47475,12,47505,47531,12,47561,47587,12,47617,47643,12,47673,47699,12,47729,47755,12,47785,47811,12,47841,47867,12,47897,47923,12,47953,47979,12,48009,48035,12,48065,48091,12,48121,48147,12,48177,48203,12,48233,48259,12,48289,48315,12,48345,48371,12,48401,48427,12,48457,48483,12,48513,48539,12,48569,48595,12,48625,48651,12,48681,48707,12,48737,48763,12,48793,48819,12,48849,48875,12,48905,48931,12,48961,48987,12,49017,49043,12,49073,49099,12,49129,49155,12,49185,49211,12,49241,49267,12,49297,49323,12,49353,49379,12,49409,49435,12,49465,49491,12,49521,49547,12,49577,49603,12,49633,49659,12,49689,49715,12,49745,49771,12,49801,49827,12,49857,49883,12,49913,49939,12,49969,49995,12,50025,50051,12,50081,50107,12,50137,50163,12,50193,50219,12,50249,50275,12,50305,50331,12,50361,50387,12,50417,50443,12,50473,50499,12,50529,50555,12,50585,50611,12,50641,50667,12,50697,50723,12,50753,50779,12,50809,50835,12,50865,50891,12,50921,50947,12,50977,51003,12,51033,51059,12,51089,51115,12,51145,51171,12,51201,51227,12,51257,51283,12,51313,51339,12,51369,51395,12,51425,51451,12,51481,51507,12,51537,51563,12,51593,51619,12,51649,51675,12,51705,51731,12,51761,51787,12,51817,51843,12,51873,51899,12,51929,51955,12,51985,52011,12,52041,52067,12,52097,52123,12,52153,52179,12,52209,52235,12,52265,52291,12,52321,52347,12,52377,52403,12,52433,52459,12,52489,52515,12,52545,52571,12,52601,52627,12,52657,52683,12,52713,52739,12,52769,52795,12,52825,52851,12,52881,52907,12,52937,52963,12,52993,53019,12,53049,53075,12,53105,53131,12,53161,53187,12,53217,53243,12,53273,53299,12,53329,53355,12,53385,53411,12,53441,53467,12,53497,53523,12,53553,53579,12,53609,53635,12,53665,53691,12,53721,53747,12,53777,53803,12,53833,53859,12,53889,53915,12,53945,53971,12,54001,54027,12,54057,54083,12,54113,54139,12,54169,54195,12,54225,54251,12,54281,54307,12,54337,54363,12,54393,54419,12,54449,54475,12,54505,54531,12,54561,54587,12,54617,54643,12,54673,54699,12,54729,54755,12,54785,54811,12,54841,54867,12,54897,54923,12,54953,54979,12,55009,55035,12,55065,55091,12,55121,55147,12,55177,55203,12,65024,65039,5,65520,65528,4,66422,66426,5,68152,68154,5,69291,69292,5,69633,69633,5,69747,69748,5,69811,69814,5,69826,69826,5,69932,69932,7,70016,70017,5,70079,70080,7,70095,70095,5,70196,70196,5,70367,70367,5,70402,70403,7,70464,70464,5,70487,70487,5,70709,70711,7,70725,70725,7,70833,70834,7,70843,70844,7,70849,70849,7,71090,71093,5,71103,71104,5,71227,71228,7,71339,71339,5,71344,71349,5,71458,71461,5,71727,71735,5,71985,71989,7,71998,71998,5,72002,72002,7,72154,72155,5,72193,72202,5,72251,72254,5,72281,72283,5,72344,72345,5,72766,72766,7,72874,72880,5,72885,72886,5,73023,73029,5,73104,73105,5,73111,73111,5,92912,92916,5,94095,94098,5,113824,113827,4,119142,119142,7,119155,119162,4,119362,119364,5,121476,121476,5,122888,122904,5,123184,123190,5,125252,125258,5,127183,127183,14,127340,127343,14,127377,127386,14,127491,127503,14,127548,127551,14,127744,127756,14,127761,127761,14,127769,127769,14,127773,127774,14,127780,127788,14,127796,127797,14,127820,127823,14,127869,127869,14,127894,127895,14,127902,127903,14,127943,127943,14,127947,127950,14,127972,127972,14,127988,127988,14,127992,127994,14,128009,128011,14,128019,128019,14,128023,128041,14,128064,128064,14,128102,128107,14,128174,128181,14,128238,128238,14,128246,128247,14,128254,128254,14,128264,128264,14,128278,128299,14,128329,128330,14,128348,128359,14,128371,128377,14,128392,128393,14,128401,128404,14,128421,128421,14,128433,128434,14,128450,128452,14,128476,128478,14,128483,128483,14,128495,128495,14,128506,128506,14,128519,128520,14,128528,128528,14,128534,128534,14,128538,128538,14,128540,128542,14,128544,128549,14,128552,128555,14,128557,128557,14,128560,128563,14,128565,128565,14,128567,128576,14,128581,128591,14,128641,128642,14,128646,128646,14,128648,128648,14,128650,128651,14,128653,128653,14,128655,128655,14,128657,128659,14,128661,128661,14,128663,128663,14,128665,128666,14,128674,128674,14,128676,128677,14,128679,128685,14,128690,128690,14,128694,128694,14,128697,128702,14,128704,128704,14,128710,128714,14,128716,128716,14,128720,128720,14,128723,128724,14,128726,128727,14,128733,128735,14,128742,128744,14,128746,128746,14,128749,128751,14,128753,128754,14,128756,128758,14,128761,128761,14,128763,128764,14,128884,128895,14,128992,129003,14,129008,129008,14,129036,129039,14,129114,129119,14,129198,129279,14,129293,129295,14,129305,129310,14,129312,129319,14,129328,129328,14,129331,129338,14,129343,129343,14,129351,129355,14,129357,129359,14,129375,129387,14,129393,129393,14,129395,129398,14,129401,129401,14,129403,129403,14,129408,129412,14,129426,129431,14,129443,129444,14,129451,129453,14,129456,129465,14,129472,129472,14,129475,129482,14,129484,129484,14,129488,129510,14,129536,129647,14,129652,129652,14,129656,129658,14,129661,129663,14,129667,129670,14,129680,129685,14,129705,129708,14,129712,129718,14,129723,129727,14,129731,129733,14,129744,129750,14,129754,129759,14,129768,129775,14,129783,129791,14,917504,917504,4,917506,917535,4,917632,917759,4,918000,921599,4,0,9,4,11,12,4,14,31,4,169,169,14,174,174,14,1155,1159,5,1425,1469,5,1473,1474,5,1479,1479,5,1552,1562,5,1611,1631,5,1750,1756,5,1759,1764,5,1770,1773,5,1809,1809,5,1958,1968,5,2045,2045,5,2075,2083,5,2089,2093,5,2192,2193,1,2250,2273,5,2275,2306,5,2362,2362,5,2364,2364,5,2369,2376,5,2381,2381,5,2385,2391,5,2433,2433,5,2492,2492,5,2495,2496,7,2503,2504,7,2509,2509,5,2530,2531,5,2561,2562,5,2620,2620,5,2625,2626,5,2635,2637,5,2672,2673,5,2689,2690,5,2748,2748,5,2753,2757,5,2761,2761,7,2765,2765,5,2810,2815,5,2818,2819,7,2878,2878,5,2880,2880,7,2887,2888,7,2893,2893,5,2903,2903,5,2946,2946,5,3007,3007,7,3009,3010,7,3018,3020,7,3031,3031,5,3073,3075,7,3132,3132,5,3137,3140,7,3146,3149,5,3170,3171,5,3202,3203,7,3262,3262,7,3264,3265,7,3267,3268,7,3271,3272,7,3276,3277,5,3298,3299,5,3330,3331,7,3390,3390,5,3393,3396,5,3402,3404,7,3406,3406,1,3426,3427,5,3458,3459,7,3535,3535,5,3538,3540,5,3544,3550,7,3570,3571,7,3635,3635,7,3655,3662,5,3763,3763,7,3784,3789,5,3893,3893,5,3897,3897,5,3953,3966,5,3968,3972,5,3981,3991,5,4038,4038,5,4145,4145,7,4153,4154,5,4157,4158,5,4184,4185,5,4209,4212,5,4228,4228,7,4237,4237,5,4352,4447,8,4520,4607,10,5906,5908,5,5938,5939,5,5970,5971,5,6068,6069,5,6071,6077,5,6086,6086,5,6089,6099,5,6155,6157,5,6159,6159,5,6313,6313,5,6435,6438,7,6441,6443,7,6450,6450,5,6457,6459,5,6681,6682,7,6741,6741,7,6743,6743,7,6752,6752,5,6757,6764,5,6771,6780,5,6832,6845,5,6847,6862,5,6916,6916,7,6965,6965,5,6971,6971,7,6973,6977,7,6979,6980,7,7040,7041,5,7073,7073,7,7078,7079,7,7082,7082,7,7142,7142,5,7144,7145,5,7149,7149,5,7151,7153,5,7204,7211,7,7220,7221,7,7376,7378,5,7393,7393,7,7405,7405,5,7415,7415,7,7616,7679,5,8204,8204,5,8206,8207,4,8233,8233,4,8252,8252,14,8288,8292,4,8294,8303,4,8413,8416,5,8418,8420,5,8482,8482,14,8596,8601,14,8986,8987,14,9096,9096,14,9193,9196,14,9199,9199,14,9201,9202,14,9208,9210,14,9642,9643,14,9664,9664,14,9728,9729,14,9732,9732,14,9735,9741,14,9743,9744,14,9746,9746,14,9750,9751,14,9753,9756,14,9758,9759,14,9761,9761,14,9764,9765,14,9767,9769,14,9771,9773,14,9775,9775,14,9784,9785,14,9787,9791,14,9793,9793,14,9795,9799,14,9812,9822,14,9824,9824,14,9827,9827,14,9829,9830,14,9832,9832,14,9851,9851,14,9854,9854,14,9856,9861,14,9874,9874,14,9876,9876,14,9878,9879,14,9881,9881,14,9883,9884,14,9888,9889,14,9895,9895,14,9898,9899,14,9904,9905,14,9917,9918,14,9924,9925,14,9928,9928,14,9934,9934,14,9936,9936,14,9938,9938,14,9940,9940,14,9961,9961,14,9963,9967,14,9970,9971,14,9973,9973,14,9975,9977,14,9979,9980,14,9982,9985,14,9987,9988,14,9992,9996,14,9998,9998,14,10000,10001,14,10004,10004,14,10013,10013,14,10024,10024,14,10052,10052,14,10060,10060,14,10067,10069,14,10083,10083,14,10085,10087,14,10145,10145,14,10175,10175,14,11013,11015,14,11088,11088,14,11503,11505,5,11744,11775,5,12334,12335,5,12349,12349,14,12951,12951,14,42607,42607,5,42612,42621,5,42736,42737,5,43014,43014,5,43043,43044,7,43047,43047,7,43136,43137,7,43204,43205,5,43263,43263,5,43335,43345,5,43360,43388,8,43395,43395,7,43444,43445,7,43450,43451,7,43454,43456,7,43561,43566,5,43569,43570,5,43573,43574,5,43596,43596,5,43644,43644,5,43698,43700,5,43710,43711,5,43755,43755,7,43758,43759,7,43766,43766,5,44005,44005,5,44008,44008,5,44012,44012,7,44032,44032,11,44060,44060,11,44088,44088,11,44116,44116,11,44144,44144,11,44172,44172,11,44200,44200,11,44228,44228,11,44256,44256,11,44284,44284,11,44312,44312,11,44340,44340,11,44368,44368,11,44396,44396,11,44424,44424,11,44452,44452,11,44480,44480,11,44508,44508,11,44536,44536,11,44564,44564,11,44592,44592,11,44620,44620,11,44648,44648,11,44676,44676,11,44704,44704,11,44732,44732,11,44760,44760,11,44788,44788,11,44816,44816,11,44844,44844,11,44872,44872,11,44900,44900,11,44928,44928,11,44956,44956,11,44984,44984,11,45012,45012,11,45040,45040,11,45068,45068,11,45096,45096,11,45124,45124,11,45152,45152,11,45180,45180,11,45208,45208,11,45236,45236,11,45264,45264,11,45292,45292,11,45320,45320,11,45348,45348,11,45376,45376,11,45404,45404,11,45432,45432,11,45460,45460,11,45488,45488,11,45516,45516,11,45544,45544,11,45572,45572,11,45600,45600,11,45628,45628,11,45656,45656,11,45684,45684,11,45712,45712,11,45740,45740,11,45768,45768,11,45796,45796,11,45824,45824,11,45852,45852,11,45880,45880,11,45908,45908,11,45936,45936,11,45964,45964,11,45992,45992,11,46020,46020,11,46048,46048,11,46076,46076,11,46104,46104,11,46132,46132,11,46160,46160,11,46188,46188,11,46216,46216,11,46244,46244,11,46272,46272,11,46300,46300,11,46328,46328,11,46356,46356,11,46384,46384,11,46412,46412,11,46440,46440,11,46468,46468,11,46496,46496,11,46524,46524,11,46552,46552,11,46580,46580,11,46608,46608,11,46636,46636,11,46664,46664,11,46692,46692,11,46720,46720,11,46748,46748,11,46776,46776,11,46804,46804,11,46832,46832,11,46860,46860,11,46888,46888,11,46916,46916,11,46944,46944,11,46972,46972,11,47000,47000,11,47028,47028,11,47056,47056,11,47084,47084,11,47112,47112,11,47140,47140,11,47168,47168,11,47196,47196,11,47224,47224,11,47252,47252,11,47280,47280,11,47308,47308,11,47336,47336,11,47364,47364,11,47392,47392,11,47420,47420,11,47448,47448,11,47476,47476,11,47504,47504,11,47532,47532,11,47560,47560,11,47588,47588,11,47616,47616,11,47644,47644,11,47672,47672,11,47700,47700,11,47728,47728,11,47756,47756,11,47784,47784,11,47812,47812,11,47840,47840,11,47868,47868,11,47896,47896,11,47924,47924,11,47952,47952,11,47980,47980,11,48008,48008,11,48036,48036,11,48064,48064,11,48092,48092,11,48120,48120,11,48148,48148,11,48176,48176,11,48204,48204,11,48232,48232,11,48260,48260,11,48288,48288,11,48316,48316,11,48344,48344,11,48372,48372,11,48400,48400,11,48428,48428,11,48456,48456,11,48484,48484,11,48512,48512,11,48540,48540,11,48568,48568,11,48596,48596,11,48624,48624,11,48652,48652,11,48680,48680,11,48708,48708,11,48736,48736,11,48764,48764,11,48792,48792,11,48820,48820,11,48848,48848,11,48876,48876,11,48904,48904,11,48932,48932,11,48960,48960,11,48988,48988,11,49016,49016,11,49044,49044,11,49072,49072,11,49100,49100,11,49128,49128,11,49156,49156,11,49184,49184,11,49212,49212,11,49240,49240,11,49268,49268,11,49296,49296,11,49324,49324,11,49352,49352,11,49380,49380,11,49408,49408,11,49436,49436,11,49464,49464,11,49492,49492,11,49520,49520,11,49548,49548,11,49576,49576,11,49604,49604,11,49632,49632,11,49660,49660,11,49688,49688,11,49716,49716,11,49744,49744,11,49772,49772,11,49800,49800,11,49828,49828,11,49856,49856,11,49884,49884,11,49912,49912,11,49940,49940,11,49968,49968,11,49996,49996,11,50024,50024,11,50052,50052,11,50080,50080,11,50108,50108,11,50136,50136,11,50164,50164,11,50192,50192,11,50220,50220,11,50248,50248,11,50276,50276,11,50304,50304,11,50332,50332,11,50360,50360,11,50388,50388,11,50416,50416,11,50444,50444,11,50472,50472,11,50500,50500,11,50528,50528,11,50556,50556,11,50584,50584,11,50612,50612,11,50640,50640,11,50668,50668,11,50696,50696,11,50724,50724,11,50752,50752,11,50780,50780,11,50808,50808,11,50836,50836,11,50864,50864,11,50892,50892,11,50920,50920,11,50948,50948,11,50976,50976,11,51004,51004,11,51032,51032,11,51060,51060,11,51088,51088,11,51116,51116,11,51144,51144,11,51172,51172,11,51200,51200,11,51228,51228,11,51256,51256,11,51284,51284,11,51312,51312,11,51340,51340,11,51368,51368,11,51396,51396,11,51424,51424,11,51452,51452,11,51480,51480,11,51508,51508,11,51536,51536,11,51564,51564,11,51592,51592,11,51620,51620,11,51648,51648,11,51676,51676,11,51704,51704,11,51732,51732,11,51760,51760,11,51788,51788,11,51816,51816,11,51844,51844,11,51872,51872,11,51900,51900,11,51928,51928,11,51956,51956,11,51984,51984,11,52012,52012,11,52040,52040,11,52068,52068,11,52096,52096,11,52124,52124,11,52152,52152,11,52180,52180,11,52208,52208,11,52236,52236,11,52264,52264,11,52292,52292,11,52320,52320,11,52348,52348,11,52376,52376,11,52404,52404,11,52432,52432,11,52460,52460,11,52488,52488,11,52516,52516,11,52544,52544,11,52572,52572,11,52600,52600,11,52628,52628,11,52656,52656,11,52684,52684,11,52712,52712,11,52740,52740,11,52768,52768,11,52796,52796,11,52824,52824,11,52852,52852,11,52880,52880,11,52908,52908,11,52936,52936,11,52964,52964,11,52992,52992,11,53020,53020,11,53048,53048,11,53076,53076,11,53104,53104,11,53132,53132,11,53160,53160,11,53188,53188,11,53216,53216,11,53244,53244,11,53272,53272,11,53300,53300,11,53328,53328,11,53356,53356,11,53384,53384,11,53412,53412,11,53440,53440,11,53468,53468,11,53496,53496,11,53524,53524,11,53552,53552,11,53580,53580,11,53608,53608,11,53636,53636,11,53664,53664,11,53692,53692,11,53720,53720,11,53748,53748,11,53776,53776,11,53804,53804,11,53832,53832,11,53860,53860,11,53888,53888,11,53916,53916,11,53944,53944,11,53972,53972,11,54000,54000,11,54028,54028,11,54056,54056,11,54084,54084,11,54112,54112,11,54140,54140,11,54168,54168,11,54196,54196,11,54224,54224,11,54252,54252,11,54280,54280,11,54308,54308,11,54336,54336,11,54364,54364,11,54392,54392,11,54420,54420,11,54448,54448,11,54476,54476,11,54504,54504,11,54532,54532,11,54560,54560,11,54588,54588,11,54616,54616,11,54644,54644,11,54672,54672,11,54700,54700,11,54728,54728,11,54756,54756,11,54784,54784,11,54812,54812,11,54840,54840,11,54868,54868,11,54896,54896,11,54924,54924,11,54952,54952,11,54980,54980,11,55008,55008,11,55036,55036,11,55064,55064,11,55092,55092,11,55120,55120,11,55148,55148,11,55176,55176,11,55216,55238,9,64286,64286,5,65056,65071,5,65438,65439,5,65529,65531,4,66272,66272,5,68097,68099,5,68108,68111,5,68159,68159,5,68900,68903,5,69446,69456,5,69632,69632,7,69634,69634,7,69744,69744,5,69759,69761,5,69808,69810,7,69815,69816,7,69821,69821,1,69837,69837,1,69927,69931,5,69933,69940,5,70003,70003,5,70018,70018,7,70070,70078,5,70082,70083,1,70094,70094,7,70188,70190,7,70194,70195,7,70197,70197,7,70206,70206,5,70368,70370,7,70400,70401,5,70459,70460,5,70463,70463,7,70465,70468,7,70475,70477,7,70498,70499,7,70512,70516,5,70712,70719,5,70722,70724,5,70726,70726,5,70832,70832,5,70835,70840,5,70842,70842,5,70845,70845,5,70847,70848,5,70850,70851,5,71088,71089,7,71096,71099,7,71102,71102,7,71132,71133,5,71219,71226,5,71229,71229,5,71231,71232,5,71340,71340,7,71342,71343,7,71350,71350,7,71453,71455,5,71462,71462,7,71724,71726,7,71736,71736,7,71984,71984,5,71991,71992,7,71997,71997,7,71999,71999,1,72001,72001,1,72003,72003,5,72148,72151,5,72156,72159,7,72164,72164,7,72243,72248,5,72250,72250,1,72263,72263,5,72279,72280,7,72324,72329,1,72343,72343,7,72751,72751,7,72760,72765,5,72767,72767,5,72873,72873,7,72881,72881,7,72884,72884,7,73009,73014,5,73020,73021,5,73030,73030,1,73098,73102,7,73107,73108,7,73110,73110,7,73459,73460,5,78896,78904,4,92976,92982,5,94033,94087,7,94180,94180,5,113821,113822,5,118528,118573,5,119141,119141,5,119143,119145,5,119150,119154,5,119163,119170,5,119210,119213,5,121344,121398,5,121461,121461,5,121499,121503,5,122880,122886,5,122907,122913,5,122918,122922,5,123566,123566,5,125136,125142,5,126976,126979,14,126981,127182,14,127184,127231,14,127279,127279,14,127344,127345,14,127374,127374,14,127405,127461,14,127489,127490,14,127514,127514,14,127538,127546,14,127561,127567,14,127570,127743,14,127757,127758,14,127760,127760,14,127762,127762,14,127766,127768,14,127770,127770,14,127772,127772,14,127775,127776,14,127778,127779,14,127789,127791,14,127794,127795,14,127798,127798,14,127819,127819,14,127824,127824,14,127868,127868,14,127870,127871,14,127892,127893,14,127896,127896,14,127900,127901,14,127904,127940,14,127942,127942,14,127944,127944,14,127946,127946,14,127951,127955,14,127968,127971,14,127973,127984,14,127987,127987,14,127989,127989,14,127991,127991,14,127995,127999,5,128008,128008,14,128012,128014,14,128017,128018,14,128020,128020,14,128022,128022,14,128042,128042,14,128063,128063,14,128065,128065,14,128101,128101,14,128108,128109,14,128173,128173,14,128182,128183,14,128236,128237,14,128239,128239,14,128245,128245,14,128248,128248,14,128253,128253,14,128255,128258,14,128260,128263,14,128265,128265,14,128277,128277,14,128300,128301,14,128326,128328,14,128331,128334,14,128336,128347,14,128360,128366,14,128369,128370,14,128378,128378,14,128391,128391,14,128394,128397,14,128400,128400,14,128405,128406,14,128420,128420,14,128422,128423,14,128425,128432,14,128435,128443,14,128445,128449,14,128453,128464,14,128468,128475,14,128479,128480,14,128482,128482,14,128484,128487,14,128489,128494,14,128496,128498,14,128500,128505,14,128507,128511,14,128513,128518,14,128521,128525,14,128527,128527,14,128529,128529,14,128533,128533,14,128535,128535,14,128537,128537,14]');
1152 }
1153 > strings.ts
1154 > //#endregion
1155 >
1156 > /**
1157 > * Computes the offset after performing a left delete on the given string,
1158 > * while considering unicode grapheme/emoji rules.
1159 > */
1160 > export function getLeftDeleteOffset(offset: number, str: string): number {
1161 if (offset === 0) {
1162 return 0;
1174 return iterator.offset;
1175 }
1176 > strings.ts
1177 function getOffsetBeforeLastEmojiComponent(initialOffset: number, str: string): number | undefined {
1178 // See https://www.unicode.org/reports/tr51/tr51-14.html#EBNF_and_Regex for the
1210 return resultOffset;
1211 }
1212 > strings.ts
1213 function isEmojiModifier(codePoint: number): boolean {
1214 return 0x1F3FB <= codePoint && codePoint <= 0x1F3FF;
1215 }
1216 > strings.ts
1217 > const enum CodePoint {
1218 > zwj = 0x200D,
1219 >
1220 > /**
1221 > * Variation Selector-16 (VS16)
1222 > */
1223 > emojiVariantSelector = 0xFE0F,
1224 >
1225 > /**
1226 > * Combining Enclosing Keycap
1227 > */
1228 > enclosingKeyCap = 0x20E3,
1229 >
1230 > space = 0x0020,
1231 > }
1232 >
1233 > export const noBreakWhitespace = '\xa0';
1234 >
1235 > export class AmbiguousCharacters {
1236 > private static readonly ambiguousCharacterData = new Lazy<
1237 > Record<
1238 > string | '_common' | '_default',
1239 > /* code point -> ascii code point */ number[]
1240 > >
1241 > >(() => {
1242 // Generated using https://github.com/hediet/vscode-unicode-data
1243 // Stored as key1, value1, key2, value2, ...
1245 '{\"_common\":[8232,32,8233,32,5760,32,8192,32,8193,32,8194,32,8195,32,8196,32,8197,32,8198,32,8200,32,8201,32,8202,32,8287,32,8199,32,8239,32,2042,95,65101,95,65102,95,65103,95,8208,45,8209,45,8210,45,65112,45,1748,45,8259,45,727,45,8722,45,10134,45,11450,45,1549,44,1643,44,184,44,42233,44,894,59,2307,58,2691,58,1417,58,1795,58,1796,58,5868,58,65072,58,6147,58,6153,58,8282,58,1475,58,760,58,42889,58,8758,58,720,58,42237,58,451,33,11601,33,660,63,577,63,2429,63,5038,63,42731,63,119149,46,8228,46,1793,46,1794,46,42510,46,68176,46,1632,46,1776,46,42232,46,1373,96,65287,96,8219,96,1523,96,8242,96,1370,96,8175,96,65344,96,900,96,8189,96,8125,96,8127,96,8190,96,697,96,884,96,712,96,714,96,715,96,756,96,699,96,701,96,700,96,702,96,42892,96,1497,96,2036,96,2037,96,5194,96,5836,96,94033,96,94034,96,65339,91,10088,40,10098,40,12308,40,64830,40,65341,93,10089,41,10099,41,12309,41,64831,41,10100,123,119060,123,10101,125,65342,94,8270,42,1645,42,8727,42,66335,42,5941,47,8257,47,8725,47,8260,47,9585,47,10187,47,10744,47,119354,47,12755,47,12339,47,11462,47,20031,47,12035,47,65340,92,65128,92,8726,92,10189,92,10741,92,10745,92,119311,92,119355,92,12756,92,20022,92,12034,92,42872,38,708,94,710,94,5869,43,10133,43,66203,43,8249,60,10094,60,706,60,119350,60,5176,60,5810,60,5120,61,11840,61,12448,61,42239,61,8250,62,10095,62,707,62,119351,62,5171,62,94015,62,8275,126,732,126,8128,126,8764,126,65372,124,65293,45,118002,50,120784,50,120794,50,120804,50,120814,50,120824,50,130034,50,42842,50,423,50,1000,50,42564,50,5311,50,42735,50,119302,51,118003,51,120785,51,120795,51,120805,51,120815,51,120825,51,130035,51,42923,51,540,51,439,51,42858,51,11468,51,1248,51,94011,51,71882,51,118004,52,120786,52,120796,52,120806,52,120816,52,120826,52,130036,52,5070,52,71855,52,118005,53,120787,53,120797,53,120807,53,120817,53,120827,53,130037,53,444,53,71867,53,118006,54,120788,54,120798,54,120808,54,120818,54,120828,54,130038,54,11474,54,5102,54,71893,54,119314,55,118007,55,120789,55,120799,55,120809,55,120819,55,120829,55,130039,55,66770,55,71878,55,2819,56,2538,56,2666,56,125131,56,118008,56,120790,56,120800,56,120810,56,120820,56,120830,56,130040,56,547,56,546,56,66330,56,2663,57,2920,57,2541,57,3437,57,118009,57,120791,57,120801,57,120811,57,120821,57,120831,57,130041,57,42862,57,11466,57,71884,57,71852,57,71894,57,9082,97,65345,97,119834,97,119886,97,119938,97,119990,97,120042,97,120094,97,120146,97,120198,97,120250,97,120302,97,120354,97,120406,97,120458,97,593,97,945,97,120514,97,120572,97,120630,97,120688,97,120746,97,65313,65,117974,65,119808,65,119860,65,119912,65,119964,65,120016,65,120068,65,120120,65,120172,65,120224,65,120276,65,120328,65,120380,65,120432,65,913,65,120488,65,120546,65,120604,65,120662,65,120720,65,5034,65,5573,65,42222,65,94016,65,66208,65,119835,98,119887,98,119939,98,119991,98,120043,98,120095,98,120147,98,120199,98,120251,98,120303,98,120355,98,120407,98,120459,98,388,98,5071,98,5234,98,5551,98,65314,66,8492,66,117975,66,119809,66,119861,66,119913,66,120017,66,120069,66,120121,66,120173,66,120225,66,120277,66,120329,66,120381,66,120433,66,42932,66,914,66,120489,66,120547,66,120605,66,120663,66,120721,66,5108,66,5623,66,42192,66,66178,66,66209,66,66305,66,65347,99,8573,99,119836,99,119888,99,119940,99,119992,99,120044,99,120096,99,120148,99,120200,99,120252,99,120304,99,120356,99,120408,99,120460,99,7428,99,1010,99,11429,99,43951,99,66621,99,128844,67,71913,67,71922,67,65315,67,8557,67,8450,67,8493,67,117976,67,119810,67,119862,67,119914,67,119966,67,120018,67,120174,67,120226,67,120278,67,120330,67,120382,67,120434,67,1017,67,11428,67,5087,67,42202,67,66210,67,66306,67,66581,67,66844,67,8574,100,8518,100,119837,100,119889,100,119941,100,119993,100,120045,100,120097,100,120149,100,120201,100,120253,100,120305,100,120357,100,120409,100,120461,100,1281,100,5095,100,5231,100,42194,100,8558,68,8517,68,117977,68,119811,68,119863,68,119915,68,119967,68,120019,68,120071,68,120123,68,120175,68,120227,68,120279,68,120331,68,120383,68,120435,68,5024,68,5598,68,5610,68,42195,68,8494,101,65349,101,8495,101,8519,101,119838,101,119890,101,119942,101,120046,101,120098,101,120150,101,120202,101,120254,101,120306,101,120358,101,120410,101,120462,101,43826,101,1213,101,8959,69,65317,69,8496,69,117978,69,119812,69,119864,69,119916,69,120020,69,120072,69,120124,69,120176,69,120228,69,120280,69,120332,69,120384,69,120436,69,917,69,120492,69,120550,69,120608,69,120666,69,120724,69,11577,69,5036,69,42224,69,71846,69,71854,69,66182,69,119839,102,119891,102,119943,102,119995,102,120047,102,120099,102,120151,102,120203,102,120255,102,120307,102,120359,102,120411,102,120463,102,43829,102,42905,102,383,102,7837,102,1412,102,119315,70,8497,70,117979,70,119813,70,119865,70,119917,70,120021,70,120073,70,120125,70,120177,70,120229,70,120281,70,120333,70,120385,70,120437,70,42904,70,988,70,120778,70,5556,70,42205,70,71874,70,71842,70,66183,70,66213,70,66853,70,65351,103,8458,103,119840,103,119892,103,119944,103,120048,103,120100,103,120152,103,120204,103,120256,103,120308,103,120360,103,120412,103,120464,103,609,103,7555,103,397,103,1409,103,117980,71,119814,71,119866,71,119918,71,119970,71,120022,71,120074,71,120126,71,120178,71,120230,71,120282,71,120334,71,120386,71,120438,71,1292,71,5056,71,5107,71,42198,71,65352,104,8462,104,119841,104,119945,104,119997,104,120049,104,120101,104,120153,104,120205,104,120257,104,120309,104,120361,104,120413,104,120465,104,1211,104,1392,104,5058,104,65320,72,8459,72,8460,72,8461,72,117981,72,119815,72,119867,72,119919,72,120023,72,120179,72,120231,72,120283,72,120335,72,120387,72,120439,72,919,72,120494,72,120552,72,120610,72,120668,72,120726,72,11406,72,5051,72,5500,72,42215,72,66255,72,731,105,9075,105,65353,105,8560,105,8505,105,8520,105,119842,105,119894,105,119946,105,119998,105,120050,105,120102,105,120154,105,120206,105,120258,105,120310,105,120362,105,120414,105,120466,105,120484,105,618,105,617,105,953,105,8126,105,890,105,120522,105,120580,105,120638,105,120696,105,120754,105,1110,105,42567,105,1231,105,43893,105,5029,105,71875,105,65354,106,8521,106,119843,106,119895,106,119947,106,119999,106,120051,106,120103,106,120155,106,120207,106,120259,106,120311,106,120363,106,120415,106,120467,106,1011,106,1112,106,65322,74,117983,74,119817,74,119869,74,119921,74,119973,74,120025,74,120077,74,120129,74,120181,74,120233,74,120285,74,120337,74,120389,74,120441,74,42930,74,895,74,1032,74,5035,74,5261,74,42201,74,119844,107,119896,107,119948,107,120000,107,120052,107,120104,107,120156,107,120208,107,120260,107,120312,107,120364,107,120416,107,120468,107,8490,75,65323,75,117984,75,119818,75,119870,75,119922,75,119974,75,120026,75,120078,75,120130,75,120182,75,120234,75,120286,75,120338,75,120390,75,120442,75,922,75,120497,75,120555,75,120613,75,120671,75,120729,75,11412,75,5094,75,5845,75,42199,75,66840,75,1472,108,8739,73,9213,73,65512,73,1633,108,1777,73,66336,108,125127,108,118001,108,120783,73,120793,73,120803,73,120813,73,120823,73,130033,73,65321,73,8544,73,8464,73,8465,73,117982,108,119816,73,119868,73,119920,73,120024,73,120128,73,120180,73,120232,73,120284,73,120336,73,120388,73,120440,73,65356,108,8572,73,8467,108,119845,108,119897,108,119949,108,120001,108,120053,108,120105,73,120157,73,120209,73,120261,73,120313,73,120365,73,120417,73,120469,73,448,73,120496,73,120554,73,120612,73,120670,73,120728,73,11410,73,1030,73,1216,73,1493,108,1503,108,1575,108,126464,108,126592,108,65166,108,65165,108,1994,108,11599,73,5825,73,42226,73,93992,73,66186,124,66313,124,119338,76,8556,76,8466,76,117985,76,119819,76,119871,76,119923,76,120027,76,120079,76,120131,76,120183,76,120235,76,120287,76,120339,76,120391,76,120443,76,11472,76,5086,76,5290,76,42209,76,93974,76,71843,76,71858,76,66587,76,66854,76,65325,77,8559,77,8499,77,117986,77,119820,77,119872,77,119924,77,120028,77,120080,77,120132,77,120184,77,120236,77,120288,77,120340,77,120392,77,120444,77,924,77,120499,77,120557,77,120615,77,120673,77,120731,77,1018,77,11416,77,5047,77,5616,77,5846,77,42207,77,66224,77,66321,77,119847,110,119899,110,119951,110,120003,110,120055,110,120107,110,120159,110,120211,110,120263,110,120315,110,120367,110,120419,110,120471,110,1400,110,1404,110,65326,78,8469,78,117987,78,119821,78,119873,78,119925,78,119977,78,120029,78,120081,78,120185,78,120237,78,120289,78,120341,78,120393,78,120445,78,925,78,120500,78,120558,78,120616,78,120674,78,120732,78,11418,78,42208,78,66835,78,3074,111,3202,111,3330,111,3458,111,2406,111,2662,111,2790,111,3046,111,3174,111,3302,111,3430,111,3664,111,3792,111,4160,111,1637,111,1781,111,65359,111,8500,111,119848,111,119900,111,119952,111,120056,111,120108,111,120160,111,120212,111,120264,111,120316,111,120368,111,120420,111,120472,111,7439,111,7441,111,43837,111,959,111,120528,111,120586,111,120644,111,120702,111,120760,111,963,111,120532,111,120590,111,120648,111,120706,111,120764,111,11423,111,4351,111,1413,111,1505,111,1607,111,126500,111,126564,111,126596,111,65259,111,65260,111,65258,111,65257,111,1726,111,64428,111,64429,111,64427,111,64426,111,1729,111,64424,111,64425,111,64423,111,64422,111,1749,111,3360,111,4125,111,66794,111,71880,111,71895,111,66604,111,1984,79,2534,79,2918,79,12295,79,70864,79,71904,79,118000,79,120782,79,120792,79,120802,79,120812,79,120822,79,130032,79,65327,79,117988,79,119822,79,119874,79,119926,79,119978,79,120030,79,120082,79,120134,79,120186,79,120238,79,120290,79,120342,79,120394,79,120446,79,927,79,120502,79,120560,79,120618,79,120676,79,120734,79,11422,79,1365,79,11604,79,4816,79,2848,79,66754,79,42227,79,71861,79,66194,79,66219,79,66564,79,66838,79,9076,112,65360,112,119849,112,119901,112,119953,112,120005,112,120057,112,120109,112,120161,112,120213,112,120265,112,120317,112,120369,112,120421,112,120473,112,961,112,120530,112,120544,112,120588,112,120602,112,120646,112,120660,112,120704,112,120718,112,120762,112,120776,112,11427,112,65328,80,8473,80,117989,80,119823,80,119875,80,119927,80,119979,80,120031,80,120083,80,120187,80,120239,80,120291,80,120343,80,120395,80,120447,80,929,80,120504,80,120562,80,120620,80,120678,80,120736,80,11426,80,5090,80,5229,80,42193,80,66197,80,119850,113,119902,113,119954,113,120006,113,120058,113,120110,113,120162,113,120214,113,120266,113,120318,113,120370,113,120422,113,120474,113,1307,113,1379,113,1382,113,8474,81,117990,81,119824,81,119876,81,119928,81,119980,81,120032,81,120084,81,120188,81,120240,81,120292,81,120344,81,120396,81,120448,81,11605,81,119851,114,119903,114,119955,114,120007,114,120059,114,120111,114,120163,114,120215,114,120267,114,120319,114,120371,114,120423,114,120475,114,43847,114,43848,114,7462,114,11397,114,43905,114,119318,82,8475,82,8476,82,8477,82,117991,82,119825,82,119877,82,119929,82,120033,82,120189,82,120241,82,120293,82,120345,82,120397,82,120449,82,422,82,5025,82,5074,82,66740,82,5511,82,42211,82,94005,82,65363,115,119852,115,119904,115,119956,115,120008,115,120060,115,120112,115,120164,115,120216,115,120268,115,120320,115,120372,115,120424,115,120476,115,42801,115,445,115,1109,115,43946,115,71873,115,66632,115,65331,83,117992,83,119826,83,119878,83,119930,83,119982,83,120034,83,120086,83,120138,83,120190,83,120242,83,120294,83,120346,83,120398,83,120450,83,1029,83,1359,83,5077,83,5082,83,42210,83,94010,83,66198,83,66592,83,119853,116,119905,116,119957,116,120009,116,120061,116,120113,116,120165,116,120217,116,120269,116,120321,116,120373,116,120425,116,120477,116,8868,84,10201,84,128872,84,65332,84,117993,84,119827,84,119879,84,119931,84,119983,84,120035,84,120087,84,120139,84,120191,84,120243,84,120295,84,120347,84,120399,84,120451,84,932,84,120507,84,120565,84,120623,84,120681,84,120739,84,11430,84,5026,84,42196,84,93962,84,71868,84,66199,84,66225,84,66325,84,119854,117,119906,117,119958,117,120010,117,120062,117,120114,117,120166,117,120218,117,120270,117,120322,117,120374,117,120426,117,120478,117,42911,117,7452,117,43854,117,43858,117,651,117,965,117,120534,117,120592,117,120650,117,120708,117,120766,117,1405,117,66806,117,71896,117,8746,85,8899,85,117994,85,119828,85,119880,85,119932,85,119984,85,120036,85,120088,85,120140,85,120192,85,120244,85,120296,85,120348,85,120400,85,120452,85,1357,85,4608,85,66766,85,5196,85,42228,85,94018,85,71864,85,8744,118,8897,118,65366,118,8564,118,119855,118,119907,118,119959,118,120011,118,120063,118,120115,118,120167,118,120219,118,120271,118,120323,118,120375,118,120427,118,120479,118,7456,118,957,118,120526,118,120584,118,120642,118,120700,118,120758,118,1141,118,1496,118,71430,118,43945,118,71872,118,119309,86,1639,86,1783,86,8548,86,117995,86,119829,86,119881,86,119933,86,119985,86,120037,86,120089,86,120141,86,120193,86,120245,86,120297,86,120349,86,120401,86,120453,86,1140,86,11576,86,5081,86,5167,86,42719,86,42214,86,93960,86,71840,86,66845,86,623,119,119856,119,119908,119,119960,119,120012,119,120064,119,120116,119,120168,119,120220,119,120272,119,120324,119,120376,119,120428,119,120480,119,7457,119,1121,119,1309,119,1377,119,71434,119,71438,119,71439,119,43907,119,71910,87,71919,87,117996,87,119830,87,119882,87,119934,87,119986,87,120038,87,120090,87,120142,87,120194,87,120246,87,120298,87,120350,87,120402,87,120454,87,1308,87,5043,87,5076,87,42218,87,5742,120,10539,120,10540,120,10799,120,65368,120,8569,120,119857,120,119909,120,119961,120,120013,120,120065,120,120117,120,120169,120,120221,120,120273,120,120325,120,120377,120,120429,120,120481,120,5441,120,5501,120,5741,88,9587,88,66338,88,71916,88,65336,88,8553,88,117997,88,119831,88,119883,88,119935,88,119987,88,120039,88,120091,88,120143,88,120195,88,120247,88,120299,88,120351,88,120403,88,120455,88,42931,88,935,88,120510,88,120568,88,120626,88,120684,88,120742,88,11436,88,11613,88,5815,88,42219,88,66192,88,66228,88,66327,88,66855,88,611,121,7564,121,65369,121,119858,121,119910,121,119962,121,120014,121,120066,121,120118,121,120170,121,120222,121,120274,121,120326,121,120378,121,120430,121,120482,121,655,121,7935,121,43866,121,947,121,8509,121,120516,121,120574,121,120632,121,120690,121,120748,121,1199,121,4327,121,71900,121,65337,89,117998,89,119832,89,119884,89,119936,89,119988,89,120040,89,120092,89,120144,89,120196,89,120248,89,120300,89,120352,89,120404,89,120456,89,933,89,978,89,120508,89,120566,89,120624,89,120682,89,120740,89,11432,89,1198,89,5033,89,5053,89,42220,89,94019,89,71844,89,66226,89,119859,122,119911,122,119963,122,120015,122,120067,122,120119,122,120171,122,120223,122,120275,122,120327,122,120379,122,120431,122,120483,122,7458,122,43923,122,71876,122,71909,90,66293,90,65338,90,8484,90,8488,90,117999,90,119833,90,119885,90,119937,90,119989,90,120041,90,120197,90,120249,90,120301,90,120353,90,120405,90,120457,90,918,90,120493,90,120551,90,120609,90,120667,90,120725,90,5059,90,42204,90,71849,90,65282,34,65283,35,65284,36,65285,37,65286,38,65290,42,65291,43,65294,46,65295,47,65296,48,65298,50,65299,51,65300,52,65301,53,65302,54,65303,55,65304,56,65305,57,65308,60,65309,61,65310,62,65312,64,65316,68,65318,70,65319,71,65324,76,65329,81,65330,82,65333,85,65334,86,65335,87,65343,95,65346,98,65348,100,65350,102,65355,107,65357,109,65358,110,65361,113,65362,114,65364,116,65365,117,65367,119,65370,122,65371,123,65373,125,119846,109],\"_default\":[160,32,8211,45,65374,126,8218,44,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"cs\":[65374,126,8218,44,65306,58,65281,33,8216,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"de\":[65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"es\":[8211,45,65374,126,8218,44,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"fr\":[65374,126,8218,44,65306,58,65281,33,8216,96,8245,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"it\":[160,32,8211,45,65374,126,8218,44,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"ja\":[8211,45,8218,44,65281,33,8216,96,8245,96,180,96,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65292,44,65297,49,65307,59],\"ko\":[8211,45,65374,126,8218,44,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"pl\":[65374,126,65306,58,65281,33,8216,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"pt-BR\":[65374,126,8218,44,65306,58,65281,33,8216,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"qps-ploc\":[160,32,8211,45,65374,126,8218,44,65306,58,65281,33,8216,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"ru\":[65374,126,8218,44,65306,58,65281,33,8216,96,8245,96,180,96,12494,47,305,105,921,73,1009,112,215,120,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"tr\":[160,32,8211,45,65374,126,8218,44,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41,65292,44,65297,49,65307,59,65311,63],\"zh-hans\":[160,32,65374,126,8218,44,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65297,49],\"zh-hant\":[8211,45,65374,126,8218,44,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89]}'
1246 );
1247 > }); strings.ts
1248 >
1249 > private static readonly cache = new LRUCachedFunction<string, AmbiguousCharacters>((localesStr) => {
1250 const locales = localesStr.split(',');
1251
1304
1305 return new AmbiguousCharacters(map);
1306 > }); strings.ts
1307 >
1308 > public static getInstance(locales: Iterable<string>): AmbiguousCharacters {
1309 return AmbiguousCharacters.cache.get(Array.from(locales).join(','));
1310 }
1311 > strings.ts
1312 > private static _locales = new Lazy<string[]>(() =>
1313 Object.keys(AmbiguousCharacters.ambiguousCharacterData.value).filter(
1314 (k) => !k.startsWith('_')
1315 )
1316 > ); strings.ts
1317 > public static getLocales(): string[] {
1318 return AmbiguousCharacters._locales.value;
1319 }
1320 > strings.ts
1321 > private constructor(
1322 private readonly confusableDictionary: Map<number, number>
1323 ) { }
1324 > strings.ts
1325 > public isAmbiguous(codePoint: number): boolean {
1326 return this.confusableDictionary.has(codePoint);
1327 }
1328 > strings.ts
1329 > public containsAmbiguousCharacter(str: string): boolean {
1330 for (let i = 0; i < str.length; i++) {
1331 const codePoint = str.codePointAt(i);
1336 return false;
1337 }
1338 > strings.ts
1339 > /**
1340 > * Returns the non basic ASCII code point that the given code point can be confused,
1341 > * or undefined if such code point does note exist.
1342 > */
1343 > public getPrimaryConfusable(codePoint: number): number | undefined {
1344 return this.confusableDictionary.get(codePoint);
1345 }
1346 > strings.ts
1347 > public getConfusableCodePoints(): ReadonlySet<number> {
1348 return new Set(this.confusableDictionary.keys());
1349 }
1350 > } strings.ts
1351 >
1352 > export class InvisibleCharacters {
1353 > private static getRawData(): Record<string | '_common', number[]> {
1354 // Generated using https://github.com/hediet/vscode-unicode-data
1355 return JSON.parse('{\"_common\":[11,12,13,127,847,1564,4447,4448,6068,6069,6155,6156,6157,6158,7355,7356,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8204,8205,8206,8207,8234,8235,8236,8237,8238,8239,8287,8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,10240,12644,65024,65025,65026,65027,65028,65029,65030,65031,65032,65033,65034,65035,65036,65037,65038,65039,65279,65440,65520,65521,65522,65523,65524,65525,65526,65527,65528,65532,78844,119155,119156,119157,119158,119159,119160,119161,119162,917504,917505,917506,917507,917508,917509,917510,917511,917512,917513,917514,917515,917516,917517,917518,917519,917520,917521,917522,917523,917524,917525,917526,917527,917528,917529,917530,917531,917532,917533,917534,917535,917536,917537,917538,917539,917540,917541,917542,917543,917544,917545,917546,917547,917548,917549,917550,917551,917552,917553,917554,917555,917556,917557,917558,917559,917560,917561,917562,917563,917564,917565,917566,917567,917568,917569,917570,917571,917572,917573,917574,917575,917576,917577,917578,917579,917580,917581,917582,917583,917584,917585,917586,917587,917588,917589,917590,917591,917592,917593,917594,917595,917596,917597,917598,917599,917600,917601,917602,917603,917604,917605,917606,917607,917608,917609,917610,917611,917612,917613,917614,917615,917616,917617,917618,917619,917620,917621,917622,917623,917624,917625,917626,917627,917628,917629,917630,917631,917760,917761,917762,917763,917764,917765,917766,917767,917768,917769,917770,917771,917772,917773,917774,917775,917776,917777,917778,917779,917780,917781,917782,917783,917784,917785,917786,917787,917788,917789,917790,917791,917792,917793,917794,917795,917796,917797,917798,917799,917800,917801,917802,917803,917804,917805,917806,917807,917808,917809,917810,917811,917812,917813,917814,917815,917816,917817,917818,917819,917820,917821,917822,917823,917824,917825,917826,917827,917828,917829,917830,917831,917832,917833,917834,917835,917836,917837,917838,917839,917840,917841,917842,917843,917844,917845,917846,917847,917848,917849,917850,917851,917852,917853,917854,917855,917856,917857,917858,917859,917860,917861,917862,917863,917864,917865,917866,917867,917868,917869,917870,917871,917872,917873,917874,917875,917876,917877,917878,917879,917880,917881,917882,917883,917884,917885,917886,917887,917888,917889,917890,917891,917892,917893,917894,917895,917896,917897,917898,917899,917900,917901,917902,917903,917904,917905,917906,917907,917908,917909,917910,917911,917912,917913,917914,917915,917916,917917,917918,917919,917920,917921,917922,917923,917924,917925,917926,917927,917928,917929,917930,917931,917932,917933,917934,917935,917936,917937,917938,917939,917940,917941,917942,917943,917944,917945,917946,917947,917948,917949,917950,917951,917952,917953,917954,917955,917956,917957,917958,917959,917960,917961,917962,917963,917964,917965,917966,917967,917968,917969,917970,917971,917972,917973,917974,917975,917976,917977,917978,917979,917980,917981,917982,917983,917984,917985,917986,917987,917988,917989,917990,917991,917992,917993,917994,917995,917996,917997,917998,917999],\"cs\":[173,8203,12288],\"de\":[173,8203,12288],\"es\":[8203,12288],\"fr\":[173,8203,12288],\"it\":[160,173,12288],\"ja\":[173],\"ko\":[173,12288],\"pl\":[173,8203,12288],\"pt-BR\":[173,8203,12288],\"qps-ploc\":[160,173,8203,12288],\"ru\":[173,12288],\"tr\":[160,173,8203,12288],\"zh-hans\":[160,173,8203,12288],\"zh-hant\":[173,12288]}');
1356 }
1357 > strings.ts
1358 > private static _data: Set<number> | undefined = undefined;
1359 >
1360 > private static getData() {
1361 if (!this._data) {
1362 this._data = new Set([...Object.values(InvisibleCharacters.getRawData())].flat());
1364 return this._data;
1365 }
1366 > strings.ts
1367 > public static isInvisibleCharacter(codePoint: number): boolean {
1368 return InvisibleCharacters.getData().has(codePoint);
1369 }
1370 > strings.ts
1371 > public static containsInvisibleCharacter(str: string): boolean {
1372 for (let i = 0; i < str.length; i++) {
1373 const codePoint = str.codePointAt(i);
1378 return false;
1379 }
1380 > strings.ts
1381 > public static get codePoints(): ReadonlySet<number> {
1382 return InvisibleCharacters.getData();
1383 }
1384 > } strings.ts
1385 >
1386 > export const Ellipsis = '\u2026';
1387 >
1388 > /**
1389 > * Convert a Unicode string to a string in which each 16-bit unit occupies only one byte
1390 > *
1391 > * From https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa
1392 > */
1393 function toBinary(str: string): string {
1394 const codeUnits = new Uint16Array(str.length);
1403 return binary;
1404 }
1405 > strings.ts
1406 > /**
1407 > * Version of the global `btoa` function that handles multi-byte characters instead
1408 > * of throwing an exception.
1409 > */
1410 >
1411 > export function multibyteAwareBtoa(str: string): string {
1412 return btoa(toBinary(str));
1413 }
src/vs/base/common/charCode.ts 450 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- charCode.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // Names from https://blog.codinghorror.com/ascii-pronunciation-rules-for-programmers/
7 >
8 > /**
9 > * An inlined enum containing useful character codes (to be used with String.charCodeAt).
10 > * Please leave the const keyword such that it gets inlined when compiled to JavaScript!
11 > */
12 > export const enum CharCode {
13 > Null = 0,
14 > /**
15 > * The `\b` character.
16 > */
17 > Backspace = 8,
18 > /**
19 > * The `\t` character.
20 > */
21 > Tab = 9,
22 > /**
23 > * The `\n` character.
24 > */
25 > LineFeed = 10,
26 > /**
27 > * The `\r` character.
28 > */
29 > CarriageReturn = 13,
30 > Space = 32,
31 > /**
32 > * The `!` character.
33 > */
34 > ExclamationMark = 33,
35 > /**
36 > * The `"` character.
37 > */
38 > DoubleQuote = 34,
39 > /**
40 > * The `#` character.
41 > */
42 > Hash = 35,
43 > /**
44 > * The `$` character.
45 > */
46 > DollarSign = 36,
47 > /**
48 > * The `%` character.
49 > */
50 > PercentSign = 37,
51 > /**
52 > * The `&` character.
53 > */
54 > Ampersand = 38,
55 > /**
56 > * The `'` character.
57 > */
58 > SingleQuote = 39,
59 > /**
60 > * The `(` character.
61 > */
62 > OpenParen = 40,
63 > /**
64 > * The `)` character.
65 > */
66 > CloseParen = 41,
67 > /**
68 > * The `*` character.
69 > */
70 > Asterisk = 42,
71 > /**
72 > * The `+` character.
73 > */
74 > Plus = 43,
75 > /**
76 > * The `,` character.
77 > */
78 > Comma = 44,
79 > /**
80 > * The `-` character.
81 > */
82 > Dash = 45,
83 > /**
84 > * The `.` character.
85 > */
86 > Period = 46,
87 > /**
88 > * The `/` character.
89 > */
90 > Slash = 47,
91 >
92 > Digit0 = 48,
93 > Digit1 = 49,
94 > Digit2 = 50,
95 > Digit3 = 51,
96 > Digit4 = 52,
97 > Digit5 = 53,
98 > Digit6 = 54,
99 > Digit7 = 55,
100 > Digit8 = 56,
101 > Digit9 = 57,
102 >
103 > /**
104 > * The `:` character.
105 > */
106 > Colon = 58,
107 > /**
108 > * The `;` character.
109 > */
110 > Semicolon = 59,
111 > /**
112 > * The `<` character.
113 > */
114 > LessThan = 60,
115 > /**
116 > * The `=` character.
117 > */
118 > Equals = 61,
119 > /**
120 > * The `>` character.
121 > */
122 > GreaterThan = 62,
123 > /**
124 > * The `?` character.
125 > */
126 > QuestionMark = 63,
127 > /**
128 > * The `@` character.
129 > */
130 > AtSign = 64,
131 >
132 > A = 65,
133 > B = 66,
134 > C = 67,
135 > D = 68,
136 > E = 69,
137 > F = 70,
138 > G = 71,
139 > H = 72,
140 > I = 73,
141 > J = 74,
142 > K = 75,
143 > L = 76,
144 > M = 77,
145 > N = 78,
146 > O = 79,
147 > P = 80,
148 > Q = 81,
149 > R = 82,
150 > S = 83,
151 > T = 84,
152 > U = 85,
153 > V = 86,
154 > W = 87,
155 > X = 88,
156 > Y = 89,
157 > Z = 90,
158 >
159 > /**
160 > * The `[` character.
161 > */
162 > OpenSquareBracket = 91,
163 > /**
164 > * The `\` character.
165 > */
166 > Backslash = 92,
167 > /**
168 > * The `]` character.
169 > */
170 > CloseSquareBracket = 93,
171 > /**
172 > * The `^` character.
173 > */
174 > Caret = 94,
175 > /**
176 > * The `_` character.
177 > */
178 > Underline = 95,
179 > /**
180 > * The ``(`)`` character.
181 > */
182 > BackTick = 96,
183 >
184 > a = 97,
185 > b = 98,
186 > c = 99,
187 > d = 100,
188 > e = 101,
189 > f = 102,
190 > g = 103,
191 > h = 104,
192 > i = 105,
193 > j = 106,
194 > k = 107,
195 > l = 108,
196 > m = 109,
197 > n = 110,
198 > o = 111,
199 > p = 112,
200 > q = 113,
201 > r = 114,
202 > s = 115,
203 > t = 116,
204 > u = 117,
205 > v = 118,
206 > w = 119,
207 > x = 120,
208 > y = 121,
209 > z = 122,
210 >
211 > /**
212 > * The `{` character.
213 > */
214 > OpenCurlyBrace = 123,
215 > /**
216 > * The `|` character.
217 > */
218 > Pipe = 124,
219 > /**
220 > * The `}` character.
221 > */
222 > CloseCurlyBrace = 125,
223 > /**
224 > * The `~` character.
225 > */
226 > Tilde = 126,
227 >
228 > /**
229 > * The &nbsp; (no-break space) character.
230 > * Unicode Character 'NO-BREAK SPACE' (U+00A0)
231 > */
232 > NoBreakSpace = 160,
233 >
234 > U_Combining_Grave_Accent = 0x0300, // U+0300 Combining Grave Accent
235 > U_Combining_Acute_Accent = 0x0301, // U+0301 Combining Acute Accent
236 > U_Combining_Circumflex_Accent = 0x0302, // U+0302 Combining Circumflex Accent
237 > U_Combining_Tilde = 0x0303, // U+0303 Combining Tilde
238 > U_Combining_Macron = 0x0304, // U+0304 Combining Macron
239 > U_Combining_Overline = 0x0305, // U+0305 Combining Overline
240 > U_Combining_Breve = 0x0306, // U+0306 Combining Breve
241 > U_Combining_Dot_Above = 0x0307, // U+0307 Combining Dot Above
242 > U_Combining_Diaeresis = 0x0308, // U+0308 Combining Diaeresis
243 > U_Combining_Hook_Above = 0x0309, // U+0309 Combining Hook Above
244 > U_Combining_Ring_Above = 0x030A, // U+030A Combining Ring Above
245 > U_Combining_Double_Acute_Accent = 0x030B, // U+030B Combining Double Acute Accent
246 > U_Combining_Caron = 0x030C, // U+030C Combining Caron
247 > U_Combining_Vertical_Line_Above = 0x030D, // U+030D Combining Vertical Line Above
248 > U_Combining_Double_Vertical_Line_Above = 0x030E, // U+030E Combining Double Vertical Line Above
249 > U_Combining_Double_Grave_Accent = 0x030F, // U+030F Combining Double Grave Accent
250 > U_Combining_Candrabindu = 0x0310, // U+0310 Combining Candrabindu
251 > U_Combining_Inverted_Breve = 0x0311, // U+0311 Combining Inverted Breve
252 > U_Combining_Turned_Comma_Above = 0x0312, // U+0312 Combining Turned Comma Above
253 > U_Combining_Comma_Above = 0x0313, // U+0313 Combining Comma Above
254 > U_Combining_Reversed_Comma_Above = 0x0314, // U+0314 Combining Reversed Comma Above
255 > U_Combining_Comma_Above_Right = 0x0315, // U+0315 Combining Comma Above Right
256 > U_Combining_Grave_Accent_Below = 0x0316, // U+0316 Combining Grave Accent Below
257 > U_Combining_Acute_Accent_Below = 0x0317, // U+0317 Combining Acute Accent Below
258 > U_Combining_Left_Tack_Below = 0x0318, // U+0318 Combining Left Tack Below
259 > U_Combining_Right_Tack_Below = 0x0319, // U+0319 Combining Right Tack Below
260 > U_Combining_Left_Angle_Above = 0x031A, // U+031A Combining Left Angle Above
261 > U_Combining_Horn = 0x031B, // U+031B Combining Horn
262 > U_Combining_Left_Half_Ring_Below = 0x031C, // U+031C Combining Left Half Ring Below
263 > U_Combining_Up_Tack_Below = 0x031D, // U+031D Combining Up Tack Below
264 > U_Combining_Down_Tack_Below = 0x031E, // U+031E Combining Down Tack Below
265 > U_Combining_Plus_Sign_Below = 0x031F, // U+031F Combining Plus Sign Below
266 > U_Combining_Minus_Sign_Below = 0x0320, // U+0320 Combining Minus Sign Below
267 > U_Combining_Palatalized_Hook_Below = 0x0321, // U+0321 Combining Palatalized Hook Below
268 > U_Combining_Retroflex_Hook_Below = 0x0322, // U+0322 Combining Retroflex Hook Below
269 > U_Combining_Dot_Below = 0x0323, // U+0323 Combining Dot Below
270 > U_Combining_Diaeresis_Below = 0x0324, // U+0324 Combining Diaeresis Below
271 > U_Combining_Ring_Below = 0x0325, // U+0325 Combining Ring Below
272 > U_Combining_Comma_Below = 0x0326, // U+0326 Combining Comma Below
273 > U_Combining_Cedilla = 0x0327, // U+0327 Combining Cedilla
274 > U_Combining_Ogonek = 0x0328, // U+0328 Combining Ogonek
275 > U_Combining_Vertical_Line_Below = 0x0329, // U+0329 Combining Vertical Line Below
276 > U_Combining_Bridge_Below = 0x032A, // U+032A Combining Bridge Below
277 > U_Combining_Inverted_Double_Arch_Below = 0x032B, // U+032B Combining Inverted Double Arch Below
278 > U_Combining_Caron_Below = 0x032C, // U+032C Combining Caron Below
279 > U_Combining_Circumflex_Accent_Below = 0x032D, // U+032D Combining Circumflex Accent Below
280 > U_Combining_Breve_Below = 0x032E, // U+032E Combining Breve Below
281 > U_Combining_Inverted_Breve_Below = 0x032F, // U+032F Combining Inverted Breve Below
282 > U_Combining_Tilde_Below = 0x0330, // U+0330 Combining Tilde Below
283 > U_Combining_Macron_Below = 0x0331, // U+0331 Combining Macron Below
284 > U_Combining_Low_Line = 0x0332, // U+0332 Combining Low Line
285 > U_Combining_Double_Low_Line = 0x0333, // U+0333 Combining Double Low Line
286 > U_Combining_Tilde_Overlay = 0x0334, // U+0334 Combining Tilde Overlay
287 > U_Combining_Short_Stroke_Overlay = 0x0335, // U+0335 Combining Short Stroke Overlay
288 > U_Combining_Long_Stroke_Overlay = 0x0336, // U+0336 Combining Long Stroke Overlay
289 > U_Combining_Short_Solidus_Overlay = 0x0337, // U+0337 Combining Short Solidus Overlay
290 > U_Combining_Long_Solidus_Overlay = 0x0338, // U+0338 Combining Long Solidus Overlay
291 > U_Combining_Right_Half_Ring_Below = 0x0339, // U+0339 Combining Right Half Ring Below
292 > U_Combining_Inverted_Bridge_Below = 0x033A, // U+033A Combining Inverted Bridge Below
293 > U_Combining_Square_Below = 0x033B, // U+033B Combining Square Below
294 > U_Combining_Seagull_Below = 0x033C, // U+033C Combining Seagull Below
295 > U_Combining_X_Above = 0x033D, // U+033D Combining X Above
296 > U_Combining_Vertical_Tilde = 0x033E, // U+033E Combining Vertical Tilde
297 > U_Combining_Double_Overline = 0x033F, // U+033F Combining Double Overline
298 > U_Combining_Grave_Tone_Mark = 0x0340, // U+0340 Combining Grave Tone Mark
299 > U_Combining_Acute_Tone_Mark = 0x0341, // U+0341 Combining Acute Tone Mark
300 > U_Combining_Greek_Perispomeni = 0x0342, // U+0342 Combining Greek Perispomeni
301 > U_Combining_Greek_Koronis = 0x0343, // U+0343 Combining Greek Koronis
302 > U_Combining_Greek_Dialytika_Tonos = 0x0344, // U+0344 Combining Greek Dialytika Tonos
303 > U_Combining_Greek_Ypogegrammeni = 0x0345, // U+0345 Combining Greek Ypogegrammeni
304 > U_Combining_Bridge_Above = 0x0346, // U+0346 Combining Bridge Above
305 > U_Combining_Equals_Sign_Below = 0x0347, // U+0347 Combining Equals Sign Below
306 > U_Combining_Double_Vertical_Line_Below = 0x0348, // U+0348 Combining Double Vertical Line Below
307 > U_Combining_Left_Angle_Below = 0x0349, // U+0349 Combining Left Angle Below
308 > U_Combining_Not_Tilde_Above = 0x034A, // U+034A Combining Not Tilde Above
309 > U_Combining_Homothetic_Above = 0x034B, // U+034B Combining Homothetic Above
310 > U_Combining_Almost_Equal_To_Above = 0x034C, // U+034C Combining Almost Equal To Above
311 > U_Combining_Left_Right_Arrow_Below = 0x034D, // U+034D Combining Left Right Arrow Below
312 > U_Combining_Upwards_Arrow_Below = 0x034E, // U+034E Combining Upwards Arrow Below
313 > U_Combining_Grapheme_Joiner = 0x034F, // U+034F Combining Grapheme Joiner
314 > U_Combining_Right_Arrowhead_Above = 0x0350, // U+0350 Combining Right Arrowhead Above
315 > U_Combining_Left_Half_Ring_Above = 0x0351, // U+0351 Combining Left Half Ring Above
316 > U_Combining_Fermata = 0x0352, // U+0352 Combining Fermata
317 > U_Combining_X_Below = 0x0353, // U+0353 Combining X Below
318 > U_Combining_Left_Arrowhead_Below = 0x0354, // U+0354 Combining Left Arrowhead Below
319 > U_Combining_Right_Arrowhead_Below = 0x0355, // U+0355 Combining Right Arrowhead Below
320 > U_Combining_Right_Arrowhead_And_Up_Arrowhead_Below = 0x0356, // U+0356 Combining Right Arrowhead And Up Arrowhead Below
321 > U_Combining_Right_Half_Ring_Above = 0x0357, // U+0357 Combining Right Half Ring Above
322 > U_Combining_Dot_Above_Right = 0x0358, // U+0358 Combining Dot Above Right
323 > U_Combining_Asterisk_Below = 0x0359, // U+0359 Combining Asterisk Below
324 > U_Combining_Double_Ring_Below = 0x035A, // U+035A Combining Double Ring Below
325 > U_Combining_Zigzag_Above = 0x035B, // U+035B Combining Zigzag Above
326 > U_Combining_Double_Breve_Below = 0x035C, // U+035C Combining Double Breve Below
327 > U_Combining_Double_Breve = 0x035D, // U+035D Combining Double Breve
328 > U_Combining_Double_Macron = 0x035E, // U+035E Combining Double Macron
329 > U_Combining_Double_Macron_Below = 0x035F, // U+035F Combining Double Macron Below
330 > U_Combining_Double_Tilde = 0x0360, // U+0360 Combining Double Tilde
331 > U_Combining_Double_Inverted_Breve = 0x0361, // U+0361 Combining Double Inverted Breve
332 > U_Combining_Double_Rightwards_Arrow_Below = 0x0362, // U+0362 Combining Double Rightwards Arrow Below
333 > U_Combining_Latin_Small_Letter_A = 0x0363, // U+0363 Combining Latin Small Letter A
334 > U_Combining_Latin_Small_Letter_E = 0x0364, // U+0364 Combining Latin Small Letter E
335 > U_Combining_Latin_Small_Letter_I = 0x0365, // U+0365 Combining Latin Small Letter I
336 > U_Combining_Latin_Small_Letter_O = 0x0366, // U+0366 Combining Latin Small Letter O
337 > U_Combining_Latin_Small_Letter_U = 0x0367, // U+0367 Combining Latin Small Letter U
338 > U_Combining_Latin_Small_Letter_C = 0x0368, // U+0368 Combining Latin Small Letter C
339 > U_Combining_Latin_Small_Letter_D = 0x0369, // U+0369 Combining Latin Small Letter D
340 > U_Combining_Latin_Small_Letter_H = 0x036A, // U+036A Combining Latin Small Letter H
341 > U_Combining_Latin_Small_Letter_M = 0x036B, // U+036B Combining Latin Small Letter M
342 > U_Combining_Latin_Small_Letter_R = 0x036C, // U+036C Combining Latin Small Letter R
343 > U_Combining_Latin_Small_Letter_T = 0x036D, // U+036D Combining Latin Small Letter T
344 > U_Combining_Latin_Small_Letter_V = 0x036E, // U+036E Combining Latin Small Letter V
345 > U_Combining_Latin_Small_Letter_X = 0x036F, // U+036F Combining Latin Small Letter X
346 >
347 > /**
348 > * Unicode Character 'LINE SEPARATOR' (U+2028)
349 > * http://www.fileformat.info/info/unicode/char/2028/index.htm
350 > */
351 > LINE_SEPARATOR = 0x2028,
352 > /**
353 > * Unicode Character 'PARAGRAPH SEPARATOR' (U+2029)
354 > * http://www.fileformat.info/info/unicode/char/2029/index.htm
355 > */
356 > PARAGRAPH_SEPARATOR = 0x2029,
357 > /**
358 > * Unicode Character 'NEXT LINE' (U+0085)
359 > * http://www.fileformat.info/info/unicode/char/0085/index.htm
360 > */
361 > NEXT_LINE = 0x0085,
362 >
363 > // http://www.fileformat.info/info/unicode/category/Sk/list.htm
364 > U_CIRCUMFLEX = 0x005E, // U+005E CIRCUMFLEX
365 > U_GRAVE_ACCENT = 0x0060, // U+0060 GRAVE ACCENT
366 > U_DIAERESIS = 0x00A8, // U+00A8 DIAERESIS
367 > U_MACRON = 0x00AF, // U+00AF MACRON
368 > U_ACUTE_ACCENT = 0x00B4, // U+00B4 ACUTE ACCENT
369 > U_CEDILLA = 0x00B8, // U+00B8 CEDILLA
370 > U_MODIFIER_LETTER_LEFT_ARROWHEAD = 0x02C2, // U+02C2 MODIFIER LETTER LEFT ARROWHEAD
371 > U_MODIFIER_LETTER_RIGHT_ARROWHEAD = 0x02C3, // U+02C3 MODIFIER LETTER RIGHT ARROWHEAD
372 > U_MODIFIER_LETTER_UP_ARROWHEAD = 0x02C4, // U+02C4 MODIFIER LETTER UP ARROWHEAD
373 > U_MODIFIER_LETTER_DOWN_ARROWHEAD = 0x02C5, // U+02C5 MODIFIER LETTER DOWN ARROWHEAD
374 > U_MODIFIER_LETTER_CENTRED_RIGHT_HALF_RING = 0x02D2, // U+02D2 MODIFIER LETTER CENTRED RIGHT HALF RING
375 > U_MODIFIER_LETTER_CENTRED_LEFT_HALF_RING = 0x02D3, // U+02D3 MODIFIER LETTER CENTRED LEFT HALF RING
376 > U_MODIFIER_LETTER_UP_TACK = 0x02D4, // U+02D4 MODIFIER LETTER UP TACK
377 > U_MODIFIER_LETTER_DOWN_TACK = 0x02D5, // U+02D5 MODIFIER LETTER DOWN TACK
378 > U_MODIFIER_LETTER_PLUS_SIGN = 0x02D6, // U+02D6 MODIFIER LETTER PLUS SIGN
379 > U_MODIFIER_LETTER_MINUS_SIGN = 0x02D7, // U+02D7 MODIFIER LETTER MINUS SIGN
380 > U_BREVE = 0x02D8, // U+02D8 BREVE
381 > U_DOT_ABOVE = 0x02D9, // U+02D9 DOT ABOVE
382 > U_RING_ABOVE = 0x02DA, // U+02DA RING ABOVE
383 > U_OGONEK = 0x02DB, // U+02DB OGONEK
384 > U_SMALL_TILDE = 0x02DC, // U+02DC SMALL TILDE
385 > U_DOUBLE_ACUTE_ACCENT = 0x02DD, // U+02DD DOUBLE ACUTE ACCENT
386 > U_MODIFIER_LETTER_RHOTIC_HOOK = 0x02DE, // U+02DE MODIFIER LETTER RHOTIC HOOK
387 > U_MODIFIER_LETTER_CROSS_ACCENT = 0x02DF, // U+02DF MODIFIER LETTER CROSS ACCENT
388 > U_MODIFIER_LETTER_EXTRA_HIGH_TONE_BAR = 0x02E5, // U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR
389 > U_MODIFIER_LETTER_HIGH_TONE_BAR = 0x02E6, // U+02E6 MODIFIER LETTER HIGH TONE BAR
390 > U_MODIFIER_LETTER_MID_TONE_BAR = 0x02E7, // U+02E7 MODIFIER LETTER MID TONE BAR
391 > U_MODIFIER_LETTER_LOW_TONE_BAR = 0x02E8, // U+02E8 MODIFIER LETTER LOW TONE BAR
392 > U_MODIFIER_LETTER_EXTRA_LOW_TONE_BAR = 0x02E9, // U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR
393 > U_MODIFIER_LETTER_YIN_DEPARTING_TONE_MARK = 0x02EA, // U+02EA MODIFIER LETTER YIN DEPARTING TONE MARK
394 > U_MODIFIER_LETTER_YANG_DEPARTING_TONE_MARK = 0x02EB, // U+02EB MODIFIER LETTER YANG DEPARTING TONE MARK
395 > U_MODIFIER_LETTER_UNASPIRATED = 0x02ED, // U+02ED MODIFIER LETTER UNASPIRATED
396 > U_MODIFIER_LETTER_LOW_DOWN_ARROWHEAD = 0x02EF, // U+02EF MODIFIER LETTER LOW DOWN ARROWHEAD
397 > U_MODIFIER_LETTER_LOW_UP_ARROWHEAD = 0x02F0, // U+02F0 MODIFIER LETTER LOW UP ARROWHEAD
398 > U_MODIFIER_LETTER_LOW_LEFT_ARROWHEAD = 0x02F1, // U+02F1 MODIFIER LETTER LOW LEFT ARROWHEAD
399 > U_MODIFIER_LETTER_LOW_RIGHT_ARROWHEAD = 0x02F2, // U+02F2 MODIFIER LETTER LOW RIGHT ARROWHEAD
400 > U_MODIFIER_LETTER_LOW_RING = 0x02F3, // U+02F3 MODIFIER LETTER LOW RING
401 > U_MODIFIER_LETTER_MIDDLE_GRAVE_ACCENT = 0x02F4, // U+02F4 MODIFIER LETTER MIDDLE GRAVE ACCENT
402 > U_MODIFIER_LETTER_MIDDLE_DOUBLE_GRAVE_ACCENT = 0x02F5, // U+02F5 MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT
403 > U_MODIFIER_LETTER_MIDDLE_DOUBLE_ACUTE_ACCENT = 0x02F6, // U+02F6 MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT
404 > U_MODIFIER_LETTER_LOW_TILDE = 0x02F7, // U+02F7 MODIFIER LETTER LOW TILDE
405 > U_MODIFIER_LETTER_RAISED_COLON = 0x02F8, // U+02F8 MODIFIER LETTER RAISED COLON
406 > U_MODIFIER_LETTER_BEGIN_HIGH_TONE = 0x02F9, // U+02F9 MODIFIER LETTER BEGIN HIGH TONE
407 > U_MODIFIER_LETTER_END_HIGH_TONE = 0x02FA, // U+02FA MODIFIER LETTER END HIGH TONE
408 > U_MODIFIER_LETTER_BEGIN_LOW_TONE = 0x02FB, // U+02FB MODIFIER LETTER BEGIN LOW TONE
409 > U_MODIFIER_LETTER_END_LOW_TONE = 0x02FC, // U+02FC MODIFIER LETTER END LOW TONE
410 > U_MODIFIER_LETTER_SHELF = 0x02FD, // U+02FD MODIFIER LETTER SHELF
411 > U_MODIFIER_LETTER_OPEN_SHELF = 0x02FE, // U+02FE MODIFIER LETTER OPEN SHELF
412 > U_MODIFIER_LETTER_LOW_LEFT_ARROW = 0x02FF, // U+02FF MODIFIER LETTER LOW LEFT ARROW
413 > U_GREEK_LOWER_NUMERAL_SIGN = 0x0375, // U+0375 GREEK LOWER NUMERAL SIGN
414 > U_GREEK_TONOS = 0x0384, // U+0384 GREEK TONOS
415 > U_GREEK_DIALYTIKA_TONOS = 0x0385, // U+0385 GREEK DIALYTIKA TONOS
416 > U_GREEK_KORONIS = 0x1FBD, // U+1FBD GREEK KORONIS
417 > U_GREEK_PSILI = 0x1FBF, // U+1FBF GREEK PSILI
418 > U_GREEK_PERISPOMENI = 0x1FC0, // U+1FC0 GREEK PERISPOMENI
419 > U_GREEK_DIALYTIKA_AND_PERISPOMENI = 0x1FC1, // U+1FC1 GREEK DIALYTIKA AND PERISPOMENI
420 > U_GREEK_PSILI_AND_VARIA = 0x1FCD, // U+1FCD GREEK PSILI AND VARIA
421 > U_GREEK_PSILI_AND_OXIA = 0x1FCE, // U+1FCE GREEK PSILI AND OXIA
422 > U_GREEK_PSILI_AND_PERISPOMENI = 0x1FCF, // U+1FCF GREEK PSILI AND PERISPOMENI
423 > U_GREEK_DASIA_AND_VARIA = 0x1FDD, // U+1FDD GREEK DASIA AND VARIA
424 > U_GREEK_DASIA_AND_OXIA = 0x1FDE, // U+1FDE GREEK DASIA AND OXIA
425 > U_GREEK_DASIA_AND_PERISPOMENI = 0x1FDF, // U+1FDF GREEK DASIA AND PERISPOMENI
426 > U_GREEK_DIALYTIKA_AND_VARIA = 0x1FED, // U+1FED GREEK DIALYTIKA AND VARIA
427 > U_GREEK_DIALYTIKA_AND_OXIA = 0x1FEE, // U+1FEE GREEK DIALYTIKA AND OXIA
428 > U_GREEK_VARIA = 0x1FEF, // U+1FEF GREEK VARIA
429 > U_GREEK_OXIA = 0x1FFD, // U+1FFD GREEK OXIA
430 > U_GREEK_DASIA = 0x1FFE, // U+1FFE GREEK DASIA
431 >
432 > U_IDEOGRAPHIC_FULL_STOP = 0x3002, // U+3002 IDEOGRAPHIC FULL STOP
433 > U_LEFT_CORNER_BRACKET = 0x300C, // U+300C LEFT CORNER BRACKET
434 > U_RIGHT_CORNER_BRACKET = 0x300D, // U+300D RIGHT CORNER BRACKET
435 > U_LEFT_BLACK_LENTICULAR_BRACKET = 0x3010, // U+3010 LEFT BLACK LENTICULAR BRACKET
436 > U_RIGHT_BLACK_LENTICULAR_BRACKET = 0x3011, // U+3011 RIGHT BLACK LENTICULAR BRACKET
437 >
438 >
439 > U_OVERLINE = 0x203E, // Unicode Character 'OVERLINE'
440 >
441 > /**
442 > * UTF-8 BOM
443 > * Unicode Character 'ZERO WIDTH NO-BREAK SPACE' (U+FEFF)
444 > * http://www.fileformat.info/info/unicode/char/feff/index.htm
445 > */
446 > UTF8_BOM = 65279,
447 >
448 > U_FULLWIDTH_SEMICOLON = 0xFF1B, // U+FF1B FULLWIDTH SEMICOLON
449 > U_FULLWIDTH_COMMA = 0xFF0C, // U+FF0C FULLWIDTH COMMA
450 > }
src/vs/base/common/arrays.ts 404 covered LOC · 72 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- arrays.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { findFirstIdxMonotonousOrArrLen } from './arraysFind.js';
7 > import { CancellationToken } from './cancellation.js';
8 > import { CancellationError } from './errors.js';
9 > import { ISplice } from './sequence.js';
10 >
11 > /**
12 > * Returns the last entry and the initial N-1 entries of the array, as a tuple of [rest, last].
13 > *
14 > * The array must have at least one element.
15 > *
16 > * @param arr The input array
17 > * @returns A tuple of [rest, last] where rest is all but the last element and last is the last element
18 > * @throws Error if the array is empty
19 > */
20 > export function tail<T>(arr: T[]): [T[], T] {
21 if (arr.length === 0) {
22 throw new Error('Invalid tail call');
25 return [arr.slice(0, arr.length - 1), arr[arr.length - 1]];
26 }
27 > arrays.ts
28 > export function equals<T>(one: ReadonlyArray<T> | undefined, other: ReadonlyArray<T> | undefined, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {
29 if (one === other) {
30 return true;
47 return true;
48 }
49 > arrays.ts
50 > /**
51 > * Remove the element at `index` by replacing it with the last element. This is faster than `splice`
52 > * but changes the order of the array
53 > */
54 > export function removeFastWithoutKeepingOrder<T>(array: T[], index: number) {
55 const last = array.length - 1;
56 if (index < last) {
59 array.pop();
60 }
61 > arrays.ts
62 > /**
63 > * Performs a binary search algorithm over a sorted array.
64 > *
65 > * @param array The array being searched.
66 > * @param key The value we search for.
67 > * @param comparator A function that takes two array elements and returns zero
68 > * if they are equal, a negative number if the first element precedes the
69 > * second one in the sorting order, or a positive number if the second element
70 > * precedes the first one.
71 > * @return See {@link binarySearch2}
72 > */
73 > export function binarySearch<T>(array: ReadonlyArray<T>, key: T, comparator: (op1: T, op2: T) => number): number {
74 return binarySearch2(array.length, i => comparator(array[i], key));
75 }
76 > arrays.ts
77 > /**
78 > * Performs a binary search algorithm over a sorted collection. Useful for cases
79 > * when we need to perform a binary search over something that isn't actually an
80 > * array, and converting data to an array would defeat the use of binary search
81 > * in the first place.
82 > *
83 > * @param length The collection length.
84 > * @param compareToKey A function that takes an index of an element in the
85 > * collection and returns zero if the value at this index is equal to the
86 > * search key, a negative number if the value precedes the search key in the
87 > * sorting order, or a positive number if the search key precedes the value.
88 > * @return A non-negative index of an element, if found. If not found, the
89 > * result is -(n+1) (or ~n, using bitwise notation), where n is the index
90 > * where the key should be inserted to maintain the sorting order.
91 > */
92 > export function binarySearch2(length: number, compareToKey: (index: number) => number): number {
93 let low = 0,
94 high = length - 1;
107 return -(low + 1);
108 }
109 > arrays.ts
110 > type Compare<T> = (a: T, b: T) => number;
111 >
112 > /**
113 > * Finds the nth smallest element in the array using quickselect algorithm.
114 > * The data does not need to be sorted.
115 > *
116 > * @param nth The zero-based index of the element to find (0 = smallest, 1 = second smallest, etc.)
117 > * @param data The unsorted array
118 > * @param compare A comparator function that defines the sort order
119 > * @returns The nth smallest element
120 > * @throws TypeError if nth is >= data.length
121 > */
122 > export function quickSelect<T>(nth: number, data: T[], compare: Compare<T>): T {
123
124 nth = nth | 0;
152 }
153 }
154 > arrays.ts
155 > export function groupBy<T>(data: ReadonlyArray<T>, compare: (a: T, b: T) => number): T[][] {
156 const result: T[][] = [];
157 let currentGroup: T[] | undefined = undefined;
166 return result;
167 }
168 > arrays.ts
169 > /**
170 > * Splits the given items into a list of (non-empty) groups.
171 > * `shouldBeGrouped` is used to decide if two consecutive items should be in the same group.
172 > * The order of the items is preserved.
173 > */
174 > export function* groupAdjacentBy<T>(items: Iterable<T>, shouldBeGrouped: (item1: T, item2: T) => boolean): Iterable<T[]> {
175 let currentGroup: T[] | undefined;
176 let last: T | undefined;
190 }
191 }
192 > arrays.ts
193 > export function forEachAdjacent<T>(arr: T[], f: (item1: T | undefined, item2: T | undefined) => void): void {
194 for (let i = 0; i <= arr.length; i++) {
195 f(i === 0 ? undefined : arr[i - 1], i === arr.length ? undefined : arr[i]);
196 }
197 }
198 > arrays.ts
199 > export function forEachWithNeighbors<T>(arr: T[], f: (before: T | undefined, element: T, after: T | undefined) => void): void {
200 for (let i = 0; i < arr.length; i++) {
201 f(i === 0 ? undefined : arr[i - 1], arr[i], i + 1 === arr.length ? undefined : arr[i + 1]);
202 }
203 }
204 > arrays.ts
205 > export function concatArrays<T extends any[]>(...arrays: T): T[number][number][] {
206 return [].concat(...arrays);
207 }
208 > arrays.ts
209 > interface IMutableSplice<T> extends ISplice<T> {
210 > readonly toInsert: T[];
211 > deleteCount: number;
212 > }
213 >
214 > /**
215 > * Diffs two *sorted* arrays and computes the splices which apply the diff.
216 > */
217 > export function sortedDiff<T>(before: ReadonlyArray<T>, after: ReadonlyArray<T>, compare: (a: T, b: T) => number): ISplice<T>[] {
218 const result: IMutableSplice<T>[] = [];
219
266 return result;
267 }
268 > arrays.ts
269 > /**
270 > * Takes two *sorted* arrays and computes their delta (removed, added elements).
271 > * Finishes in `Math.min(before.length, after.length)` steps.
272 > */
273 > export function delta<T>(before: ReadonlyArray<T>, after: ReadonlyArray<T>, compare: (a: T, b: T) => number): { removed: T[]; added: T[] } {
274 const splices = sortedDiff(before, after, compare);
275 const removed: T[] = [];
283 return { removed, added };
284 }
285 > arrays.ts
286 > /**
287 > * Returns the top N elements from the array.
288 > *
289 > * Faster than sorting the entire array when the array is a lot larger than N.
290 > *
291 > * @param array The unsorted array.
292 > * @param compare A sort function for the elements.
293 > * @param n The number of elements to return.
294 > * @return The first n elements from array when sorted with compare.
295 > */
296 > export function top<T>(array: ReadonlyArray<T>, compare: (a: T, b: T) => number, n: number): T[] {
297 if (n === 0) {
298 return [];
302 return result;
303 }
304 > arrays.ts
305 > /**
306 > * Asynchronous variant of `top()` allowing for splitting up work in batches between which the event loop can run.
307 > *
308 > * Returns the top N elements from the array.
309 > *
310 > * Faster than sorting the entire array when the array is a lot larger than N.
311 > *
312 > * @param array The unsorted array.
313 > * @param compare A sort function for the elements.
314 > * @param n The number of elements to return.
315 > * @param batch The number of elements to examine before yielding to the event loop.
316 > * @return The first n elements from array when sorted with compare.
317 > */
318 > export function topAsync<T>(array: T[], compare: (a: T, b: T) => number, n: number, batch: number, token?: CancellationToken): Promise<T[]> {
319 if (n === 0) {
320 return Promise.resolve([]);
339 });
340 }
341 > arrays.ts
342 function topStep<T>(array: ReadonlyArray<T>, compare: (a: T, b: T) => number, result: T[], i: number, m: number): void {
343 for (const n = result.length; i < m; i++) {
350 }
351 }
352 > arrays.ts
353 > /**
354 > * @returns New array with all falsy values removed. The original array IS NOT modified.
355 > */
356 > export function coalesce<T>(array: ReadonlyArray<T | undefined | null>): T[] {
357 return array.filter((e): e is T => !!e);
358 }
359 > arrays.ts
360 > /**
361 > * Remove all falsy values from `array`. The original array IS modified.
362 > */
363 > export function coalesceInPlace<T>(array: Array<T | undefined | null>): asserts array is Array<T> {
364 let to = 0;
365 for (let i = 0; i < array.length; i++) {
371 array.length = to;
372 }
373 > arrays.ts
374 > /**
375 > * @deprecated Use `Array.copyWithin` instead
376 > */
377 > export function move(array: unknown[], from: number, to: number): void {
378 array.splice(to, 0, array.splice(from, 1)[0]);
379 }
380 > arrays.ts
381 > /**
382 > * @returns false if the provided object is an array and not empty.
383 > */
384 > export function isFalsyOrEmpty(obj: unknown): boolean {
385 return !Array.isArray(obj) || obj.length === 0;
386 }
387 > arrays.ts
388 > /**
389 > * @returns True if the provided object is an array and has at least one element.
390 > */
391 > export function isNonEmptyArray<T>(obj: T[] | undefined | null): obj is T[];
392 > export function isNonEmptyArray<T>(obj: readonly T[] | undefined | null): obj is readonly T[];
393 > export function isNonEmptyArray<T>(obj: T[] | readonly T[] | undefined | null): obj is T[] | readonly T[] {
394 return Array.isArray(obj) && obj.length > 0;
395 }
396 > arrays.ts
397 > /**
398 > * Removes duplicates from the given array. The optional keyFn allows to specify
399 > * how elements are checked for equality by returning an alternate value for each.
400 > */
401 > export function distinct<T>(array: ReadonlyArray<T>, keyFn: (value: T) => unknown = value => value): T[] {
402 const seen = new Set<any>();
403
411 });
412 }
413 > arrays.ts
414 > export function uniqueFilter<T, R>(keyFn: (t: T) => R): (t: T) => boolean {
415 const seen = new Set<R>();
416
426 };
427 }
428 > arrays.ts
429 > export function commonPrefixLength<T>(one: ReadonlyArray<T>, other: ReadonlyArray<T>, equals: (a: T, b: T) => boolean = (a, b) => a === b): number {
430 let result = 0;
431
436 return result;
437 }
438 > arrays.ts
439 > export function range(to: number): number[];
440 > export function range(from: number, to: number): number[];
441 > export function range(arg: number, to?: number): number[] {
442 let from = typeof to === 'number' ? arg : 0;
443
463 return result;
464 }
465 > arrays.ts
466 > export function index<T>(array: ReadonlyArray<T>, indexer: (t: T) => string): { [key: string]: T };
467 > export function index<T, R>(array: ReadonlyArray<T>, indexer: (t: T) => string, mapper: (t: T) => R): { [key: string]: R };
468 > export function index<T, R>(array: ReadonlyArray<T>, indexer: (t: T) => string, mapper?: (t: T) => R): { [key: string]: R } {
469 return array.reduce((r, t) => {
470 r[indexer(t)] = mapper ? mapper(t) : t;
472 }, Object.create(null));
473 }
474 > arrays.ts
475 > /**
476 > * Inserts an element into an array. Returns a function which, when
477 > * called, will remove that element from the array.
478 > *
479 > * @deprecated In almost all cases, use a `Set<T>` instead.
480 > */
481 > export function insert<T>(array: T[], element: T): () => void {
482 array.push(element);
483
484 return () => remove(array, element);
485 }
486 > arrays.ts
487 > /**
488 > * Removes an element from an array if it can be found.
489 > *
490 > * @deprecated In almost all cases, use a `Set<T>` instead.
491 > */
492 > export function remove<T>(array: T[], element: T): T | undefined {
493 const index = array.indexOf(element);
494 if (index > -1) {
500 return undefined;
501 }
502 > arrays.ts
503 > /**
504 > * Insert `insertArr` inside `target` at `insertIndex`.
505 > * Please don't touch unless you understand https://jsperf.com/inserting-an-array-within-an-array
506 > */
507 > export function arrayInsert<T>(target: T[], insertIndex: number, insertArr: T[]): T[] {
508 const before = target.slice(0, insertIndex);
509 const after = target.slice(insertIndex);
510 return before.concat(insertArr, after);
511 }
512 > arrays.ts
513 > /**
514 > * Uses Fisher-Yates shuffle to shuffle the given array
515 > */
516 > export function shuffle<T>(array: T[], _seed?: number): void {
517 let rand: () => number;
518
536 }
537 }
538 > arrays.ts
539 > /**
540 > * Pushes an element to the start of the array, if found.
541 > */
542 > export function pushToStart<T>(arr: T[], value: T): void {
543 const index = arr.indexOf(value);
544
548 }
549 }
550 > arrays.ts
551 > /**
552 > * Pushes an element to the end of the array, if found.
553 > */
554 > export function pushToEnd<T>(arr: T[], value: T): void {
555 const index = arr.indexOf(value);
556
560 }
561 }
562 > arrays.ts
563 > export function pushMany<T>(arr: T[], items: ReadonlyArray<T>): void {
564 for (const item of items) {
565 arr.push(item);
566 }
567 }
568 > arrays.ts
569 > export function mapArrayOrNot<T, U>(items: T | T[], fn: (_: T) => U): U | U[] {
570 return Array.isArray(items) ?
571 items.map(fn) :
572 fn(items);
573 }
574 > arrays.ts
575 > export function mapFilter<T, U>(array: ReadonlyArray<T>, fn: (t: T) => U | undefined): U[] {
576 const result: U[] = [];
577 for (const item of array) {
583 return result;
584 }
585 > arrays.ts
586 > export function withoutDuplicates<T>(array: ReadonlyArray<T>): T[] {
587 const s = new Set(array);
588 return Array.from(s);
589 }
590 > arrays.ts
591 > export function asArray<T>(x: T | T[]): T[];
592 > export function asArray<T>(x: T | readonly T[]): readonly T[];
593 > export function asArray<T>(x: T | T[]): T[] {
594 return Array.isArray(x) ? x : [x];
595 }
596 > arrays.ts
597 > export function getRandomElement<T>(arr: T[]): T | undefined {
598 return arr[Math.floor(Math.random() * arr.length)];
599 }
600 > arrays.ts
601 > /**
602 > * Insert the new items in the array.
603 > * @param array The original array.
604 > * @param start The zero-based location in the array from which to start inserting elements.
605 > * @param newItems The items to be inserted
606 > */
607 > export function insertInto<T>(array: T[], start: number, newItems: T[]): void {
608 const startIdx = getActualStartIndex(array, start);
609 const originalLength = array.length;
619 }
620 }
621 > arrays.ts
622 > /**
623 > * Removes elements from an array and inserts new elements in their place, returning the deleted elements. Alternative to the native Array.splice method, it
624 > * can only support limited number of items due to the maximum call stack size limit.
625 > * @param array The original array.
626 > * @param start The zero-based location in the array from which to start removing elements.
627 > * @param deleteCount The number of elements to remove.
628 > * @returns An array containing the elements that were deleted.
629 > */
630 > export function splice<T>(array: T[], start: number, deleteCount: number, newItems: T[]): T[] {
631 const index = getActualStartIndex(array, start);
632 let result = array.splice(index, deleteCount);
638 return result;
639 }
640 > arrays.ts
641 > /**
642 > * Determine the actual start index (same logic as the native splice() or slice())
643 > * If greater than the length of the array, start will be set to the length of the array. In this case, no element will be deleted but the method will behave as an adding function, adding as many element as item[n*] provided.
644 > * If negative, it will begin that many elements from the end of the array. (In this case, the origin -1, meaning -n is the index of the nth last element, and is therefore equivalent to the index of array.length - n.) If array.length + start is less than 0, it will begin from index 0.
645 > * @param array The target array.
646 > * @param start The operation index.
647 > */
648 function getActualStartIndex<T>(array: T[], start: number): number {
649 return start < 0 ? Math.max(start + array.length, 0) : Math.min(start, array.length);
650 }
651 > arrays.ts
652 >
653 >
654 > /**
655 > * When comparing two values,
656 > * a negative number indicates that the first value is less than the second,
657 > * a positive number indicates that the first value is greater than the second,
658 > * and zero indicates that neither is the case.
659 > */
660 > export type CompareResult = number;
661 >
662 > export namespace CompareResult {
663 > export function isLessThan(result: CompareResult): boolean {
664 return result < 0;
665 }
666 > arrays.ts
667 > export function isLessThanOrEqual(result: CompareResult): boolean {
668 return result <= 0;
669 }
670 > arrays.ts
671 > export function isGreaterThan(result: CompareResult): boolean {
672 return result > 0;
673 }
674 > arrays.ts
675 > export function isNeitherLessOrGreaterThan(result: CompareResult): boolean {
676 return result === 0;
677 }
678 > arrays.ts
679 > export const greaterThan = 1;
680 > export const lessThan = -1;
681 > export const neitherLessOrGreaterThan = 0;
682 > }
683 >
684 > /**
685 > * A comparator `c` defines a total order `<=` on `T` as following:
686 > * `c(a, b) <= 0` iff `a` <= `b`.
687 > * We also have `c(a, b) == 0` iff `c(b, a) == 0`.
688 > */
689 > export type Comparator<T> = (a: T, b: T) => CompareResult;
690 >
691 > export function compareBy<TItem, TCompareBy>(selector: (item: TItem) => TCompareBy, comparator: Comparator<TCompareBy>): Comparator<TItem> {
692 return (a, b) => comparator(selector(a), selector(b));
693 }
694 > arrays.ts
695 > export function tieBreakComparators<TItem>(...comparators: Comparator<TItem>[]): Comparator<TItem> {
696 return (item1, item2) => {
697 for (const comparator of comparators) {
704 };
705 }
706 > arrays.ts
707 > /**
708 > * The natural order on numbers.
709 > */
710 > export const numberComparator: Comparator<number> = (a, b) => a - b;
711 >
712 > export const booleanComparator: Comparator<boolean> = (a, b) => numberComparator(a ? 1 : 0, b ? 1 : 0);
713 >
714 > export function reverseOrder<TItem>(comparator: Comparator<TItem>): Comparator<TItem> {
715 return (a, b) => -comparator(a, b);
716 }
717 > arrays.ts
718 > /**
719 > * Returns a new comparator that treats `undefined` as the smallest value.
720 > * All other values are compared using the given comparator.
721 > */
722 > export function compareUndefinedSmallest<T>(comparator: Comparator<T>): Comparator<T | undefined> {
723 return (a, b) => {
724 if (a === undefined) {
731 };
732 }
733 > arrays.ts
734 > export class ArrayQueue<T> {
735 > private readonly items: readonly T[];
736 > private firstIdx = 0;
737 > private lastIdx: number;
738 >
739 > /**
740 > * Constructs a queue that is backed by the given array. Runtime is O(1).
741 > */
742 > constructor(items: readonly T[]) {
743 this.items = items;
744 this.lastIdx = this.items.length - 1;
745 }
746 > arrays.ts
747 > get length(): number {
748 return this.lastIdx - this.firstIdx + 1;
749 }
750 > arrays.ts
751 > /**
752 > * Consumes elements from the beginning of the queue as long as the predicate returns true.
753 > * If no elements were consumed, `null` is returned. Has a runtime of O(result.length).
754 > */
755 > takeWhile(predicate: (value: T) => boolean): T[] | null {
756 // P(k) := k <= this.lastIdx && predicate(this.items[k])
757 // Find s := min { k | k >= this.firstIdx && !P(k) } and return this.data[this.firstIdx...s)
765 return result;
766 }
767 > arrays.ts
768 > /**
769 > * Consumes elements from the end of the queue as long as the predicate returns true.
770 > * If no elements were consumed, `null` is returned.
771 > * The result has the same order as the underlying array!
772 > */
773 > takeFromEndWhile(predicate: (value: T) => boolean): T[] | null {
774 // P(k) := this.firstIdx >= k && predicate(this.items[k])
775 // Find s := max { k | k <= this.lastIdx && !P(k) } and return this.data(s...this.lastIdx]
783 return result;
784 }
785 > arrays.ts
786 > peek(): T | undefined {
787 if (this.length === 0) {
788 return undefined;
790 return this.items[this.firstIdx];
791 }
792 > arrays.ts
793 > peekLast(): T | undefined {
794 if (this.length === 0) {
795 return undefined;
797 return this.items[this.lastIdx];
798 }
799 > arrays.ts
800 > dequeue(): T | undefined {
801 const result = this.items[this.firstIdx];
802 this.firstIdx++;
803 return result;
804 }
805 > arrays.ts
806 > removeLast(): T | undefined {
807 const result = this.items[this.lastIdx];
808 this.lastIdx--;
809 return result;
810 }
811 > arrays.ts
812 > takeCount(count: number): T[] {
813 const result = this.items.slice(this.firstIdx, this.firstIdx + count);
814 this.firstIdx += count;
815 return result;
816 }
817 > } arrays.ts
818 >
819 > /**
820 > * This class is faster than an iterator and array for lazy computed data.
821 > */
822 > export class CallbackIterable<T> {
823 > public static readonly empty = new CallbackIterable<never>(_callback => { });
824 >
825 > constructor(
826 > /**
827 > * Calls the callback for every item.
828 > * Stops when the callback returns false.
829 > */
830 > public readonly iterate: (callback: (item: T) => boolean) => void
831 > ) {
832 > }
833 >
834 > forEach(handler: (item: T) => void) {
835 this.iterate(item => { handler(item); return true; });
836 }
837 > arrays.ts
838 > toArray(): T[] {
839 const result: T[] = [];
840 this.iterate(item => { result.push(item); return true; });
841 return result;
842 }
843 > arrays.ts
844 > filter(predicate: (item: T) => boolean): CallbackIterable<T> {
845 return new CallbackIterable(cb => this.iterate(item => predicate(item) ? cb(item) : true));
846 }
847 > arrays.ts
848 > map<TResult>(mapFn: (item: T) => TResult): CallbackIterable<TResult> {
849 return new CallbackIterable<TResult>(cb => this.iterate(item => cb(mapFn(item))));
850 }
851 > arrays.ts
852 > some(predicate: (item: T) => boolean): boolean {
853 let result = false;
854 this.iterate(item => { result = predicate(item); return !result; });
855 return result;
856 }
857 > arrays.ts
858 > findFirst(predicate: (item: T) => boolean): T | undefined {
859 let result: T | undefined;
860 this.iterate(item => {
867 return result;
868 }
869 > arrays.ts
870 > findLast(predicate: (item: T) => boolean): T | undefined {
871 let result: T | undefined;
872 this.iterate(item => {
878 return result;
879 }
880 > arrays.ts
881 > findLastMaxBy(comparator: Comparator<T>): T | undefined {
882 let result: T | undefined;
883 let first = true;
891 return result;
892 }
893 > } arrays.ts
894 >
895 > /**
896 > * Represents a re-arrangement of items in an array.
897 > */
898 > export class Permutation {
899 > constructor(private readonly _indexMap: readonly number[]) { }
900 >
901 > /**
902 > * Returns a permutation that sorts the given array according to the given compare function.
903 > */
904 > public static createSortPermutation<T>(arr: readonly T[], compareFn: (a: T, b: T) => number): Permutation {
905 const sortIndices = Array.from(arr.keys()).sort((index1, index2) => compareFn(arr[index1], arr[index2]));
906 return new Permutation(sortIndices);
907 }
908 > arrays.ts
909 > /**
910 > * Returns a new array with the elements of the given array re-arranged according to this permutation.
911 > */
912 > apply<T>(arr: readonly T[]): T[] {
913 return arr.map((_, index) => arr[this._indexMap[index]]);
914 }
915 > arrays.ts
916 > /**
917 > * Returns a new permutation that undoes the re-arrangement of this permutation.
918 > */
919 > inverse(): Permutation {
920 const inverseIndexMap = this._indexMap.slice();
921 for (let i = 0; i < this._indexMap.length; i++) {
924 return new Permutation(inverseIndexMap);
925 }
926 > } arrays.ts
927 >
928 > /**
929 > * Asynchronous variant of `Array.find()`, returning the first element in
930 > * the array for which the predicate returns true.
931 > *
932 > * This implementation does not bail early and waits for all promises to
933 > * resolve before returning.
934 > */
935 export async function findAsync<T>(array: readonly T[], predicate: (element: T, index: number) => Promise<boolean>): Promise<T | undefined> {
936 const results = await Promise.all(array.map(
940 return results.find(r => r.ok)?.element;
941 }
942 > arrays.ts
943 > export function sum(array: readonly number[]): number {
944 return array.reduce((acc, value) => acc + value, 0);
945 }
946 > arrays.ts
947 > export function sumBy<T>(array: readonly T[], selector: (value: T) => number): number {
948 return array.reduce((acc, value) => acc + selector(value), 0);
949 }
src/vs/base/common/uri.ts 354 covered LOC · 50 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- uri.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CharCode } from './charCode.js';
7 > import { MarshalledId } from './marshallingIds.js';
8 > import * as paths from './path.js';
9 > import { isWindows } from './platform.js';
10 >
11 > const _schemePattern = /^\w[\w\d+.-]*$/;
12 > const _singleSlashStart = /^\//;
13 > const _doubleSlashStart = /^\/\//;
14 >
15 > function _validateUri(ret: URI, _strict?: boolean): void { uri.ts
16 >
17 > // scheme, must be set
18 > if (!ret.scheme && _strict) {
19 throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`);
20 }
21 > uri.ts
22 > // scheme, https://tools.ietf.org/html/rfc3986#section-3.1
23 > // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
24 > if (ret.scheme && !_schemePattern.test(ret.scheme)) { uri.ts
25 const matches = [...ret.scheme.matchAll(/[^\w\d+.-]/gu)];
26 const detail = matches.length > 0
29 throw new Error(`[UriError]: Scheme contains illegal characters.${detail} (len:${ret.scheme.length})`);
30 }
31 > uri.ts
32 > // path, http://tools.ietf.org/html/rfc3986#section-3.3
33 > // If a URI contains an authority component, then the path component
34 > // must either be empty or begin with a slash ("/") character. If a URI
35 > // does not contain an authority component, then the path cannot begin
36 > // with two slash characters ("//").
37 > if (ret.path) {
38 > if (ret.authority) { uri.ts
39 if (!_singleSlashStart.test(ret.path)) {
40 throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character');
41 }
42 > } else { uri.ts
43 > if (_doubleSlashStart.test(ret.path)) { uri.ts
44 throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")');
45 }
46 > } uri.ts
47 > } uri.ts
48 > } uri.ts
49 > uri.ts
50 > // for a while we allowed uris *without* schemes and this is the migration
51 > // for them, e.g. an uri without scheme and without strict-mode warns and falls
52 > // back to the file-scheme. that should cause the least carnage and still be a
53 > // clear warning
54 > function _schemeFix(scheme: string, _strict: boolean): string { uri.ts
55 > if (!scheme && !_strict) {
56 return 'file';
57 }
58 > return scheme; uri.ts
59 > }
60 > uri.ts
61 > // implements a bit of https://tools.ietf.org/html/rfc3986#section-5
62 > function _referenceResolution(scheme: string, path: string): string { uri.ts
63 >
64 > // the slash-character is our 'default base' as we don't
65 > // support constructing URIs relative to other URIs. This
66 > // also means that we alter and potentially break paths.
67 > // see https://tools.ietf.org/html/rfc3986#section-5.1.4
68 > switch (scheme) {
69 > case 'https':
70 > case 'http':
71 > case 'file':
72 > if (!path) { uri.ts
73 path = _slash;
74 > } else if (path[0] !== _slash) { uri.ts
75 path = _slash + path;
76 }
77 > break; uri.ts
78 > } uri.ts
79 > return path;
80 > }
81 > uri.ts
82 > const _empty = '';
83 > const _slash = '/';
84 > const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
85 >
86 > /**
87 > * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.
88 > * This class is a simple parser which creates the basic component parts
89 > * (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation
90 > * and encoding.
91 > *
92 > * ```txt
93 > * foo://example.com:8042/over/there?name=ferret#nose
94 > * \_/ \______________/\_________/ \_________/ \__/
95 > * | | | | |
96 > * scheme authority path query fragment
97 > * | _____________________|__
98 > * / \ / \
99 > * urn:example:animal:ferret:nose
100 > * ```
101 > */
102 > export class URI implements UriComponents {
103 >
104 > static isUri(thing: unknown): thing is URI {
105 if (thing instanceof URI) {
106 return true;
118 && typeof (<URI>thing).toString === 'function';
119 }
120 > uri.ts
121 > /**
122 > * scheme is the 'http' part of 'http://www.example.com/some/path?query#fragment'.
123 > * The part before the first colon.
124 > */
125 > readonly scheme: string;
126 >
127 > /**
128 > * authority is the 'www.example.com' part of 'http://www.example.com/some/path?query#fragment'.
129 > * The part between the first double slashes and the next slash.
130 > */
131 > readonly authority: string;
132 >
133 > /**
134 > * path is the '/some/path' part of 'http://www.example.com/some/path?query#fragment'.
135 > */
136 > readonly path: string;
137 >
138 > /**
139 > * query is the 'query' part of 'http://www.example.com/some/path?query#fragment'.
140 > */
141 > readonly query: string;
142 >
143 > /**
144 > * fragment is the 'fragment' part of 'http://www.example.com/some/path?query#fragment'.
145 > */
146 > readonly fragment: string;
147 >
148 > /**
149 > * @internal
150 > */
151 > protected constructor(scheme: string, authority?: string, path?: string, query?: string, fragment?: string, _strict?: boolean);
152 >
153 > /**
154 > * @internal
155 > */
156 > protected constructor(components: UriComponents);
157 >
158 > /**
159 > * @internal
160 > */
161 > protected constructor(schemeOrData: string | UriComponents, authority?: string, path?: string, query?: string, fragment?: string, _strict: boolean = false) {
162 > uri.ts
163 > if (typeof schemeOrData === 'object') {
164 this.scheme = schemeOrData.scheme || _empty;
165 this.authority = schemeOrData.authority || _empty;
170 // that creates uri components.
171 // _validateUri(this);
172 > } else { uri.ts
173 > this.scheme = _schemeFix(schemeOrData, _strict);
174 > this.authority = authority || _empty;
175 > this.path = _referenceResolution(this.scheme, path || _empty);
176 > this.query = query || _empty;
177 > this.fragment = fragment || _empty;
178 >
179 > _validateUri(this, _strict);
180 > }
181 > }
182 > uri.ts
183 > // ---- filesystem path -----------------------
184 >
185 > /**
186 > * Returns a string representing the corresponding file system path of this URI.
187 > * Will handle UNC paths, normalizes windows drive letters to lower-case, and uses the
188 > * platform specific path separator.
189 > *
190 > * * Will *not* validate the path for invalid characters and semantics.
191 > * * Will *not* look at the scheme of this URI.
192 > * * The result shall *not* be used for display purposes but for accessing a file on disk.
193 > *
194 > *
195 > * The *difference* to `URI#path` is the use of the platform specific separator and the handling
196 > * of UNC paths. See the below sample of a file-uri with an authority (UNC path).
197 > *
198 > * ```ts
199 > const u = URI.parse('file://server/c$/folder/file.txt')
200 > u.authority === 'server'
201 > u.path === '/shares/c$/file.txt'
202 > u.fsPath === '\\server\c$\folder\file.txt'
203 > ```
204 > *
205 > * Using `URI#path` to read a file (using fs-apis) would not be enough because parts of the path,
206 > * namely the server name, would be missing. Therefore `URI#fsPath` exists - it's sugar to ease working
207 > * with URIs that represent files on disk (`file` scheme).
208 > */
209 > get fsPath(): string {
210 // if (this.scheme !== 'file') {
211 // console.warn(`[UriError] calling fsPath with scheme ${this.scheme}`);
213 return uriToFsPath(this, false);
214 }
215 > uri.ts
216 > // ---- modify to new -------------------------
217 >
218 > with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI {
219
220 if (!change) {
260 return new Uri(scheme, authority, path, query, fragment);
261 }
262 > uri.ts
263 > // ---- parse & validate ------------------------
264 >
265 > /**
266 > * Creates a new URI from a string, e.g. `http://www.example.com/some/path`,
267 > * `file:///usr/home`, or `scheme:with/path`.
268 > *
269 > * @param value A string which represents an URI (see `URI#toString`).
270 > */
271 > static parse(value: string, _strict: boolean = false): URI {
272 const match = _regexp.exec(value);
273 if (!match) {
283 );
284 }
285 > uri.ts
286 > /**
287 > * Creates a new URI from a file system path, e.g. `c:\my\files`,
288 > * `/usr/home`, or `\\server\share\some\path`.
289 > *
290 > * The *difference* between `URI#parse` and `URI#file` is that the latter treats the argument
291 > * as path, not as stringified-uri. E.g. `URI.file(path)` is **not the same as**
292 > * `URI.parse('file://' + path)` because the path might contain characters that are
293 > * interpreted (# and ?). See the following sample:
294 > * ```ts
295 > const good = URI.file('/coding/c#/project1');
296 > good.scheme === 'file';
297 > good.path === '/coding/c#/project1';
298 > good.fragment === '';
299 > const bad = URI.parse('file://' + '/coding/c#/project1');
300 > bad.scheme === 'file';
301 > bad.path === '/coding/c'; // path is now broken
302 > bad.fragment === '/project1';
303 > ```
304 > *
305 > * @param path A file system path (see `URI#fsPath`)
306 > */
307 > static file(path: string): URI {
308 > uri.ts
309 > let authority = _empty;
310 >
311 > // normalize to fwd-slashes on windows,
312 > // on other systems bwd-slashes are valid
313 > // filename character, eg /f\oo/ba\r.txt
314 > if (isWindows) {
315 path = path.replace(/\\/g, _slash);
316 }
317 > uri.ts
318 > // check for authority as used in UNC shares
319 > // or use the path as given
320 > if (path[0] === _slash && path[1] === _slash) {
321 const idx = path.indexOf(_slash, 2);
322 if (idx === -1) {
328 }
329 }
330 > uri.ts
331 > return new Uri('file', authority, path, _empty, _empty);
332 > }
333 > uri.ts
334 > /**
335 > * Creates new URI from uri components.
336 > *
337 > * Unless `strict` is `true` the scheme is defaults to be `file`. This function performs
338 > * validation and should be used for untrusted uri components retrieved from storage,
339 > * user input, command arguments etc
340 > */
341 > static from(components: UriComponents, strict?: boolean): URI {
342 const result = new Uri(
343 components.scheme,
350 return result;
351 }
352 > uri.ts
353 > /**
354 > * Join a URI path with path fragments and normalizes the resulting path.
355 > *
356 > * @param uri The input URI.
357 > * @param pathFragment The path fragment to add to the URI path.
358 > * @returns The resulting URI.
359 > */
360 > static joinPath(uri: URI, ...pathFragment: string[]): URI {
361 if (!uri.path) {
362 throw new Error(`[UriError]: cannot call joinPath on URI without path: ${uri.toString()}`);
370 return uri.with({ path: newPath });
371 }
372 > uri.ts
373 > // ---- printing/externalize ---------------------------
374 >
375 > /**
376 > * Creates a string representation for this URI. It's guaranteed that calling
377 > * `URI.parse` with the result of this function creates an URI which is equal
378 > * to this URI.
379 > *
380 > * * The result shall *not* be used for display purposes but for externalization or transport.
381 > * * The result will be encoded using the percentage encoding and encoding happens mostly
382 > * ignore the scheme-specific encoding rules.
383 > *
384 > * @param skipEncoding Do not encode the result, default is `false`
385 > */
386 > toString(skipEncoding: boolean = false): string {
387 return _asFormatted(this, skipEncoding);
388 }
389 > uri.ts
390 > toJSON(): UriComponents {
391 return this;
392 }
393 > uri.ts
394 > /**
395 > * A helper function to revive URIs.
396 > *
397 > * **Note** that this function should only be used when receiving URI#toJSON generated data
398 > * and that it doesn't do any validation. Use {@link URI.from} when received "untrusted"
399 > * uri components such as command arguments or data from storage.
400 > *
401 > * @param data The URI components or URI to revive.
402 > * @returns The revived URI or undefined or null.
403 > */
404 > static revive(data: UriComponents | URI): URI;
405 > static revive(data: UriComponents | URI | undefined): URI | undefined;
406 > static revive(data: UriComponents | URI | null): URI | null;
407 > static revive(data: UriComponents | URI | undefined | null): URI | undefined | null;
408 > static revive(data: UriComponents | URI | undefined | null): URI | undefined | null {
409 if (!data) {
410 return data;
418 }
419 }
420 > uri.ts
421 > [Symbol.for('debug.description')]() {
422 return `URI(${this.toString()})`;
423 }
424 > } uri.ts
425 >
426 > export interface UriComponents {
427 > scheme: string;
428 > authority?: string;
429 > path?: string;
430 > query?: string;
431 > fragment?: string;
432 > }
433 >
434 > export function isUriComponents(thing: unknown): thing is UriComponents {
435 if (!thing || typeof thing !== 'object') {
436 return false;
442 && (typeof (<UriComponents>thing).fragment === 'string' || typeof (<UriComponents>thing).fragment === 'undefined');
443 }
444 > uri.ts
445 > interface UriState extends UriComponents {
446 > $mid: MarshalledId.Uri;
447 > external?: string;
448 > fsPath?: string;
449 > _sep?: 1;
450 > }
451 >
452 > const _pathSepMarker = isWindows ? 1 : undefined;
453 >
454 > // This class exists so that URI is compatible with vscode.Uri (API).
455 > class Uri extends URI { uri.ts
456 >
457 > _formatted: string | null = null;
458 > _fsPath: string | null = null;
459 > uri.ts
460 > override get fsPath(): string {
461 if (!this._fsPath) {
462 this._fsPath = uriToFsPath(this, false);
464 return this._fsPath;
465 }
466 > uri.ts
467 > override toString(skipEncoding: boolean = false): string {
468 if (!skipEncoding) {
469 if (!this._formatted) {
476 }
477 }
478 > uri.ts
479 > override toJSON(): UriComponents {
480 // eslint-disable-next-line local/code-no-dangerous-type-assertions
481 const res = <UriState>{
512 return res;
513 }
514 > } uri.ts
515 >
516 > // reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2
517 > const encodeTable: { [ch: number]: string } = {
518 > [CharCode.Colon]: '%3A', // gen-delims
519 > [CharCode.Slash]: '%2F',
520 > [CharCode.QuestionMark]: '%3F',
521 > [CharCode.Hash]: '%23',
522 > [CharCode.OpenSquareBracket]: '%5B',
523 > [CharCode.CloseSquareBracket]: '%5D',
524 > [CharCode.AtSign]: '%40',
525 >
526 > [CharCode.ExclamationMark]: '%21', // sub-delims
527 > [CharCode.DollarSign]: '%24',
528 > [CharCode.Ampersand]: '%26',
529 > [CharCode.SingleQuote]: '%27',
530 > [CharCode.OpenParen]: '%28',
531 > [CharCode.CloseParen]: '%29',
532 > [CharCode.Asterisk]: '%2A',
533 > [CharCode.Plus]: '%2B',
534 > [CharCode.Comma]: '%2C',
535 > [CharCode.Semicolon]: '%3B',
536 > [CharCode.Equals]: '%3D',
537 >
538 > [CharCode.Space]: '%20',
539 > };
540 >
541 function encodeURIComponentFast(uriComponent: string, isPath: boolean, isAuthority: boolean): string {
542 let res: string | undefined = undefined;
602 return res !== undefined ? res : uriComponent;
603 }
604 > uri.ts
605 function encodeURIComponentMinimal(path: string): string {
606 let res: string | undefined = undefined;
620 return res !== undefined ? res : path;
621 }
622 > uri.ts
623 > /**
624 > * Compute `fsPath` for the given uri
625 > */
626 > export function uriToFsPath(uri: URI, keepDriveLetterCasing: boolean): string {
627
628 let value: string;
650 return value;
651 }
652 > uri.ts
653 > /**
654 > * Create the external version of a uri
655 > */
656 function _asFormatted(uri: URI, skipEncoding: boolean): string {
657
723 return res;
724 }
725 > uri.ts
726 > // --- decode
727 >
728 function decodeURIComponentGraceful(str: string): string {
729 try {
737 }
738 }
739 > uri.ts
740 > const _rEncodedAsHex = /(%[0-9A-Za-z][0-9A-Za-z])+/g;
741 >
742 function percentDecode(str: string): string {
743 if (!str.match(_rEncodedAsHex)) {
746 return str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match));
747 }
748 > uri.ts
749 > /**
750 > * Mapped-type that replaces all occurrences of URI with UriComponents
751 > */
752 > export type UriDto<T> = { [K in keyof T]: T[K] extends URI
753 > ? UriComponents
754 > : UriDto<T[K]> };
src/vs/base/common/map.ts 313 covered LOC · 97 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- map.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { URI } from './uri.js';
7 >
8 > export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {
9 let result = map.get(key);
10 if (result === undefined) {
15 return result;
16 }
17 > map.ts
18 > export function mapToString<K, V>(map: Map<K, V>): string {
19 const entries: string[] = [];
20 map.forEach((value, key) => {
24 return `Map(${map.size}) {${entries.join(', ')}}`;
25 }
26 > map.ts
27 > export function setToString<K>(set: Set<K>): string {
28 const entries: K[] = [];
29 set.forEach(value => {
33 return `Set(${set.size}) {${entries.join(', ')}}`;
34 }
35 > map.ts
36 > interface ResourceMapKeyFn {
37 > (resource: URI): string;
38 > }
39 >
40 > class ResourceMapEntry<T> {
41 > constructor(readonly uri: URI, readonly value: T) { }
42 > }
43 >
44 function isEntries<T>(arg: ResourceMap<T> | ResourceMapKeyFn | readonly (readonly [URI, T])[] | undefined): arg is readonly (readonly [URI, T])[] {
45 return Array.isArray(arg);
46 }
47 > map.ts
48 > export class ResourceMap<T> implements Map<URI, T> {
49 >
50 > private static readonly defaultToKey = (resource: URI) => resource.toString();
51 >
52 > readonly [Symbol.toStringTag] = 'ResourceMap';
53 >
54 > private readonly map: Map<string, ResourceMapEntry<T>>;
55 > private readonly toKey: ResourceMapKeyFn;
56 >
57 > /**
58 > *
59 > * @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util
60 > */
61 > constructor(toKey?: ResourceMapKeyFn);
62 >
63 > /**
64 > *
65 > * @param other Another resource which this maps is created from
66 > * @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util
67 > */
68 > constructor(other?: ResourceMap<T>, toKey?: ResourceMapKeyFn);
69 >
70 > /**
71 > *
72 > * @param other Another resource which this maps is created from
73 > * @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util
74 > */
75 > constructor(entries?: readonly (readonly [URI, T])[], toKey?: ResourceMapKeyFn);
76 >
77 > constructor(arg?: ResourceMap<T> | ResourceMapKeyFn | readonly (readonly [URI, T])[], toKey?: ResourceMapKeyFn) {
78 if (arg instanceof ResourceMap) {
79 this.map = new Map(arg.map);
91 }
92 }
93 > map.ts
94 > set(resource: URI, value: T): this {
95 this.map.set(this.toKey(resource), new ResourceMapEntry(resource, value));
96 return this;
97 }
98 > map.ts
99 > get(resource: URI): T | undefined {
100 return this.map.get(this.toKey(resource))?.value;
101 }
102 > map.ts
103 > has(resource: URI): boolean {
104 return this.map.has(this.toKey(resource));
105 }
106 > map.ts
107 > get size(): number {
108 return this.map.size;
109 }
110 > map.ts
111 > clear(): void {
112 this.map.clear();
113 }
114 > map.ts
115 > delete(resource: URI): boolean {
116 return this.map.delete(this.toKey(resource));
117 }
118 > map.ts
119 > forEach(clb: (value: T, key: URI, map: Map<URI, T>) => void, thisArg?: object): void {
120 if (typeof thisArg !== 'undefined') {
121 clb = clb.bind(thisArg);
125 }
126 }
127 > map.ts
128 > *values(): MapIterator<T> {
129 for (const entry of this.map.values()) {
130 yield entry.value;
131 }
132 }
133 > map.ts
134 > *keys(): MapIterator<URI> {
135 for (const entry of this.map.values()) {
136 yield entry.uri;
137 }
138 }
139 > map.ts
140 > *entries(): MapIterator<[URI, T]> {
141 for (const entry of this.map.values()) {
142 yield [entry.uri, entry.value];
143 }
144 }
145 > map.ts
146 > *[Symbol.iterator](): MapIterator<[URI, T]> {
147 for (const [, entry] of this.map) {
148 yield [entry.uri, entry.value];
149 }
150 }
151 > } map.ts
152 >
153 > export class ResourceSet implements Set<URI> {
154 >
155 > readonly [Symbol.toStringTag]: string = 'ResourceSet';
156 >
157 > private readonly _map: ResourceMap<URI>;
158 >
159 > constructor(toKey?: ResourceMapKeyFn);
160 > constructor(entries: readonly URI[], toKey?: ResourceMapKeyFn);
161 > constructor(entriesOrKey?: readonly URI[] | ResourceMapKeyFn, toKey?: ResourceMapKeyFn) {
162 if (!entriesOrKey || typeof entriesOrKey === 'function') {
163 this._map = new ResourceMap(entriesOrKey);
167 }
168 }
169 > map.ts
170 >
171 > get size(): number {
172 return this._map.size;
173 }
174 > map.ts
175 > add(value: URI): this {
176 this._map.set(value, value);
177 return this;
178 }
179 > map.ts
180 > clear(): void {
181 this._map.clear();
182 }
183 > map.ts
184 > delete(value: URI): boolean {
185 return this._map.delete(value);
186 }
187 > map.ts
188 > forEach(callbackfn: (value: URI, value2: URI, set: Set<URI>) => void, thisArg?: unknown): void {
189 this._map.forEach((_value, key) => callbackfn.call(thisArg, key, key, this));
190 }
191 > map.ts
192 > has(value: URI): boolean {
193 return this._map.has(value);
194 }
195 > map.ts
196 > entries(): SetIterator<[URI, URI]> {
197 return this._map.entries() as unknown as SetIterator<[URI, URI]>;
198 }
199 > map.ts
200 > keys(): SetIterator<URI> {
201 return this._map.keys() as unknown as SetIterator<URI>;
202 }
203 > map.ts
204 > values(): SetIterator<URI> {
205 return this._map.keys() as unknown as SetIterator<URI>;
206 }
207 > map.ts
208 > [Symbol.iterator](): SetIterator<URI> {
209 return this.keys();
210 }
211 > } map.ts
212 >
213 >
214 > interface Item<K, V> {
215 > previous: Item<K, V> | undefined;
216 > next: Item<K, V> | undefined;
217 > key: K;
218 > value: V;
219 > }
220 >
221 > export const enum Touch {
222 > None = 0,
223 > AsOld = 1,
224 > AsNew = 2
225 > }
226 >
227 > export class LinkedMap<K, V> implements Map<K, V> {
228 >
229 > readonly [Symbol.toStringTag] = 'LinkedMap';
230 >
231 > private _map: Map<K, Item<K, V>>;
232 > private _head: Item<K, V> | undefined;
233 > private _tail: Item<K, V> | undefined;
234 > private _size: number;
235 >
236 > private _state: number;
237 >
238 > constructor() {
239 this._map = new Map<K, Item<K, V>>();
240 this._head = undefined;
243 this._state = 0;
244 }
245 > map.ts
246 > clear(): void {
247 this._map.clear();
248 this._head = undefined;
251 this._state++;
252 }
253 > map.ts
254 > isEmpty(): boolean {
255 return !this._head && !this._tail;
256 }
257 > map.ts
258 > get size(): number {
259 return this._size;
260 }
261 > map.ts
262 > get first(): V | undefined {
263 return this._head?.value;
264 }
265 > map.ts
266 > get last(): V | undefined {
267 return this._tail?.value;
268 }
269 > map.ts
270 > has(key: K): boolean {
271 return this._map.has(key);
272 }
273 > map.ts
274 > get(key: K, touch: Touch = Touch.None): V | undefined {
275 const item = this._map.get(key);
276 if (!item) {
282 return item.value;
283 }
284 > map.ts
285 > set(key: K, value: V, touch: Touch = Touch.None): this {
286 let item = this._map.get(key);
287 if (item) {
311 return this;
312 }
313 > map.ts
314 > delete(key: K): boolean {
315 return !!this.remove(key);
316 }
317 > map.ts
318 > remove(key: K): V | undefined {
319 const item = this._map.get(key);
320 if (!item) {
326 return item.value;
327 }
328 > map.ts
329 > shift(): V | undefined {
330 if (!this._head && !this._tail) {
331 return undefined;
340 return item.value;
341 }
342 > map.ts
343 > forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: unknown): void {
344 const state = this._state;
345 let current = this._head;
356 }
357 }
358 > map.ts
359 > keys(): MapIterator<K> {
360 const map = this;
361 const state = this._state;
381 return iterator;
382 }
383 > map.ts
384 > values(): MapIterator<V> {
385 const map = this;
386 const state = this._state;
406 return iterator;
407 }
408 > map.ts
409 > entries(): MapIterator<[K, V]> {
410 const map = this;
411 const state = this._state;
431 return iterator;
432 }
433 > map.ts
434 > [Symbol.iterator](): MapIterator<[K, V]> {
435 return this.entries();
436 }
437 > map.ts
438 > protected trimOld(newSize: number) {
439 if (newSize >= this.size) {
440 return;
458 this._state++;
459 }
460 > map.ts
461 > protected trimNew(newSize: number) {
462 if (newSize >= this.size) {
463 return;
481 this._state++;
482 }
483 > map.ts
484 > private addItemFirst(item: Item<K, V>): void {
485 // First time Insert
486 if (!this._head && !this._tail) {
495 this._state++;
496 }
497 > map.ts
498 > private addItemLast(item: Item<K, V>): void {
499 // First time Insert
500 if (!this._head && !this._tail) {
509 this._state++;
510 }
511 > map.ts
512 > private removeItem(item: Item<K, V>): void {
513 if (item === this._head && item === this._tail) {
514 this._head = undefined;
546 this._state++;
547 }
548 > map.ts
549 > private touch(item: Item<K, V>, touch: Touch): void {
550 if (!this._head || !this._tail) {
551 throw new Error('Invalid list');
608 }
609 }
610 > map.ts
611 > toJSON(): [K, V][] {
612 const data: [K, V][] = [];
613
618 return data;
619 }
620 > map.ts
621 > fromJSON(data: [K, V][]): void {
622 this.clear();
623
626 }
627 }
628 > } map.ts
629 >
630 > abstract class Cache<K, V> extends LinkedMap<K, V> {
631 >
632 > protected _limit: number;
633 > protected _ratio: number;
634 >
635 > constructor(limit: number, ratio: number = 1) {
636 super();
637 this._limit = limit;
638 this._ratio = Math.min(Math.max(0, ratio), 1);
639 }
640 > map.ts
641 > get limit(): number {
642 return this._limit;
643 }
644 > map.ts
645 > set limit(limit: number) {
646 this._limit = limit;
647 this.checkTrim();
648 }
649 > map.ts
650 > get ratio(): number {
651 return this._ratio;
652 }
653 > map.ts
654 > set ratio(ratio: number) {
655 this._ratio = Math.min(Math.max(0, ratio), 1);
656 this.checkTrim();
657 }
658 > map.ts
659 > override get(key: K, touch: Touch = Touch.AsNew): V | undefined {
660 return super.get(key, touch);
661 }
662 > map.ts
663 > peek(key: K): V | undefined {
664 return super.get(key, Touch.None);
665 }
666 > map.ts
667 > override set(key: K, value: V): this {
668 super.set(key, value, Touch.AsNew);
669 return this;
670 }
671 > map.ts
672 > protected checkTrim() {
673 if (this.size > this._limit) {
674 this.trim(Math.round(this._limit * this._ratio));
675 }
676 }
677 > map.ts
678 > protected abstract trim(newSize: number): void;
679 > }
680 >
681 > export class LRUCache<K, V> extends Cache<K, V> {
682 >
683 > constructor(limit: number, ratio: number = 1) {
684 super(limit, ratio);
685 }
686 > map.ts
687 > protected override trim(newSize: number) {
688 this.trimOld(newSize);
689 }
690 > map.ts
691 > override set(key: K, value: V): this {
692 super.set(key, value);
693 this.checkTrim();
694 return this;
695 }
696 > } map.ts
697 >
698 > export class MRUCache<K, V> extends Cache<K, V> {
699 >
700 > constructor(limit: number, ratio: number = 1) {
701 super(limit, ratio);
702 }
703 > map.ts
704 > protected override trim(newSize: number) {
705 this.trimNew(newSize);
706 }
707 > map.ts
708 > override set(key: K, value: V): this {
709 if (this._limit <= this.size && !this.has(key)) {
710 this.trim(Math.round(this._limit * this._ratio) - 1);
714 return this;
715 }
716 > } map.ts
717 >
718 > export class CounterSet<T> {
719
720 private map = new Map<T, number>();
721 > map.ts
722 > add(value: T): CounterSet<T> {
723 this.map.set(value, (this.map.get(value) || 0) + 1);
724 return this;
725 }
726 > map.ts
727 > delete(value: T): boolean {
728 let counter = this.map.get(value) || 0;
729
742 return true;
743 }
744 > map.ts
745 > has(value: T): boolean {
746 return this.map.has(value);
747 }
748 > } map.ts
749 >
750 > /**
751 > * A map that allows access both by keys and values.
752 > * **NOTE**: values need to be unique.
753 > */
754 > export class BidirectionalMap<K, V> {
755 >
756 > private readonly _m1 = new Map<K, V>();
757 > private readonly _m2 = new Map<V, K>();
758 >
759 > constructor(entries?: readonly (readonly [K, V])[]) {
760 if (entries) {
761 for (const [key, value] of entries) {
764 }
765 }
766 > map.ts
767 > clear(): void {
768 this._m1.clear();
769 this._m2.clear();
770 }
771 > map.ts
772 > set(key: K, value: V): void {
773 this._m1.set(key, value);
774 this._m2.set(value, key);
775 }
776 > map.ts
777 > get(key: K): V | undefined {
778 return this._m1.get(key);
779 }
780 > map.ts
781 > getKey(value: V): K | undefined {
782 return this._m2.get(value);
783 }
784 > map.ts
785 > delete(key: K): boolean {
786 const value = this._m1.get(key);
787 if (value === undefined) {
792 return true;
793 }
794 > map.ts
795 > forEach(callbackfn: (value: V, key: K, map: BidirectionalMap<K, V>) => void, thisArg?: unknown): void {
796 this._m1.forEach((value, key) => {
797 callbackfn.call(thisArg, value, key, this);
798 });
799 }
800 > map.ts
801 > keys(): IterableIterator<K> {
802 return this._m1.keys();
803 }
804 > map.ts
805 > values(): IterableIterator<V> {
806 return this._m1.values();
807 }
808 > } map.ts
809 >
810 > export class SetMap<K, V> {
811
812 private map = new Map<K, Set<V>>();
813 > map.ts
814 > add(key: K, value: V): void {
815 let values = this.map.get(key);
816
822 values.add(value);
823 }
824 > map.ts
825 > delete(key: K, value: V): void {
826 const values = this.map.get(key);
827
836 }
837 }
838 > map.ts
839 > forEach(key: K, fn: (value: V) => void): void {
840 const values = this.map.get(key);
841
846 values.forEach(fn);
847 }
848 > map.ts
849 > get(key: K): ReadonlySet<V> {
850 const values = this.map.get(key);
851 if (!values) {
854 return values;
855 }
856 > } map.ts
857 >
858 > export function mapsStrictEqualIgnoreOrder(a: Map<unknown, unknown>, b: Map<unknown, unknown>): boolean {
859 if (a === b) {
860 return true;
879 return true;
880 }
881 > map.ts
882 > /**
883 > * A map that is addressable with an arbitrary number of keys. This is useful in high performance
884 > * scenarios where creating a composite key whenever the data is accessed is too expensive. For
885 > * example for a very hot function, constructing a string like `first-second-third` for every call
886 > * will cause a significant hit to performance.
887 > */
888 > export class NKeyMap<TValue, TKeys extends (string | boolean | number)[]> {
889 private _data: Map<any, any> = new Map();
890 > map.ts
891 > /**
892 > * Sets a value on the map. Note that unlike a standard `Map`, the first argument is the value.
893 > * This is because the spread operator is used for the keys and must be last..
894 > * @param value The value to set.
895 > * @param keys The keys for the value.
896 > */
897 > public set(value: TValue, ...keys: [...TKeys]): void {
898 let currentMap = this._data;
899 for (let i = 0; i < keys.length - 1; i++) {
907 currentMap.set(keys[keys.length - 1], value);
908 }
909 > map.ts
910 > public get(...keys: [...TKeys]): TValue | undefined {
911 let currentMap = this._data;
912 for (let i = 0; i < keys.length - 1; i++) {
919 return currentMap.get(keys[keys.length - 1]);
920 }
921 > map.ts
922 > public delete(...keys: [...TKeys]): boolean {
923 const maps: Map<any, any>[] = [this._data];
924 let currentMap = this._data;
939 return deleted;
940 }
941 > map.ts
942 > public deleteAll(...keys: Partial<TKeys>): boolean {
943 if (keys.length === 0) {
944 const hadData = this._data.size > 0;
964 return deleted;
965 }
966 > map.ts
967 > public clear(): void {
968 this._data.clear();
969 }
970 > map.ts
971 > public *getAll(...keys: Partial<TKeys>): IterableIterator<TValue> {
972 let currentMap = this._data;
973 for (const key of keys) {
980 yield* this._values(currentMap);
981 }
982 > map.ts
983 > public *values(): IterableIterator<TValue> {
984 yield* this._values(this._data);
985 }
986 > map.ts
987 > private *_values(map: Map<any, any>): IterableIterator<TValue> {
988 for (const value of map.values()) {
989 if (value instanceof Map) {
994 }
995 }
996 > map.ts
997 > /**
998 > * Get a textual representation of the map for debugging purposes.
999 > */
1000 > public toString(): string {
1001 const printMap = (map: Map<any, any>, depth: number): string => {
1002 let result = '';
1014 return printMap(this._data, 0);
1015 }
1016 > } map.ts
src/vs/base/common/types.ts 295 covered LOC · 29 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- types.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { assert } from './assert.js';
7 >
8 > /**
9 > * @returns whether the provided parameter is a JavaScript String or not.
10 > */
11 > export function isString(str: unknown): str is string {
12 > return (typeof str === 'string'); types.ts
13 > }
14 > types.ts
15 > /**
16 > * @returns whether the provided parameter is a JavaScript Array and each element in the array is a string.
17 > */
18 > export function isStringArray(value: unknown): value is string[] {
19 return isArrayOf(value, isString);
20 }
21 > types.ts
22 > /**
23 > * @returns whether the provided parameter is a JavaScript Array and each element in the array satisfies the provided type guard.
24 > */
25 > export function isArrayOf<T>(value: unknown, check: (item: unknown) => item is T): value is T[] {
26 return Array.isArray(value) && value.every(check);
27 }
28 > types.ts
29 > /**
30 > * @returns whether the provided parameter is of type `object` but **not**
31 > * `null`, an `array`, a `regexp`, nor a `date`.
32 > */
33 > export function isObject(obj: unknown): obj is Object {
34 > // The method can't do a type cast since there are type (like strings) which types.ts
35 > // are subclasses of any put not positvely matched by the function. Hence type
36 > // narrowing results in wrong results.
37 > return typeof obj === 'object'
38 > && obj !== null types.ts
39 > && !Array.isArray(obj)
40 > && !(obj instanceof RegExp) types.ts
41 > && !(obj instanceof Date);
42 > } types.ts
43 > types.ts
44 > /**
45 > * @returns whether the provided parameter is of type `Buffer` or Uint8Array dervived type
46 > */
47 > export function isTypedArray(obj: unknown): obj is Object {
48 const TypedArray = Object.getPrototypeOf(Uint8Array);
49 return typeof obj === 'object'
50 && obj instanceof TypedArray;
51 }
52 > types.ts
53 > /**
54 > * In **contrast** to just checking `typeof` this will return `false` for `NaN`.
55 > * @returns whether the provided parameter is a JavaScript Number or not.
56 > */
57 > export function isNumber(obj: unknown): obj is number {
58 return (typeof obj === 'number' && !isNaN(obj));
59 }
60 > types.ts
61 > /**
62 > * @returns whether the provided parameter is an Iterable, casting to the given generic
63 > */
64 > export function isIterable<T>(obj: unknown): obj is Iterable<T> {
65 // eslint-disable-next-line local/code-no-any-casts
66 return !!obj && typeof (obj as any)[Symbol.iterator] === 'function';
67 }
68 > types.ts
69 > /**
70 > * @returns whether the provided parameter is an Iterable, casting to the given generic
71 > */
72 > export function isAsyncIterable<T>(obj: unknown): obj is AsyncIterable<T> {
73 // eslint-disable-next-line local/code-no-any-casts
74 return !!obj && typeof (obj as any)[Symbol.asyncIterator] === 'function';
75 }
76 > types.ts
77 > /**
78 > * @returns whether the provided parameter is a JavaScript Boolean or not.
79 > */
80 > export function isBoolean(obj: unknown): obj is boolean {
81 return (obj === true || obj === false);
82 }
83 > types.ts
84 > /**
85 > * @returns whether the provided parameter is undefined.
86 > */
87 > export function isUndefined(obj: unknown): obj is undefined {
88 return (typeof obj === 'undefined');
89 }
90 > types.ts
91 > /**
92 > * @returns whether the provided parameter is defined.
93 > */
94 > export function isDefined<T>(arg: T | null | undefined): arg is T {
95 return !isUndefinedOrNull(arg);
96 }
97 > types.ts
98 > /**
99 > * @returns whether the provided parameter is undefined or null.
100 > */
101 > export function isUndefinedOrNull(obj: unknown): obj is undefined | null {
102 return (isUndefined(obj) || obj === null);
103 }
104 > types.ts
105 >
106 > export function assertType(condition: unknown, type?: string): asserts condition {
107 if (!condition) {
108 throw new Error(type ? `Unexpected type, expected '${type}'` : 'Unexpected type');
109 }
110 }
111 > types.ts
112 > /**
113 > * Asserts that the argument passed in is neither undefined nor null.
114 > *
115 > * @see {@link assertDefined} for a similar utility that leverages TS assertion functions to narrow down the type of `arg` to be non-nullable.
116 > */
117 > export function assertReturnsDefined<T>(arg: T | null | undefined): NonNullable<T> {
118 assert(
119 arg !== null && arg !== undefined,
123 return arg;
124 }
125 > types.ts
126 > /**
127 > * Asserts that a provided `value` is `defined` - not `null` or `undefined`,
128 > * throwing an error with the provided error or error message, while also
129 > * narrowing down the type of the `value` to be `NonNullable` using TS
130 > * assertion functions.
131 > *
132 > * @throws if the provided `value` is `null` or `undefined`.
133 > *
134 > * ## Examples
135 > *
136 > * ```typescript
137 > * // an assert with an error message
138 > * assertDefined('some value', 'String constant is not defined o_O.');
139 > *
140 > * // `throws!` the provided error
141 > * assertDefined(null, new Error('Should throw this error.'));
142 > *
143 > * // narrows down the type of `someValue` to be non-nullable
144 > * const someValue: string | undefined | null = blackbox();
145 > * assertDefined(someValue, 'Some value must be defined.');
146 > * console.log(someValue.length); // now type of `someValue` is `string`
147 > * ```
148 > *
149 > * @see {@link assertReturnsDefined} for a similar utility but without assertion.
150 > * @see {@link https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions typescript-3-7.html#assertion-functions}
151 > */
152 > export function assertDefined<T>(value: T, error: string | NonNullable<Error>): asserts value is NonNullable<T> {
153 if (value === null || value === undefined) {
154 const errorToThrow = typeof error === 'string' ? new Error(error) : error;
157 }
158 }
159 > types.ts
160 > /**
161 > * Asserts that each argument passed in is neither undefined nor null.
162 > */
163 > export function assertReturnsAllDefined<T1, T2>(t1: T1 | null | undefined, t2: T2 | null | undefined): [T1, T2];
164 > export function assertReturnsAllDefined<T1, T2, T3>(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined): [T1, T2, T3];
165 > export function assertReturnsAllDefined<T1, T2, T3, T4>(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined, t4: T4 | null | undefined): [T1, T2, T3, T4];
166 > export function assertReturnsAllDefined(...args: (unknown | null | undefined)[]): unknown[] {
167 const result = [];
168
179 return result;
180 }
181 > types.ts
182 > /**
183 > * Checks if the provided value is one of the vales in the provided list.
184 > *
185 > * ## Examples
186 > *
187 > * ```typescript
188 > * // note! item type is a `subset of string`
189 > * type TItem = ':' | '.' | '/';
190 > *
191 > * // note! item is type of `string` here
192 > * const item: string = ':';
193 > * // list of the items to check against
194 > * const list: TItem[] = [':', '.'];
195 > *
196 > * // ok
197 > * assert(
198 > * isOneOf(item, list),
199 > * 'Must succeed.',
200 > * );
201 > *
202 > * // `item` is of `TItem` type now
203 > * ```
204 > */
205 > export const isOneOf = <TType, TSubtype extends TType>(
206 value: TType,
207 validValues: readonly TSubtype[],
211 return validValues.includes(<TSubtype>value);
212 };
213 > types.ts
214 > /**
215 > * Compile-time type check of a variable.
216 > */
217 > export function typeCheck<T = never>(_thing: NoInfer<T>): void { }
218 >
219 > const hasOwnProperty = Object.prototype.hasOwnProperty;
220 >
221 > /**
222 > * @returns whether the provided parameter is an empty JavaScript Object or not.
223 > */
224 > export function isEmptyObject(obj: unknown): obj is object {
225 if (!isObject(obj)) {
226 return false;
235 return true;
236 }
237 > types.ts
238 > /**
239 > * @returns whether the provided parameter is a JavaScript Function or not.
240 > */
241 > export function isFunction(obj: unknown): obj is Function {
242 return (typeof obj === 'function');
243 }
244 > types.ts
245 > /**
246 > * @returns whether the provided parameters is are JavaScript Function or not.
247 > */
248 > export function areFunctions(...objects: unknown[]): boolean {
249 return objects.length > 0 && objects.every(isFunction);
250 }
251 > types.ts
252 > export type TypeConstraint = string | Function;
253 >
254 > export function validateConstraints(args: unknown[], constraints: Array<TypeConstraint | undefined>): void {
255 const len = Math.min(args.length, constraints.length);
256 for (let i = 0; i < len; i++) {
258 }
259 }
260 > types.ts
261 > export function validateConstraint(arg: unknown, constraint: TypeConstraint | undefined): void {
262
263 if (isString(constraint)) {
283 }
284 }
285 > types.ts
286 > /**
287 > * Helper type assertion that safely upcasts a type to a supertype.
288 > *
289 > * This can be used to make sure the argument correctly conforms to the subtype while still being able to pass it
290 > * to contexts that expects the supertype.
291 > */
292 > export function upcast<Base, Sub extends Base = Base>(x: Sub): Base {
293 return x;
294 }
295 > types.ts
296 > type AddFirstParameterToFunction<T, TargetFunctionsReturnType, FirstParameter> = T extends (...args: any[]) => TargetFunctionsReturnType ?
297 > // Function: add param to function
298 > (firstArg: FirstParameter, ...args: Parameters<T>) => ReturnType<T> :
299 >
300 > // Else: just leave as is
301 > T;
302 >
303 > /**
304 > * Allows to add a first parameter to functions of a type.
305 > */
306 > export type AddFirstParameterToFunctions<Target, TargetFunctionsReturnType, FirstParameter> = {
307 > // For every property
308 > [K in keyof Target]: AddFirstParameterToFunction<Target[K], TargetFunctionsReturnType, FirstParameter>;
309 > };
310 >
311 > /**
312 > * Given an object with all optional properties, requires at least one to be defined.
313 > * i.e. AtLeastOne<MyObject>;
314 > */
315 > export type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];
316 >
317 > /**
318 > * Only picks the non-optional properties of a type.
319 > */
320 > export type OmitOptional<T> = { [K in keyof T as T[K] extends Required<T>[K] ? K : never]: T[K] };
321 >
322 > /**
323 > * A type that removed readonly-less from all properties of `T`
324 > */
325 > export type Mutable<T> = {
326 > -readonly [P in keyof T]: T[P]
327 > };
328 >
329 > /**
330 > * A type that adds readonly to all properties of T, recursively.
331 > */
332 > export type DeepImmutable<T> = T extends (infer U)[]
333 > ? ReadonlyArray<DeepImmutable<U>>
334 > : T extends ReadonlyArray<infer U>
335 > ? ReadonlyArray<DeepImmutable<U>>
336 > : T extends Map<infer K, infer V>
337 > ? ReadonlyMap<K, DeepImmutable<V>>
338 > : T extends Set<infer U>
339 > ? ReadonlySet<DeepImmutable<U>>
340 > : T extends object
341 > ? {
342 > readonly [K in keyof T]: DeepImmutable<T[K]>;
343 > }
344 > : T;
345 >
346 > /**
347 > * A single object or an array of the objects.
348 > */
349 > export type SingleOrMany<T> = T | T[];
350 >
351 > /**
352 > * Given a `type X = { foo?: string }` checking that an object `satisfies X`
353 > * will ensure each property was explicitly defined, ensuring no properties
354 > * are omitted or forgotten.
355 > */
356 > export type WithDefinedProps<T> = { [K in keyof Required<T>]: T[K] };
357 >
358 >
359 > /**
360 > * A type that recursively makes all properties of `T` required
361 > */
362 > export type DeepRequiredNonNullable<T> = {
363 > [P in keyof T]-?: T[P] extends object ? DeepRequiredNonNullable<T[P]> : Required<NonNullable<T[P]>>;
364 > };
365 >
366 >
367 > /**
368 > * Represents a type that is a partial version of a given type `T`, where all properties are optional and can be deeply nested.
369 > */
370 > export type DeepPartial<T> = {
371 > [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : Partial<T[P]>;
372 > };
373 >
374 > /**
375 > * Represents a type that is a partial version of a given type `T`, except a subset.
376 > */
377 > export type PartialExcept<T, K extends keyof T> = Partial<Omit<T, K>> & Pick<T, K>;
378 >
379 >
380 > type KeysOfUnionType<T> = T extends T ? keyof T : never;
381 > type FilterType<T, TTest> = T extends TTest ? T : never;
382 > type MakeOptionalAndTrue<T extends object> = { [K in keyof T]?: true };
383 >
384 > /**
385 > * Type guard that checks if an object has specific keys and narrows the type accordingly.
386 > *
387 > * @param x - The object to check
388 > * @param key - An object with boolean values indicating which keys to check for
389 > * @returns true if all specified keys exist in the object, false otherwise
390 > *
391 > * @example
392 > * ```typescript
393 > * type A = { a: string };
394 > * type B = { b: number };
395 > * const obj: A | B = getObject();
396 > *
397 > * if (hasKey(obj, { a: true })) {
398 > * // obj is now narrowed to type A
399 > * console.log(obj.a);
400 > * }
401 > * ```
402 > */
403 > export function hasKey<T extends object, TKeys extends MakeOptionalAndTrue<T>>(x: T, key: TKeys): x is FilterType<T, { [K in KeysOfUnionType<T> & keyof TKeys]: unknown }> {
404 for (const k in key) {
405 if (!(k in x)) {
src/vs/base/common/network.ts 292 covered LOC · 20 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- network.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as errors from './errors.js';
7 > import * as platform from './platform.js';
8 > import { equalsIgnoreCase, startsWithIgnoreCase } from './strings.js';
9 > import { URI } from './uri.js';
10 > import * as paths from './path.js';
11 >
12 > export namespace Schemas {
13 >
14 > /**
15 > * A schema that is used for models that exist in memory
16 > * only and that have no correspondence on a server or such.
17 > */
18 > export const inMemory = 'inmemory';
19 >
20 > /**
21 > * A schema that is used for setting files
22 > */
23 > export const vscode = 'vscode';
24 >
25 > /**
26 > * A schema that is used for internal private files
27 > */
28 > export const internal = 'private';
29 >
30 > /**
31 > * A walk-through document.
32 > */
33 > export const walkThrough = 'walkThrough';
34 >
35 > /**
36 > * An embedded code snippet.
37 > */
38 > export const walkThroughSnippet = 'walkThroughSnippet';
39 >
40 > export const http = 'http';
41 >
42 > export const https = 'https';
43 >
44 > export const file = 'file';
45 >
46 > export const mailto = 'mailto';
47 >
48 > export const untitled = 'untitled';
49 >
50 > export const data = 'data';
51 >
52 > export const command = 'command';
53 >
54 > export const vscodeRemote = 'vscode-remote';
55 >
56 > export const vscodeRemoteResource = 'vscode-remote-resource';
57 >
58 > export const vscodeManagedRemoteResource = 'vscode-managed-remote-resource';
59 >
60 > export const vscodeUserData = 'vscode-userdata';
61 >
62 > export const vscodeCustomEditor = 'vscode-custom-editor';
63 >
64 > export const vscodeNotebookCell = 'vscode-notebook-cell';
65 > export const vscodeNotebookCellMetadata = 'vscode-notebook-cell-metadata';
66 > export const vscodeNotebookCellMetadataDiff = 'vscode-notebook-cell-metadata-diff';
67 > export const vscodeNotebookCellOutput = 'vscode-notebook-cell-output';
68 > export const vscodeNotebookCellOutputDiff = 'vscode-notebook-cell-output-diff';
69 > export const vscodeNotebookMetadata = 'vscode-notebook-metadata';
70 > export const vscodeInteractiveInput = 'vscode-interactive-input';
71 >
72 > export const vscodeSettings = 'vscode-settings';
73 >
74 > export const vscodeWorkspaceTrust = 'vscode-workspace-trust';
75 >
76 > export const vscodeTerminal = 'vscode-terminal';
77 >
78 > /** Scheme used for the image carousel editor. */
79 > export const vscodeImageCarousel = 'vscode-image-carousel';
80 >
81 > /** Scheme used for code blocks in chat. */
82 > export const vscodeChatCodeBlock = 'vscode-chat-code-block';
83 >
84 > /** Scheme used for LHS of code compare (aka diff) blocks in chat. */
85 > export const vscodeChatCodeCompareBlock = 'vscode-chat-code-compare-block';
86 >
87 > /** Scheme used for the chat input editor. */
88 > export const vscodeChatEditor = 'vscode-chat-editor';
89 >
90 > /** Scheme used for the chat input part */
91 > export const vscodeChatInput = 'chatSessionInput';
92 >
93 > /** Scheme used for local chat session content */
94 > export const vscodeLocalChatSession = 'vscode-chat-session';
95 >
96 > /**
97 > * Scheme used internally for webviews that aren't linked to a resource (i.e. not custom editors)
98 > */
99 > export const webviewPanel = 'webview-panel';
100 >
101 > /**
102 > * Scheme used for loading the wrapper html and script in webviews.
103 > */
104 > export const vscodeWebview = 'vscode-webview';
105 >
106 > /**
107 > * Scheme used for integrated browser tabs using WebContentsView.
108 > */
109 > export const vscodeBrowser = 'vscode-browser';
110 >
111 > /**
112 > * Scheme used for extension pages
113 > */
114 > export const extension = 'extension';
115 >
116 > /**
117 > * Scheme used as a replacement of `file` scheme to load
118 > * files with our custom protocol handler (desktop only).
119 > */
120 > export const vscodeFileResource = 'vscode-file';
121 >
122 > /**
123 > * Scheme used for temporary resources
124 > */
125 > export const tmp = 'tmp';
126 >
127 > /**
128 > * Scheme used vs live share
129 > */
130 > export const vsls = 'vsls';
131 >
132 > /**
133 > * Scheme used for the Source Control commit input's text document
134 > */
135 > export const vscodeSourceControl = 'vscode-scm';
136 >
137 > /**
138 > * Scheme used for input box for creating comments.
139 > */
140 > export const commentsInput = 'comment';
141 >
142 > /**
143 > * Scheme used for special rendering of settings in the release notes
144 > */
145 > export const codeSetting = 'code-setting';
146 >
147 > /**
148 > * Scheme used for output panel resources
149 > */
150 > export const outputChannel = 'output';
151 >
152 > /**
153 > * Scheme used for the accessible view
154 > */
155 > export const accessibleView = 'accessible-view';
156 >
157 > /**
158 > * Used for snapshots of chat edits
159 > */
160 > export const chatEditingSnapshotScheme = 'chat-editing-snapshot-text-model';
161 > export const chatEditingModel = 'chat-editing-text-model';
162 >
163 > /**
164 > * Used for rendering multidiffs in copilot agent sessions
165 > */
166 > export const copilotPr = 'copilot-pr';
167 > }
168 >
169 > export function matchesScheme(target: URI | string, scheme: string): boolean {
170 if (URI.isUri(target)) {
171 return equalsIgnoreCase(target.scheme, scheme);
174 }
175 }
176 > network.ts
177 > export function matchesSomeScheme(target: URI | string, ...schemes: string[]): boolean {
178 return schemes.some(scheme => matchesScheme(target, scheme));
179 }
180 > network.ts
181 > export const connectionTokenCookieName = 'vscode-tkn';
182 > export const connectionTokenQueryName = 'tkn';
183 >
184 > class RemoteAuthoritiesImpl {
185 > private readonly _hosts: { [authority: string]: string | undefined } = Object.create(null);
186 > private readonly _ports: { [authority: string]: number | undefined } = Object.create(null);
187 > private readonly _connectionTokens: { [authority: string]: string | undefined } = Object.create(null);
188 > private _preferredWebSchema: 'http' | 'https' = 'http';
189 > private _delegate: ((uri: URI) => URI) | null = null;
190 > private _serverRootPath: string = '/';
191 >
192 > setPreferredWebSchema(schema: 'http' | 'https') {
193 this._preferredWebSchema = schema;
194 }
195 > network.ts
196 > setDelegate(delegate: (uri: URI) => URI): void {
197 this._delegate = delegate;
198 }
199 > network.ts
200 > setServerRootPath(product: { quality?: string; commit?: string }, serverBasePath: string | undefined): void {
201 this._serverRootPath = paths.posix.join(serverBasePath ?? '/', getServerProductSegment(product));
202 }
203 > network.ts
204 > getServerRootPath(): string {
205 return this._serverRootPath;
206 }
207 > network.ts
208 > private get _remoteResourcesPath(): string {
209 return paths.posix.join(this._serverRootPath, Schemas.vscodeRemoteResource);
210 }
211 > network.ts
212 > set(authority: string, host: string, port: number): void {
213 this._hosts[authority] = host;
214 this._ports[authority] = port;
215 }
216 > network.ts
217 > setConnectionToken(authority: string, connectionToken: string): void {
218 this._connectionTokens[authority] = connectionToken;
219 }
220 > network.ts
221 > getPreferredWebSchema(): 'http' | 'https' {
222 return this._preferredWebSchema;
223 }
224 > network.ts
225 > rewrite(uri: URI): URI {
226 if (this._delegate) {
227 try {
250 });
251 }
252 > } network.ts
253 >
254 > export const RemoteAuthorities = new RemoteAuthoritiesImpl();
255 >
256 > export function getServerProductSegment(product: { quality?: string; commit?: string }) {
257 return `${product.quality ?? 'oss'}-${product.commit ?? 'dev'}`;
258 }
259 > network.ts
260 > /**
261 > * A string pointing to a path inside the app. It should not begin with ./ or ../
262 > */
263 > export type AppResourcePath = (
264 > `a${string}` | `b${string}` | `c${string}` | `d${string}` | `e${string}` | `f${string}`
265 > | `g${string}` | `h${string}` | `i${string}` | `j${string}` | `k${string}` | `l${string}`
266 > | `m${string}` | `n${string}` | `o${string}` | `p${string}` | `q${string}` | `r${string}`
267 > | `s${string}` | `t${string}` | `u${string}` | `v${string}` | `w${string}` | `x${string}`
268 > | `y${string}` | `z${string}`
269 > );
270 >
271 > export const builtinExtensionsPath: AppResourcePath = 'vs/../../extensions';
272 > export const nodeModulesPath: AppResourcePath = 'vs/../../node_modules';
273 > export const nodeModulesAsarPath: AppResourcePath = 'vs/../../node_modules.asar';
274 > export const nodeModulesAsarUnpackedPath: AppResourcePath = 'vs/../../node_modules.asar.unpacked';
275 >
276 > export const VSCODE_AUTHORITY = 'vscode-app';
277 >
278 > class FileAccessImpl {
279 >
280 > private static readonly FALLBACK_AUTHORITY = VSCODE_AUTHORITY;
281 >
282 > /**
283 > * Returns a URI to use in contexts where the browser is responsible
284 > * for loading (e.g. fetch()) or when used within the DOM.
285 > *
286 > * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context.
287 > */
288 > asBrowserUri(resourcePath: AppResourcePath | ''): URI {
289 const uri = this.toUri(resourcePath);
290 return this.uriToBrowserUri(uri);
291 }
292 > network.ts
293 > /**
294 > * Returns a URI to use in contexts where the browser is responsible
295 > * for loading (e.g. fetch()) or when used within the DOM.
296 > *
297 > * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context.
298 > */
299 > uriToBrowserUri(uri: URI): URI {
300 // Handle remote URIs via `RemoteAuthorities`
301 if (uri.scheme === Schemas.vscodeRemote) {
328 return uri;
329 }
330 > network.ts
331 > /**
332 > * Returns the `file` URI to use in contexts where node.js
333 > * is responsible for loading.
334 > */
335 > asFileUri(resourcePath: AppResourcePath | ''): URI {
336 const uri = this.toUri(resourcePath);
337 return this.uriToFileUri(uri);
338 }
339 > network.ts
340 > /**
341 > * Returns the `file` URI to use in contexts where node.js
342 > * is responsible for loading.
343 > */
344 > uriToFileUri(uri: URI): URI {
345 // Only convert the URI if it is `vscode-file:` scheme
346 if (uri.scheme === Schemas.vscodeFileResource) {
358 return uri;
359 }
360 > network.ts
361 > private toUri(uriOrModule: URI | string): URI {
362 if (URI.isUri(uriOrModule)) {
363 return uriOrModule;
379 throw new Error('Cannot determine URI for module id!');
380 }
381 > } network.ts
382 >
383 > export const FileAccess = new FileAccessImpl();
384 >
385 > export const CacheControlheaders: Record<string, string> = Object.freeze({
386 > 'Cache-Control': 'no-cache, no-store'
387 > });
388 >
389 > export const DocumentPolicyheaders: Record<string, string> = Object.freeze({
390 > 'Document-Policy': 'include-js-call-stacks-in-crash-reports'
391 > });
392 >
393 > export namespace COI {
394 >
395 > const coiHeaders = new Map<'3' | '2' | '1' | string, Record<string, string>>([
396 > ['1', { 'Cross-Origin-Opener-Policy': 'same-origin' }],
397 > ['2', { 'Cross-Origin-Embedder-Policy': 'require-corp' }],
398 > ['3', { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp' }],
399 > ]);
400 >
401 > export const CoopAndCoep = Object.freeze(coiHeaders.get('3'));
402 >
403 > const coiSearchParamName = 'vscode-coi';
404 >
405 > /**
406 > * Extract desired headers from `vscode-coi` invocation
407 > */
408 > export function getHeadersFromQuery(url: string | URI | URL): Record<string, string> | undefined {
409 let params: URLSearchParams | undefined;
410 if (typeof url === 'string') {
421 return coiHeaders.get(value);
422 }
423 > network.ts
424 > /**
425 > * Add the `vscode-coi` query attribute based on wanting `COOP` and `COEP`. Will be a noop when `crossOriginIsolated`
426 > * isn't enabled the current context
427 > */
428 > export function addSearchParam(urlOrSearch: URLSearchParams | Record<string, string>, coop: boolean, coep: boolean): void {
429 if (!(globalThis as typeof globalThis & { crossOriginIsolated?: boolean }).crossOriginIsolated) {
430 // depends on the current context being COI
src/vs/base/common/resources.ts 253 covered LOC · 23 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- resources.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CharCode } from './charCode.js';
7 > import * as extpath from './extpath.js';
8 > import { Schemas } from './network.js';
9 > import * as paths from './path.js';
10 > import { isLinux, isWindows } from './platform.js';
11 > import { compare as strCompare, equalsIgnoreCase } from './strings.js';
12 > import { URI, uriToFsPath } from './uri.js';
13 >
14 > export function originalFSPath(uri: URI): string {
15 return uriToFsPath(uri, true);
16 }
18 > //#region IExtUri
19 >
20 > export interface IExtUri {
21 >
22 > // --- identity
23 >
24 > /**
25 > * Compares two uris.
26 > *
27 > * @param uri1 Uri
28 > * @param uri2 Uri
29 > * @param ignoreFragment Ignore the fragment (defaults to `false`)
30 > */
31 > compare(uri1: URI, uri2: URI, ignoreFragment?: boolean): number;
32 >
33 > /**
34 > * Tests whether two uris are equal
35 > *
36 > * @param uri1 Uri
37 > * @param uri2 Uri
38 > * @param ignoreFragment Ignore the fragment (defaults to `false`)
39 > */
40 > isEqual(uri1: URI | undefined, uri2: URI | undefined, ignoreFragment?: boolean): boolean;
41 >
42 > /**
43 > * Tests whether a `candidate` URI is a parent or equal of a given `base` URI.
44 > *
45 > * @param base A uri which is "longer" or at least same length as `parentCandidate`
46 > * @param parentCandidate A uri which is "shorter" or up to same length as `base`
47 > * @param ignoreFragment Ignore the fragment (defaults to `false`)
48 > */
49 > isEqualOrParent(base: URI, parentCandidate: URI, ignoreFragment?: boolean): boolean;
50 >
51 > /**
52 > * Creates a key from a resource URI to be used to resource comparison and for resource maps.
53 > * @see {@link ResourceMap}
54 > * @param uri Uri
55 > * @param ignoreFragment Ignore the fragment (defaults to `false`)
56 > */
57 > getComparisonKey(uri: URI, ignoreFragment?: boolean): string;
58 >
59 > /**
60 > * Whether the casing of the path-component of the uri should be ignored.
61 > */
62 > ignorePathCasing(uri: URI): boolean;
63 >
64 > // --- path math
65 >
66 > basenameOrAuthority(resource: URI): string;
67 >
68 > /**
69 > * Returns the basename of the path component of an uri.
70 > * @param resource
71 > */
72 > basename(resource: URI): string;
73 >
74 > /**
75 > * Returns the extension of the path component of an uri.
76 > * @param resource
77 > */
78 > extname(resource: URI): string;
79 > /**
80 > * Return a URI representing the directory of a URI path.
81 > *
82 > * @param resource The input URI.
83 > * @returns The URI representing the directory of the input URI.
84 > */
85 > dirname(resource: URI): URI;
86 > /**
87 > * Join a URI path with path fragments and normalizes the resulting path.
88 > *
89 > * @param resource The input URI.
90 > * @param pathFragment The path fragment to add to the URI path.
91 > * @returns The resulting URI.
92 > */
93 > joinPath(resource: URI, ...pathFragment: string[]): URI;
94 > /**
95 > * Normalizes the path part of a URI: Resolves `.` and `..` elements with directory names.
96 > *
97 > * @param resource The URI to normalize the path.
98 > * @returns The URI with the normalized path.
99 > */
100 > normalizePath(resource: URI): URI;
101 > /**
102 > *
103 > * @param from
104 > * @param to
105 > */
106 > relativePath(from: URI, to: URI): string | undefined;
107 > /**
108 > * Resolves an absolute or relative path against a base URI.
109 > * The path can be relative or absolute posix or a Windows path
110 > */
111 > resolvePath(base: URI, path: string): URI;
112 >
113 > // --- misc
114 >
115 > /**
116 > * Returns true if the URI path is absolute.
117 > */
118 > isAbsolutePath(resource: URI): boolean;
119 > /**
120 > * Tests whether the two authorities are the same
121 > */
122 > isEqualAuthority(a1: string, a2: string): boolean;
123 > /**
124 > * Returns true if the URI path has a trailing path separator
125 > */
126 > hasTrailingPathSeparator(resource: URI, sep?: string): boolean;
127 > /**
128 > * Removes a trailing path separator, if there's one.
129 > * Important: Doesn't remove the first slash, it would make the URI invalid
130 > */
131 > removeTrailingPathSeparator(resource: URI, sep?: string): URI;
132 > /**
133 > * Adds a trailing path separator to the URI if there isn't one already.
134 > * For example, c:\ would be unchanged, but c:\users would become c:\users\
135 > */
136 > addTrailingPathSeparator(resource: URI, sep?: string): URI;
137 > }
138 >
139 > export class ExtUri implements IExtUri {
140 >
141 > constructor(private _ignorePathCasing: (uri: URI) => boolean) { }
142 >
143 > compare(uri1: URI, uri2: URI, ignoreFragment: boolean = false): number {
144 if (uri1 === uri2) {
145 return 0;
147 return strCompare(this.getComparisonKey(uri1, ignoreFragment), this.getComparisonKey(uri2, ignoreFragment));
148 }
149 > resources.ts
150 > isEqual(uri1: URI | undefined, uri2: URI | undefined, ignoreFragment: boolean = false): boolean {
151 if (uri1 === uri2) {
152 return true;
157 return this.getComparisonKey(uri1, ignoreFragment) === this.getComparisonKey(uri2, ignoreFragment);
158 }
159 > resources.ts
160 > getComparisonKey(uri: URI, ignoreFragment: boolean = false): string {
161 return uri.with({
162 path: this._ignorePathCasing(uri) ? uri.path.toLowerCase() : undefined,
164 }).toString();
165 }
166 > resources.ts
167 > ignorePathCasing(uri: URI): boolean {
168 return this._ignorePathCasing(uri);
169 }
170 > resources.ts
171 > isEqualOrParent(base: URI, parentCandidate: URI, ignoreFragment: boolean = false): boolean {
172 if (base.scheme === parentCandidate.scheme) {
173 if (base.scheme === Schemas.file) {
180 return false;
181 }
182 > resources.ts
183 > // --- path math
184 >
185 > joinPath(resource: URI, ...pathFragment: string[]): URI {
186 return URI.joinPath(resource, ...pathFragment);
187 }
188 > resources.ts
189 > basenameOrAuthority(resource: URI): string {
190 return basename(resource) || resource.authority;
191 }
192 > resources.ts
193 > basename(resource: URI, suffix?: string): string {
194 return paths.posix.basename(resource.path, suffix);
195 }
196 > resources.ts
197 > extname(resource: URI): string {
198 return paths.posix.extname(resource.path);
199 }
200 > resources.ts
201 > dirname(resource: URI): URI {
202 if (resource.path.length === 0) {
203 return resource;
217 });
218 }
219 > resources.ts
220 > normalizePath(resource: URI): URI {
221 if (!resource.path.length) {
222 return resource;
232 });
233 }
234 > resources.ts
235 > relativePath(from: URI, to: URI): string | undefined {
236 if (from.scheme !== to.scheme || !isEqualAuthority(from.authority, to.authority)) {
237 return undefined;
257 return paths.posix.relative(fromPath, toPath);
258 }
259 > resources.ts
260 > resolvePath(base: URI, path: string): URI {
261 if (base.scheme === Schemas.file) {
262 const newURI = URI.file(paths.resolve(originalFSPath(base), path));
271 });
272 }
273 > resources.ts
274 > // --- misc
275 >
276 > isAbsolutePath(resource: URI): boolean {
277 return !!resource.path && resource.path[0] === '/';
278 }
279 > resources.ts
280 > isEqualAuthority(a1: string | undefined, a2: string | undefined) {
281 return a1 === a2 || (a1 !== undefined && a2 !== undefined && equalsIgnoreCase(a1, a2));
282 }
283 > resources.ts
284 > hasTrailingPathSeparator(resource: URI, sep: string = paths.sep): boolean {
285 if (resource.scheme === Schemas.file) {
286 const fsp = originalFSPath(resource);
291 }
292 }
293 > resources.ts
294 > removeTrailingPathSeparator(resource: URI, sep: string = paths.sep): URI {
295 // Make sure that the path isn't a drive letter. A trailing separator there is not removable.
296 if (hasTrailingPathSeparator(resource, sep)) {
299 return resource;
300 }
301 > resources.ts
302 > addTrailingPathSeparator(resource: URI, sep: string = paths.sep): URI {
303 let isRootSep: boolean = false;
304 if (resource.scheme === Schemas.file) {
315 return resource;
316 }
317 > } resources.ts
318 >
319 >
320 > /**
321 > * Unbiased utility that takes uris "as they are". This means it can be interchanged with
322 > * uri#toString() usages. The following is true
323 > * ```
324 > * assertEqual(aUri.toString() === bUri.toString(), exturi.isEqual(aUri, bUri))
325 > * ```
326 > */
327 > export const extUri = new ExtUri(() => false);
328 >
329 > /**
330 > * BIASED utility that _mostly_ ignored the case of urs paths. ONLY use this util if you
331 > * understand what you are doing.
332 > *
333 > * This utility is INCOMPATIBLE with `uri.toString()`-usages and both CANNOT be used interchanged.
334 > *
335 > * When dealing with uris from files or documents, `extUri` (the unbiased friend)is sufficient
336 > * because those uris come from a "trustworthy source". When creating unknown uris it's always
337 > * better to use `IUriIdentityService` which exposes an `IExtUri`-instance which knows when path
338 > * casing matters.
339 > */
340 > export const extUriBiasedIgnorePathCase = new ExtUri(uri => {
341 // A file scheme resource is in the same platform as code, so ignore case for non linux platforms
342 // Resource can be from another platform. Lowering the case as an hack. Should come from File system provider
343 return uri.scheme === Schemas.file ? !isLinux : true;
344 });
345 > resources.ts
346 >
347 > /**
348 > * BIASED utility that always ignores the casing of uris paths. ONLY use this util if you
349 > * understand what you are doing.
350 > *
351 > * This utility is INCOMPATIBLE with `uri.toString()`-usages and both CANNOT be used interchanged.
352 > *
353 > * When dealing with uris from files or documents, `extUri` (the unbiased friend)is sufficient
354 > * because those uris come from a "trustworthy source". When creating unknown uris it's always
355 > * better to use `IUriIdentityService` which exposes an `IExtUri`-instance which knows when path
356 > * casing matters.
357 > */
358 > export const extUriIgnorePathCase = new ExtUri(_ => true);
359 >
360 > export const isEqual = extUri.isEqual.bind(extUri);
361 > export const isEqualOrParent = extUri.isEqualOrParent.bind(extUri);
362 > export const getComparisonKey = extUri.getComparisonKey.bind(extUri);
363 > export const basenameOrAuthority = extUri.basenameOrAuthority.bind(extUri);
364 > export const basename = extUri.basename.bind(extUri);
365 > export const extname = extUri.extname.bind(extUri);
366 > export const dirname = extUri.dirname.bind(extUri);
367 > export const joinPath = extUri.joinPath.bind(extUri);
368 > export const normalizePath = extUri.normalizePath.bind(extUri);
369 > export const relativePath = extUri.relativePath.bind(extUri);
370 > export const resolvePath = extUri.resolvePath.bind(extUri);
371 > export const isAbsolutePath = extUri.isAbsolutePath.bind(extUri);
372 > export const isEqualAuthority = extUri.isEqualAuthority.bind(extUri);
373 > export const hasTrailingPathSeparator = extUri.hasTrailingPathSeparator.bind(extUri);
374 > export const removeTrailingPathSeparator = extUri.removeTrailingPathSeparator.bind(extUri);
375 > export const addTrailingPathSeparator = extUri.addTrailingPathSeparator.bind(extUri);
376 >
377 > //#endregion
378 >
379 > export function distinctParents<T>(items: T[], resourceAccessor: (item: T) => URI): T[] {
380 const distinctParents: T[] = [];
381 for (let i = 0; i < items.length; i++) {
396 return distinctParents;
397 }
398 > resources.ts
399 > /**
400 > * Data URI related helpers.
401 > */
402 > export namespace DataUri {
403 >
404 > export const META_DATA_LABEL = 'label';
405 > export const META_DATA_DESCRIPTION = 'description';
406 > export const META_DATA_SIZE = 'size';
407 > export const META_DATA_MIME = 'mime';
408 >
409 > export function parseMetaData(dataUri: URI): Map<string, string> {
410 const metadata = new Map<string, string>();
411
429 return metadata;
430 }
431 > } resources.ts
432 >
433 > export function toLocalResource(resource: URI, authority: string | undefined, localScheme: string): URI {
434 if (authority) {
435 let path = resource.path;
src/vs/base/common/observableInternal/base.ts 206 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- base.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { DisposableStore, onUnexpectedError } from './commonFacade/deps.js';
7 >
8 > /**
9 > * Represents an observable value.
10 > *
11 > * @template T The type of the values the observable can hold.
12 > */
13 > // This interface exists so that, for example for string observables,
14 > // typescript renders the type as `IObservable<string>` instead of `IObservable<string, unknown>`.
15 > export interface IObservable<T> extends IObservableWithChange<T, unknown> { }
16 >
17 > /**
18 > * Represents an observable value.
19 > *
20 > * @template T The type of the values the observable can hold.
21 > * @template TChange The type used to describe value changes
22 > * (usually `void` and only used in advanced scenarios).
23 > * While observers can miss temporary values of an observable,
24 > * they will receive all change values (as long as they are subscribed)!
25 > */
26 > export interface IObservableWithChange<T, TChange = unknown> {
27 > /**
28 > * Returns the current value.
29 > *
30 > * Calls {@link IObserver.handleChange} if the observable notices that the value changed.
31 > * Must not be called from {@link IObserver.handleChange}!
32 > */
33 > get(): T;
34 >
35 > /**
36 > * Forces the observable to check for changes and report them.
37 > *
38 > * Has the same effect as calling {@link IObservable.get}, but does not force the observable
39 > * to actually construct the value, e.g. if change deltas are used.
40 > * Calls {@link IObserver.handleChange} if the observable notices that the value changed.
41 > * Must not be called from {@link IObserver.handleChange}!
42 > */
43 > reportChanges(): void;
44 >
45 > /**
46 > * Adds the observer to the set of subscribed observers.
47 > * This method is idempotent.
48 > */
49 > addObserver(observer: IObserver): void;
50 >
51 > /**
52 > * Removes the observer from the set of subscribed observers.
53 > * This method is idempotent.
54 > */
55 > removeObserver(observer: IObserver): void;
56 >
57 > // #region These members have a standard implementation and are only part of the interface for convenience.
58 >
59 > /**
60 > * Reads the current value and subscribes the reader to this observable.
61 > *
62 > * Calls {@link IReader.readObservable} if a reader is given, otherwise {@link IObservable.get}
63 > * (see {@link ConvenientObservable.read} for the implementation).
64 > */
65 > read(reader: IReader | undefined): T;
66 >
67 > /**
68 > * Makes sure this value is computed eagerly.
69 > */
70 > recomputeInitiallyAndOnChange(store: DisposableStore, handleValue?: (value: T) => void): IObservable<T>;
71 >
72 > /**
73 > * Makes sure this value is cached.
74 > */
75 > keepObserved(store: DisposableStore): IObservable<T>;
76 >
77 > /**
78 > * Creates a derived observable that depends on this observable.
79 > * Use the reader to read other observables
80 > * (see {@link ConvenientObservable.map} for the implementation).
81 > */
82 > map<TNew>(fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
83 > map<TNew>(owner: object, fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
84 >
85 > flatten<TNew>(this: IObservable<IObservable<TNew>>): IObservable<TNew>;
86 >
87 > /**
88 > * ONLY FOR DEBUGGING!
89 > * Logs computations of this derived.
90 > */
91 > log(): IObservableWithChange<T, TChange>;
92 >
93 > /**
94 > * A human-readable name for debugging purposes.
95 > */
96 > readonly debugName: string;
97 >
98 > /**
99 > * This property captures the type of the change object. Do not use it at runtime!
100 > */
101 > readonly TChange: TChange;
102 >
103 > // #endregion
104 > }
105 >
106 > /**
107 > * Represents an observer that can be subscribed to an observable.
108 > *
109 > * If an observer is subscribed to an observable and that observable didn't signal
110 > * a change through one of the observer methods, the observer can assume that the
111 > * observable didn't change.
112 > * If an observable reported a possible change, {@link IObservable.reportChanges} forces
113 > * the observable to report an actual change if there was one.
114 > */
115 > export interface IObserver {
116 > /**
117 > * Signals that the given observable might have changed and a transaction potentially modifying that observable started.
118 > * Before the given observable can call this method again, is must call {@link IObserver.endUpdate}.
119 > *
120 > * Implementations must not get/read the value of other observables, as they might not have received this event yet!
121 > * The method {@link IObservable.reportChanges} can be used to force the observable to report the changes.
122 > */
123 > beginUpdate<T>(observable: IObservable<T>): void;
124 >
125 > /**
126 > * Signals that the transaction that potentially modified the given observable ended.
127 > * This is a good place to react to (potential) changes.
128 > */
129 > endUpdate<T>(observable: IObservable<T>): void;
130 >
131 > /**
132 > * Signals that the given observable might have changed.
133 > * The method {@link IObservable.reportChanges} can be used to force the observable to report the changes.
134 > *
135 > * Implementations must not get/read the value of other observables, as they might not have received this event yet!
136 > * The change should be processed lazily or in {@link IObserver.endUpdate}.
137 > */
138 > handlePossibleChange<T>(observable: IObservable<T>): void;
139 >
140 > /**
141 > * Signals that the given {@link observable} changed.
142 > *
143 > * Implementations must not get/read the value of other observables, as they might not have received this event yet!
144 > * The change should be processed lazily or in {@link IObserver.endUpdate}.
145 > *
146 > * @param change Indicates how or why the value changed.
147 > */
148 > handleChange<T, TChange>(observable: IObservableWithChange<T, TChange>, change: TChange): void;
149 > }
150 >
151 > /**
152 > * A reader allows code to track what it depends on, so the caller knows when the computed value or produced side-effect is no longer valid.
153 > * Use `derived(reader => ...)` to turn code that needs a reader into an observable value.
154 > */
155 > export interface IReader {
156 > /**
157 > * Reads the value of an observable and subscribes to it.
158 > */
159 > readObservable<T>(observable: IObservableWithChange<T, any>): T;
160 > }
161 >
162 > export interface ISettable<T, TChange = void> {
163 > /**
164 > * Sets the value of the observable.
165 > * Use a transaction to batch multiple changes (with a transaction, observers only react at the end of the transaction).
166 > *
167 > * @param transaction When given, value changes are handled on demand or when the transaction ends.
168 > * @param change Describes how or why the value changed.
169 > */
170 > set(value: T, transaction: ITransaction | undefined, change: TChange): void;
171 > }
172 >
173 > export interface ITransaction {
174 > /**
175 > * Calls {@link Observer.beginUpdate} immediately
176 > * and {@link Observer.endUpdate} when the transaction ends.
177 > */
178 > updateObserver(observer: IObserver, observable: IObservableWithChange<any, any>): void;
179 > }
180 >
181 > /**
182 > * This function is used to indicate that the caller recovered from an error that indicates a bug.
183 > */
184 > export function handleBugIndicatingErrorRecovery(message: string) {
185 const err = new Error('BugIndicatingErrorRecovery: ' + message);
186 onUnexpectedError(err);
187 console.error('recovered from an error that indicates a bug', err);
188 }
189 > base.ts
190 > /**
191 > * A settable observable.
192 > */
193 > export interface ISettableObservable<T, TChange = void> extends IObservableWithChange<T, TChange>, ISettable<T, TChange> {
194 > }
195 >
196 > export interface IReaderWithStore extends IReader {
197 > /**
198 > * Items in this store get disposed just before the observable recomputes/reruns or when it becomes unobserved.
199 > */
200 > get store(): DisposableStore;
201 >
202 > /**
203 > * Items in this store get disposed just after the observable recomputes/reruns or when it becomes unobserved.
204 > * This is important if the current run needs the undisposed result from the last run.
205 > *
206 > * Warning: Items in this store might still get disposed before dependents (that read the now disposed value in the past) are recomputed with the new (undisposed) value!
207 > * A clean solution for this is ref counting.
208 > */
209 > get delayedStore(): DisposableStore;
210 > }
src/vs/base/common/observableInternal/logging/debugger/devToolsLogger.ts 204 covered LOC · 24 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- devToolsLogger.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { AutorunObserver, AutorunState } from '../../reactions/autorunImpl.js';
7 > import { TransactionImpl } from '../../transaction.js';
8 > import { IChangeInformation, IObservableLogger } from '../logging.js';
9 > import { formatValue } from '../consoleObservableLogger.js';
10 > import { ObsDebuggerApi, IObsDeclaration, ObsInstanceId, ObsStateUpdate, ITransactionState, ObserverInstanceState } from './debuggerApi.js';
11 > import { registerDebugChannel } from './debuggerRpc.js';
12 > import { deepAssign, deepAssignDeleteNulls, Throttler } from './utils.js';
13 > import { isDefined } from '../../../types.js';
14 > import { FromEventObservable } from '../../observables/observableFromEvent.js';
15 > import { BugIndicatingError, onUnexpectedError } from '../../../errors.js';
16 > import { IObservable, IObserver } from '../../base.js';
17 > import { BaseObservable } from '../../observables/baseObservable.js';
18 > import { Derived, DerivedState } from '../../observables/derivedImpl.js';
19 > import { ObservableValue } from '../../observables/observableValue.js';
20 > import { DebugLocation } from '../../debugLocation.js';
21 >
22 > interface IInstanceInfo {
23 > declarationId: number;
24 > instanceId: number;
25 > }
26 >
27 > interface IObservableInfo extends IInstanceInfo {
28 > listenerCount: number;
29 > lastValue: string | undefined;
30 > updateCount: number;
31 > changedObservables: Set<IObservable<any>>;
32 > }
33 >
34 > interface IAutorunInfo extends IInstanceInfo {
35 > updateCount: number;
36 > changedObservables: Set<IObservable<any>>;
37 > }
38 >
39 > export class DevToolsLogger implements IObservableLogger {
40 > private static _instance: DevToolsLogger | undefined = undefined;
41 > public static getInstance(): DevToolsLogger {
42 if (DevToolsLogger._instance === undefined) {
43 DevToolsLogger._instance = new DevToolsLogger();
45 return DevToolsLogger._instance;
46 }
48 > private _declarationId = 0;
49 > private _instanceId = 0;
50 >
51 > private readonly _declarations = new Map</* declarationId + type */string, IObsDeclaration>();
52 > private readonly _instanceInfos = new WeakMap<object, IObservableInfo | IAutorunInfo>();
53 > private readonly _aliveInstances = new Map<ObsInstanceId, IObservable<any> | AutorunObserver>();
54 > private readonly _activeTransactions = new Set<TransactionImpl>();
55 >
56 > private readonly _channel = registerDebugChannel<ObsDebuggerApi>('observableDevTools', () => {
57 > return {
58 > notifications: {
59 > setDeclarationIdFilter: declarationIds => {
60 >
61 > },
62 > logObservableValue: (observableId) => {
63 > console.log('logObservableValue', observableId);
64 > },
65 > flushUpdates: () => {
66 > this._flushUpdates();
67 > },
68 > resetUpdates: () => {
69 > this._pendingChanges = null;
70 > this._channel.api.notifications.handleChange(this._fullState, true);
71 > },
72 > },
73 > requests: {
74 > getDeclarations: () => {
75 > const result: Record<string, IObsDeclaration> = {};
76 > for (const decl of this._declarations.values()) {
77 > result[decl.id] = decl;
78 > }
79 > return { decls: result };
80 > },
81 > getSummarizedInstances: () => {
82 > return null!;
83 > },
84 > getObservableValueInfo: instanceId => {
85 > const obs = this._aliveInstances.get(instanceId) as BaseObservable<any>;
86 > return {
87 > observers: [...obs.debugGetObservers()].map(d => this._formatObserver(d)).filter(isDefined),
88 > };
89 > },
90 > getDerivedInfo: instanceId => {
91 > const d = this._aliveInstances.get(instanceId) as Derived<any>;
92 > return {
93 > dependencies: [...d.debugGetState().dependencies].map(d => this._formatObservable(d)).filter(isDefined),
94 > observers: [...d.debugGetObservers()].map(d => this._formatObserver(d)).filter(isDefined),
95 > };
96 > },
97 > getAutorunInfo: instanceId => {
98 > const obs = this._aliveInstances.get(instanceId) as AutorunObserver;
99 > return {
100 > dependencies: [...obs.debugGetState().dependencies].map(d => this._formatObservable(d)).filter(isDefined),
101 > };
102 > },
103 > getTransactionState: () => {
104 > return this.getTransactionState();
105 > },
106 > setValue: (instanceId, jsonValue) => {
107 > const obs = this._aliveInstances.get(instanceId) as BaseObservable<any>;
108 >
109 > if (obs instanceof Derived) {
110 > obs.debugSetValue(jsonValue);
111 > } else if (obs instanceof ObservableValue) {
112 > obs.debugSetValue(jsonValue);
113 > } else if (obs instanceof FromEventObservable) {
114 > obs.debugSetValue(jsonValue);
115 > } else {
116 > throw new BugIndicatingError('Observable is not supported');
117 > }
118 >
119 > const observers = [...obs.debugGetObservers()];
120 > for (const d of observers) {
121 > d.beginUpdate(obs);
122 > }
123 > for (const d of observers) {
124 > d.handleChange(obs, undefined);
125 > }
126 > for (const d of observers) {
127 > d.endUpdate(obs);
128 > }
129 > },
130 > getValue: instanceId => {
131 > const obs = this._aliveInstances.get(instanceId) as BaseObservable<any>;
132 > if (obs instanceof Derived) {
133 > return formatValue(obs.debugGetState().value, 200);
134 > } else if (obs instanceof ObservableValue) {
135 > return formatValue(obs.debugGetState().value, 200);
136 > }
137 >
138 > return undefined;
139 > },
140 > logValue: (instanceId) => {
141 > const obs = this._aliveInstances.get(instanceId);
142 > if (obs && 'get' in obs) {
143 > console.log('Logged Value:', obs.get());
144 > } else {
145 > throw new BugIndicatingError('Observable is not supported');
146 > }
147 > },
148 > rerun: (instanceId) => {
149 > const obs = this._aliveInstances.get(instanceId);
150 > if (obs instanceof Derived) {
151 > obs.debugRecompute();
152 > } else if (obs instanceof AutorunObserver) {
153 > obs.debugRerun();
154 > } else {
155 > throw new BugIndicatingError('Observable is not supported');
156 > }
157 > },
158 > }
159 > };
160 > });
161 >
162 > private getTransactionState(): ITransactionState | undefined {
163 const affected: ObserverInstanceState[] = [];
164 const txs = [...this._activeTransactions];
188 return { names: txs.map(t => t.getDebugName() ?? 'tx'), affected };
189 }
191 > private _getObservableInfo(observable: IObservable<any>): IObservableInfo | undefined {
192 const info = this._instanceInfos.get(observable);
193 if (!info) {
197 return info as IObservableInfo;
198 }
200 > private _getAutorunInfo(autorun: AutorunObserver): IAutorunInfo | undefined {
201 const info = this._instanceInfos.get(autorun);
202 if (!info) {
206 return info as IAutorunInfo;
207 }
209 > private _getInfo(observer: IObserver, queue: (observer: IObserver) => void): ObserverInstanceState | undefined {
210 if (observer instanceof Derived) {
211 const observersToUpdate = [...observer.debugGetObservers()];
255 return undefined;
256 }
258 > private _formatObservable(obs: IObservable<any>): { name: string; instanceId: ObsInstanceId } | undefined {
259 const info = this._getObservableInfo(obs);
260 if (!info) { return undefined; }
261 return { name: obs.debugName, instanceId: info.instanceId };
262 }
264 > private _formatObserver(obs: IObserver): { name: string; instanceId: ObsInstanceId } | undefined {
265 if (obs instanceof Derived) {
266 return { name: obs.toString(), instanceId: this._getObservableInfo(obs)?.instanceId! };
273 return undefined;
274 }
276 > private constructor() {
277 DebugLocation.enable();
278 }
280 > private _pendingChanges: ObsStateUpdate | null = null;
281 > private readonly _changeThrottler = new Throttler();
282 >
283 > private readonly _fullState = {};
284 >
285 > private _handleChange(update: ObsStateUpdate): void {
286 deepAssignDeleteNulls(this._fullState, update);
287
294 this._changeThrottler.throttle(this._flushUpdates, 10);
295 }
297 > private readonly _flushUpdates = () => {
298 > if (this._pendingChanges !== null) {
299 > this._channel.api.notifications.handleChange(this._pendingChanges, false);
300 > this._pendingChanges = null;
301 > }
302 > };
303 >
304 > private _getDeclarationId(type: IObsDeclaration['type'], location: DebugLocation): number {
305 if (!location) {
306 return -1;
322 return decInfo.id;
323 }
325 > handleObservableCreated(observable: IObservable<any>, location: DebugLocation): void {
326 const declarationId = this._getDeclarationId('observable/value', location);
327
336 this._instanceInfos.set(observable, info);
337 }
339 > handleOnListenerCountChanged(observable: IObservable<any>, newCount: number): void {
340 const info = this._getObservableInfo(observable);
341 if (!info) { return; }
364 info.listenerCount = newCount;
365 }
367 > handleObservableUpdated(observable: IObservable<any>, changeInfo: IChangeInformation): void {
368 if (observable instanceof Derived) {
369 this._handleDerivedRecomputed(observable, changeInfo);
383 }
384 }
386 > handleAutorunCreated(autorun: AutorunObserver, location: DebugLocation): void {
387 const declarationId = this._getDeclarationId('autorun', location);
388 const info: IAutorunInfo = {
408 }
409 }
410 > handleAutorunDisposed(autorun: AutorunObserver): void { devToolsLogger.ts
411 const info = this._getAutorunInfo(autorun);
412 if (!info) { return; }
418 this._aliveInstances.delete(info.instanceId);
419 }
420 > handleAutorunDependencyChanged(autorun: AutorunObserver, observable: IObservable<any>, change: unknown): void { devToolsLogger.ts
421 const info = this._getAutorunInfo(autorun);
422 if (!info) { return; }
424 info.changedObservables.add(observable);
425 }
426 > handleAutorunStarted(autorun: AutorunObserver): void { devToolsLogger.ts
427
428 }
429 > handleAutorunFinished(autorun: AutorunObserver): void { devToolsLogger.ts
430 const info = this._getAutorunInfo(autorun);
431 if (!info) { return; }
437 });
438 }
440 > handleDerivedDependencyChanged(derived: Derived<any>, observable: IObservable<any>, change: unknown): void {
441 const info = this._getObservableInfo(derived);
442 if (info) {
444 }
445 }
446 > _handleDerivedRecomputed(observable: Derived<any>, changeInfo: IChangeInformation): void { devToolsLogger.ts
447 const info = this._getObservableInfo(observable);
448 if (!info) { return; }
459 }
460 }
461 > handleDerivedCleared(observable: Derived<any>): void { devToolsLogger.ts
462 const info = this._getObservableInfo(observable);
463 if (!info) { return; }
475 }
476 }
477 > handleBeginTransaction(transaction: TransactionImpl): void { devToolsLogger.ts
478 this._activeTransactions.add(transaction);
479 }
480 > handleEndTransaction(transaction: TransactionImpl): void { devToolsLogger.ts
481 this._activeTransactions.delete(transaction);
482 }
src/vs/nls.ts 201 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- nls.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export function getNLSMessages(): string[] {
7 return globalThis._VSCODE_NLS_MESSAGES;
8 }
9 > nls.ts
10 > export function getNLSLanguage(): string | undefined {
11 > return globalThis._VSCODE_NLS_LANGUAGE;
12 > }
13 >
14 > declare const document: { location?: { hash?: string } } | undefined;
15 > const isPseudo = getNLSLanguage() === 'pseudo' || (typeof document !== 'undefined' && document.location && typeof document.location.hash === 'string' && document.location.hash.indexOf('pseudo=true') >= 0);
16 >
17 > export interface ILocalizeInfo {
18 > key: string;
19 > comment: string[];
20 > }
21 >
22 > export interface ILocalizedString {
23 > original: string;
24 > value: string;
25 > }
26 >
27 > function _format(message: string, args: (string | number | boolean | undefined | null)[]): string { nls.ts
28 > let result: string;
29 >
30 > if (args.length === 0) {
31 > result = message; nls.ts
32 > } else { nls.ts
33 result = message.replace(/\{(\d+)\}/g, (match, rest) => {
34 const index = rest[0];
43 });
44 }
45 > nls.ts
46 > if (isPseudo) {
47 // FF3B and FF3D is the Unicode zenkaku representation for [ and ]
48 result = '\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\uFF3D';
49 }
50 > nls.ts
51 > return result;
52 > }
53 > nls.ts
54 > /**
55 > * Marks a string to be localized. Returns the localized string.
56 > *
57 > * @param info The {@linkcode ILocalizeInfo} which describes the id and comments associated with the localized string.
58 > * @param message The string to localize
59 > * @param args The arguments to the string
60 > *
61 > * @note `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
62 > * @example `localize({ key: 'sayHello', comment: ['Welcomes user'] }, 'hello {0}', name)`
63 > *
64 > * @returns string The localized string.
65 > */
66 > export function localize(info: ILocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): string;
67 >
68 > /**
69 > * Marks a string to be localized. Returns the localized string.
70 > *
71 > * @param key The key to use for localizing the string
72 > * @param message The string to localize
73 > * @param args The arguments to the string
74 > *
75 > * @note `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
76 > * @example For example, `localize('sayHello', 'hello {0}', name)`
77 > *
78 > * @returns string The localized string.
79 > */
80 > export function localize(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): string;
81 >
82 > /**
83 > * @skipMangle
84 > */
85 > export function localize(data: ILocalizeInfo | string /* | number when built */, message: string /* | null when built */, ...args: (string | number | boolean | undefined | null)[]): string {
86 > if (typeof data === 'number') { nls.ts
87 return _format(lookupMessage(data, message), args);
88 }
89 > return _format(message, args); nls.ts
90 > }
91 > nls.ts
92 > /**
93 > * Only used when built: Looks up the message in the global NLS table.
94 > * This table is being made available as a global through bootstrapping
95 > * depending on the target context.
96 > */
97 function lookupMessage(index: number, fallback: string | null): string {
98 const message = getNLSMessages()?.[index];
105 return message;
106 }
107 > nls.ts
108 > /**
109 > * Marks a string to be localized. Returns an {@linkcode ILocalizedString}
110 > * which contains the localized string and the original string.
111 > *
112 > * @param info The {@linkcode ILocalizeInfo} which describes the id and comments associated with the localized string.
113 > * @param message The string to localize
114 > * @param args The arguments to the string
115 > *
116 > * @note `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
117 > * @example `localize2({ key: 'sayHello', comment: ['Welcomes user'] }, 'hello {0}', name)`
118 > *
119 > * @returns ILocalizedString which contains the localized string and the original string.
120 > */
121 > export function localize2(info: ILocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): ILocalizedString;
122 >
123 > /**
124 > * Marks a string to be localized. Returns an {@linkcode ILocalizedString}
125 > * which contains the localized string and the original string.
126 > *
127 > * @param key The key to use for localizing the string
128 > * @param message The string to localize
129 > * @param args The arguments to the string
130 > *
131 > * @note `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
132 > * @example `localize('sayHello', 'hello {0}', name)`
133 > *
134 > * @returns ILocalizedString which contains the localized string and the original string.
135 > */
136 > export function localize2(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): ILocalizedString;
137 >
138 > /**
139 > * @skipMangle
140 > */
141 > export function localize2(data: ILocalizeInfo | string /* | number when built */, originalMessage: string, ...args: (string | number | boolean | undefined | null)[]): ILocalizedString {
142 let message: string;
143 if (typeof data === 'number') {
154 };
155 }
156 > nls.ts
157 > export interface INLSLanguagePackConfiguration {
158 >
159 > /**
160 > * The path to the translations config file that contains pointers to
161 > * all message bundles for `main` and extensions.
162 > */
163 > readonly translationsConfigFile: string;
164 >
165 > /**
166 > * The path to the file containing the translations for this language
167 > * pack as flat string array.
168 > */
169 > readonly messagesFile: string;
170 >
171 > /**
172 > * The path to the file that can be used to signal a corrupt language
173 > * pack, for example when reading the `messagesFile` fails. This will
174 > * instruct the application to re-create the cache on next startup.
175 > */
176 > readonly corruptMarkerFile: string;
177 > }
178 >
179 > export interface INLSConfiguration {
180 >
181 > /**
182 > * Locale as defined in `argv.json` or `app.getLocale()`.
183 > */
184 > readonly userLocale: string;
185 >
186 > /**
187 > * Locale as defined by the OS (e.g. `app.getPreferredSystemLanguages()`).
188 > */
189 > readonly osLocale: string;
190 >
191 > /**
192 > * The actual language of the UI that ends up being used considering `userLocale`
193 > * and `osLocale`.
194 > */
195 > readonly resolvedLanguage: string;
196 >
197 > /**
198 > * Defined if a language pack is used that is not the
199 > * default english language pack. This requires a language
200 > * pack to be installed as extension.
201 > */
202 > readonly languagePack?: INLSLanguagePackConfiguration;
203 >
204 > /**
205 > * The path to the file containing the default english messages
206 > * as flat string array. The file is only present in built
207 > * versions of the application.
208 > */
209 > readonly defaultMessagesFile: string;
210 >
211 > /**
212 > * Below properties are deprecated and only there to continue support
213 > * for `vscode-nls` module that depends on them.
214 > * Refs https://github.com/microsoft/vscode-nls/blob/main/src/node/main.ts#L36-L46
215 > */
216 > /** @deprecated */
217 > readonly locale: string;
218 > /** @deprecated */
219 > readonly availableLanguages: Record<string, string>;
220 > /** @deprecated */
221 > readonly _languagePackSupport?: boolean;
222 > /** @deprecated */
223 > readonly _languagePackId?: string;
224 > /** @deprecated */
225 > readonly _translationsConfigFile?: string;
226 > /** @deprecated */
227 > readonly _cacheRoot?: string;
228 > /** @deprecated */
229 > readonly _resolvedLanguagePackCoreLocation?: string;
230 > /** @deprecated */
231 > readonly _corruptedFile?: string;
232 > }
233 >
234 > export interface ILanguagePack {
235 > readonly hash: string;
236 > readonly label: string | undefined;
237 > readonly extensions: {
238 > readonly extensionIdentifier: { readonly id: string; readonly uuid?: string };
239 > readonly version: string;
240 > }[];
241 > readonly translations: Record<string, string | undefined>;
242 > }
243 >
244 > export type ILanguagePacks = Record<string, ILanguagePack | undefined>;
src/vs/base/common/platform.ts 189 covered LOC · 12 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- platform.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as nls from '../../nls.js';
7 >
8 > export const LANGUAGE_DEFAULT = 'en';
9 >
10 > let _isWindows = false;
11 > let _isMacintosh = false;
12 > let _isLinux = false;
13 > let _isLinuxSnap = false;
14 > let _isNative = false;
15 > let _isWeb = false;
16 > let _isElectron = false;
17 > let _isIOS = false;
18 > let _isCI = false;
19 > let _isMobile = false;
20 > let _locale: string | undefined = undefined;
21 > let _language: string = LANGUAGE_DEFAULT;
22 > let _platformLocale: string = LANGUAGE_DEFAULT;
23 > let _translationsConfigFile: string | undefined = undefined;
24 > let _userAgent: string | undefined = undefined;
25 >
26 > export interface IProcessEnvironment {
27 > [key: string]: string | undefined;
28 > }
29 >
30 > /**
31 > * This interface is intentionally not identical to node.js
32 > * process because it also works in sandboxed environments
33 > * where the process object is implemented differently. We
34 > * define the properties here that we need for `platform`
35 > * to work and nothing else.
36 > */
37 > export interface INodeProcess {
38 > platform: string;
39 > arch: string;
40 > env: IProcessEnvironment;
41 > versions?: {
42 > node?: string;
43 > electron?: string;
44 > chrome?: string;
45 > };
46 > type?: string;
47 > cwd: () => string;
48 > }
49 >
50 > declare const process: INodeProcess;
51 >
52 > const $globalThis: any = globalThis;
53 >
54 > let nodeProcess: INodeProcess | undefined = undefined;
55 > if (typeof $globalThis.vscode !== 'undefined' && typeof $globalThis.vscode.process !== 'undefined') {
56 // Native environment (sandboxed)
57 nodeProcess = $globalThis.vscode.process;
58 > } else if (typeof process !== 'undefined' && typeof process?.versions?.node === 'string') { platform.ts
59 > // Native environment (non-sandboxed)
60 > nodeProcess = process;
61 > }
62 >
63 > const isElectronProcess = typeof nodeProcess?.versions?.electron === 'string';
64 > const isElectronRenderer = isElectronProcess && nodeProcess?.type === 'renderer';
65 >
66 > interface INavigator {
67 > userAgent: string;
68 > maxTouchPoints?: number;
69 > language: string;
70 > }
71 > declare const navigator: INavigator;
72 >
73 > // Native environment
74 > if (typeof nodeProcess === 'object') {
75 > _isWindows = (nodeProcess.platform === 'win32');
76 > _isMacintosh = (nodeProcess.platform === 'darwin');
77 > _isLinux = (nodeProcess.platform === 'linux');
78 > _isLinuxSnap = _isLinux && !!nodeProcess.env['SNAP'] && !!nodeProcess.env['SNAP_REVISION'];
79 > _isElectron = isElectronProcess;
80 > _isCI = !!nodeProcess.env['CI'] || !!nodeProcess.env['BUILD_ARTIFACTSTAGINGDIRECTORY'] || !!nodeProcess.env['GITHUB_WORKSPACE'];
81 > _locale = LANGUAGE_DEFAULT;
82 > _language = LANGUAGE_DEFAULT;
83 > const rawNlsConfig = nodeProcess.env['VSCODE_NLS_CONFIG'];
84 > if (rawNlsConfig) {
85 try {
86 const nlsConfig: nls.INLSConfiguration = JSON.parse(rawNlsConfig);
113 console.error('Unable to resolve platform.');
114 }
115 > platform.ts
116 > export const enum Platform {
117 > Web,
118 > Mac,
119 > Linux,
120 > Windows
121 > }
122 > export type PlatformName = 'Web' | 'Windows' | 'Mac' | 'Linux';
123 >
124 > export function PlatformToString(platform: Platform): PlatformName {
125 switch (platform) {
126 case Platform.Web: return 'Web';
130 }
131 }
132 > platform.ts
133 > let _platform: Platform = Platform.Web;
134 > if (_isMacintosh) {
135 _platform = Platform.Mac;
136 > } else if (_isWindows) { platform.ts
137 _platform = Platform.Windows;
138 > } else if (_isLinux) { platform.ts
139 > _platform = Platform.Linux;
140 > }
141 >
142 > export const isWindows = _isWindows;
143 > export const isMacintosh = _isMacintosh;
144 > export const isLinux = _isLinux;
145 > export const isLinuxSnap = _isLinuxSnap;
146 > export const isNative = _isNative;
147 > export const isElectron = _isElectron;
148 > export const isWeb = _isWeb;
149 > export const isWebWorker = (_isWeb && typeof $globalThis.importScripts === 'function');
150 > export const webWorkerOrigin = isWebWorker ? $globalThis.origin : undefined;
151 > export const isIOS = _isIOS;
152 > export const isMobile = _isMobile;
153 > /**
154 > * Whether we run inside a CI environment, such as
155 > * GH actions or Azure Pipelines.
156 > */
157 > export const isCI = _isCI;
158 > export const platform = _platform;
159 > export const userAgent = _userAgent;
160 >
161 > /**
162 > * The language used for the user interface. The format of
163 > * the string is all lower case (e.g. zh-tw for Traditional
164 > * Chinese or de for German)
165 > */
166 > export const language = _language;
167 >
168 > export namespace Language {
169 >
170 > export function value(): string {
171 return language;
172 }
173 > platform.ts
174 > export function isDefaultVariant(): boolean {
175 if (language.length === 2) {
176 return language === 'en';
181 }
182 }
183 > platform.ts
184 > export function isDefault(): boolean {
185 return language === 'en';
186 }
187 > } platform.ts
188 >
189 > /**
190 > * Desktop: The OS locale or the locale specified by --locale or `argv.json`.
191 > * Web: matches `platformLocale`.
192 > *
193 > * The UI is not necessarily shown in the provided locale.
194 > */
195 > export const locale = _locale;
196 >
197 > /**
198 > * This will always be set to the OS/browser's locale regardless of
199 > * what was specified otherwise. The format of the string is all
200 > * lower case (e.g. zh-tw for Traditional Chinese). The UI is not
201 > * necessarily shown in the provided locale.
202 > */
203 > export const platformLocale = _platformLocale;
204 >
205 > /**
206 > * The translations that are available through language packs.
207 > */
208 > export const translationsConfigFile = _translationsConfigFile;
209 >
210 > export const setTimeout0IsFaster = (typeof $globalThis.postMessage === 'function' && !$globalThis.importScripts);
211 >
212 > /**
213 > * See https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#:~:text=than%204%2C%20then-,set%20timeout%20to%204,-.
214 > *
215 > * Works similarly to `setTimeout(0)` but doesn't suffer from the 4ms artificial delay
216 > * that browsers set when the nesting level is > 5.
217 > */
218 > export const setTimeout0 = (() => {
219 > if (setTimeout0IsFaster) {
220 interface IQueueElement {
221 id: number;
246 };
247 }
248 > return (callback: () => void) => setTimeout(callback); platform.ts
249 > })();
250 >
251 > export const enum OperatingSystem {
252 > Windows = 1,
253 > Macintosh = 2,
254 > Linux = 3
255 > }
256 > export const OS = (_isMacintosh || _isIOS ? OperatingSystem.Macintosh : (_isWindows ? OperatingSystem.Windows : OperatingSystem.Linux));
257 >
258 > let _isLittleEndian = true;
259 > let _isLittleEndianComputed = false;
260 > export function isLittleEndian(): boolean {
261 if (!_isLittleEndianComputed) {
262 _isLittleEndianComputed = true;
269 return _isLittleEndian;
270 }
271 > platform.ts
272 > export const isChrome = !!(userAgent && userAgent.indexOf('Chrome') >= 0);
273 > export const isFirefox = !!(userAgent && userAgent.indexOf('Firefox') >= 0);
274 > export const isSafari = !!(!isChrome && (userAgent && userAgent.indexOf('Safari') >= 0));
275 > export const isEdge = !!(userAgent && userAgent.indexOf('Edg/') >= 0);
276 > export const isAndroid = !!(userAgent && userAgent.indexOf('Android') >= 0);
277 > export const hasElectronUserAgent = !!(userAgent && userAgent.indexOf('Electron') >= 0);
278 >
279 > export function isTahoeOrNewer(osVersion: string): boolean {
280 return parseFloat(osVersion) >= 25;
281 }
src/vs/base/common/errors.ts 183 covered LOC · 32 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- errors.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export interface ErrorListenerCallback {
7 > (error: any): void;
8 > }
9 >
10 > export interface ErrorListenerUnbind {
11 > (): void;
12 > }
13 >
14 > // Avoid circular dependency on EventEmitter by implementing a subset of the interface.
15 > export class ErrorHandler {
16 > private unexpectedErrorHandler: (e: any) => void;
17 > private listeners: ErrorListenerCallback[];
18 >
19 > constructor() {
20 >
21 > this.listeners = [];
22 >
23 > this.unexpectedErrorHandler = function (e: any) {
24 setTimeout(() => {
25 if (e.stack) {
34 }, 0);
35 };
36 > } errors.ts
37 >
38 > addListener(listener: ErrorListenerCallback): ErrorListenerUnbind {
39 this.listeners.push(listener);
40
43 };
44 }
45 > errors.ts
46 > private emit(e: any): void {
47 this.listeners.forEach((listener) => {
48 listener(e);
49 });
50 }
51 > errors.ts
52 > private _removeListener(listener: ErrorListenerCallback): void {
53 this.listeners.splice(this.listeners.indexOf(listener), 1);
54 }
55 > errors.ts
56 > setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {
57 > this.unexpectedErrorHandler = newUnexpectedErrorHandler;
58 > }
59 >
60 > getUnexpectedErrorHandler(): (e: any) => void {
61 return this.unexpectedErrorHandler;
62 }
63 > errors.ts
64 > onUnexpectedError(e: any): void {
65 this.unexpectedErrorHandler(e);
66 this.emit(e);
67 }
68 > errors.ts
69 > // For external errors, we don't want the listeners to be called
70 > onUnexpectedExternalError(e: any): void {
71 this.unexpectedErrorHandler(e);
72 }
73 > } errors.ts
74 >
75 > export const errorHandler = new ErrorHandler();
76 >
77 > /** @skipMangle */
78 > export function setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {
79 > errorHandler.setUnexpectedErrorHandler(newUnexpectedErrorHandler);
80 > }
81 >
82 > /**
83 > * Returns if the error is a SIGPIPE error. SIGPIPE errors should generally be
84 > * logged at most once, to avoid a loop.
85 > *
86 > * @see https://github.com/microsoft/vscode-remote-release/issues/6481
87 > */
88 > export function isSigPipeError(e: unknown): e is Error {
89 if (!e || typeof e !== 'object') {
90 return false;
94 return cast.code === 'EPIPE' && cast.syscall?.toUpperCase() === 'WRITE';
95 }
96 > errors.ts
97 > /**
98 > * This function should only be called with errors that indicate a bug in the product.
99 > * E.g. buggy extensions/invalid user-input/network issues should not be able to trigger this code path.
100 > * If they are, this indicates there is also a bug in the product.
101 > */
102 > export function onBugIndicatingError(e: any): undefined {
103 errorHandler.onUnexpectedError(e);
104 return undefined;
105 }
106 > errors.ts
107 > export function onUnexpectedError(e: any): undefined {
108 // ignore errors from cancelled promises
109 if (!isCancellationError(e)) {
112 return undefined;
113 }
114 > errors.ts
115 > export function onUnexpectedExternalError(e: any): undefined {
116 // ignore errors from cancelled promises
117 if (!isCancellationError(e)) {
120 return undefined;
121 }
122 > errors.ts
123 > type ObjectWithCode = {
124 > readonly code: unknown;
125 > };
126 >
127 function hasErrorCode(error: object): error is ObjectWithCode {
128 return Object.hasOwn(error, 'code');
129 }
130 > errors.ts
131 > export function getErrorCode(error: unknown): string | undefined {
132 if (!error || typeof error !== 'object' || !hasErrorCode(error)) {
133 return undefined;
136 return typeof code === 'string' || typeof code === 'number' ? String(code) : undefined;
137 }
138 > errors.ts
139 > export interface SerializedError {
140 > readonly $isError: true;
141 > readonly name: string;
142 > readonly message: string;
143 > readonly stack: string;
144 > readonly noTelemetry: boolean;
145 > readonly code?: string;
146 > readonly cause?: SerializedError;
147 > }
148 >
149 > type ErrorWithCode = Error & {
150 > code: string | undefined;
151 > };
152 >
153 > export function transformErrorForSerialization(error: Error): SerializedError;
154 > export function transformErrorForSerialization(error: any): any;
155 > export function transformErrorForSerialization(error: any): any {
156 if (error instanceof Error) {
157 const { name, message, cause } = error;
172 return error;
173 }
174 > errors.ts
175 > export function transformErrorFromSerialization(data: SerializedError): Error {
176 let error: Error;
177 if (data.noTelemetry) {
191 return error;
192 }
193 > errors.ts
194 > // see https://github.com/v8/v8/wiki/Stack%20Trace%20API#basic-stack-traces
195 > export interface V8CallSite {
196 > getThis(): unknown;
197 > getTypeName(): string | null;
198 > getFunction(): Function | undefined;
199 > getFunctionName(): string | null;
200 > getMethodName(): string | null;
201 > getFileName(): string | null;
202 > getLineNumber(): number | null;
203 > getColumnNumber(): number | null;
204 > getEvalOrigin(): string | undefined;
205 > isToplevel(): boolean;
206 > isEval(): boolean;
207 > isNative(): boolean;
208 > isConstructor(): boolean;
209 > toString(): string;
210 > }
211 >
212 > export const canceledName = 'Canceled';
213 >
214 > /**
215 > * Checks if the given error is a promise in canceled state
216 > */
217 > export function isCancellationError(error: any): boolean {
218 if (error instanceof CancellationError) {
219 return true;
221 return error instanceof Error && error.name === canceledName && error.message === canceledName;
222 }
223 > errors.ts
224 > // !!!IMPORTANT!!!
225 > // Do NOT change this class because it is also used as an API-type.
226 > export class CancellationError extends Error {
227 > constructor() {
228 super(canceledName);
229 this.name = this.message;
230 }
231 > } errors.ts
232 >
233 > export class PendingMigrationError extends Error {
234 >
235 > private static readonly _name = 'PendingMigrationError';
236 >
237 > static is(error: unknown): error is PendingMigrationError {
238 return error instanceof PendingMigrationError || (error instanceof Error && error.name === PendingMigrationError._name);
239 }
240 > errors.ts
241 > constructor(message: string) {
242 super(message);
243 this.name = PendingMigrationError._name;
244 }
245 > } errors.ts
246 >
247 > /**
248 > * @deprecated use {@link CancellationError `new CancellationError()`} instead
249 > */
250 > export function canceled(): Error {
251 const error = new Error(canceledName);
252 error.name = error.message;
253 return error;
254 }
255 > errors.ts
256 > export function illegalArgument(name?: string): Error {
257 if (name) {
258 return new Error(`Illegal argument: ${name}`);
261 }
262 }
263 > errors.ts
264 > export function illegalState(name?: string): Error {
265 if (name) {
266 return new Error(`Illegal state: ${name}`);
269 }
270 }
271 > errors.ts
272 > export class ReadonlyError extends TypeError {
273 > constructor(name?: string) {
274 super(name ? `${name} is read-only and cannot be changed` : 'Cannot change read-only property');
275 }
276 > } errors.ts
277 >
278 > export function getErrorMessage(err: any): string {
279 if (!err) {
280 return 'Error';
291 return String(err);
292 }
293 > errors.ts
294 > export class NotImplementedError extends Error {
295 > constructor(message?: string) {
296 super('NotImplemented');
297 if (message) {
299 }
300 }
301 > } errors.ts
302 >
303 > export class NotSupportedError extends Error {
304 > constructor(message?: string) {
305 super('NotSupported');
306 if (message) {
308 }
309 }
310 > } errors.ts
311 >
312 > export class ExpectedError extends Error {
313 readonly isExpected = true;
314 > } errors.ts
315 >
316 > /**
317 > * Error that when thrown won't be logged in telemetry as an unhandled error.
318 > */
319 > export class ErrorNoTelemetry extends Error {
320 > override readonly name: string;
321 >
322 > constructor(msg?: string) {
323 super(msg);
324 this.name = 'CodeExpectedError';
325 }
326 > errors.ts
327 > public static fromError(err: Error): ErrorNoTelemetry {
328 if (err instanceof ErrorNoTelemetry) {
329 return err;
335 return result;
336 }
337 > errors.ts
338 > public static isErrorNoTelemetry(err: Error): err is ErrorNoTelemetry {
339 return err.name === 'CodeExpectedError';
340 }
341 > } errors.ts
342 >
343 > /**
344 > * This error indicates a bug.
345 > * Do not throw this for invalid user input.
346 > * Only catch this error to recover gracefully from bugs.
347 > */
348 > export class BugIndicatingError extends Error {
349 > constructor(message?: string) {
350 super(message || 'An unexpected bug occurred.');
351 Object.setPrototypeOf(this, BugIndicatingError.prototype);
src/vs/base/common/path.ts 177 covered LOC · 31 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- path.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // NOTE: VSCode's copy of nodejs path library to be usable in common (non-node) namespace
7 > // Copied from: https://github.com/nodejs/node/commits/v22.15.0/lib/path.js
8 > // Excluding: the change that adds primordials
9 > // (https://github.com/nodejs/node/commit/187a862d221dec42fa9a5c4214e7034d9092792f and others)
10 > // Excluding: the change that adds glob matching
11 > // (https://github.com/nodejs/node/commit/57b8b8e18e5e2007114c63b71bf0baedc01936a6)
12 >
13 > /**
14 > * Copyright Joyent, Inc. and other Node contributors.
15 > *
16 > * Permission is hereby granted, free of charge, to any person obtaining a
17 > * copy of this software and associated documentation files (the
18 > * "Software"), to deal in the Software without restriction, including
19 > * without limitation the rights to use, copy, modify, merge, publish,
20 > * distribute, sublicense, and/or sell copies of the Software, and to permit
21 > * persons to whom the Software is furnished to do so, subject to the
22 > * following conditions:
23 > *
24 > * The above copyright notice and this permission notice shall be included
25 > * in all copies or substantial portions of the Software.
26 > *
27 > * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28 > * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 > * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
30 > * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
31 > * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
32 > * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
33 > * USE OR OTHER DEALINGS IN THE SOFTWARE.
34 > */
35 >
36 > import * as process from './process.js';
37 >
38 > const CHAR_UPPERCASE_A = 65;/* A */
39 > const CHAR_LOWERCASE_A = 97; /* a */
40 > const CHAR_UPPERCASE_Z = 90; /* Z */
41 > const CHAR_LOWERCASE_Z = 122; /* z */
42 > const CHAR_DOT = 46; /* . */
43 > const CHAR_FORWARD_SLASH = 47; /* / */
44 > const CHAR_BACKWARD_SLASH = 92; /* \ */
45 > const CHAR_COLON = 58; /* : */
46 > const CHAR_QUESTION_MARK = 63; /* ? */
47 >
48 > class ErrorInvalidArgType extends Error {
49 > code: 'ERR_INVALID_ARG_TYPE';
50 > constructor(name: string, expected: string, actual: unknown) {
51 // determiner: 'must be' or 'must not be'
52 let determiner;
66 this.code = 'ERR_INVALID_ARG_TYPE';
67 }
68 > } path.ts
69 >
70 function validateObject(pathObject: object, name: string) {
71 if (pathObject === null || typeof pathObject !== 'object') {
73 }
74 }
75 > path.ts
76 function validateString(value: string, name: string) {
77 if (typeof value !== 'string') {
79 }
80 }
81 > path.ts
82 > const platformIsWin32 = (process.platform === 'win32');
83 >
84 function isPathSeparator(code: number | undefined) {
85 return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
86 }
87 > path.ts
88 function isPosixPathSeparator(code: number | undefined) {
89 return code === CHAR_FORWARD_SLASH;
90 }
91 > path.ts
92 function isWindowsDeviceRoot(code: number) {
93 return (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||
94 (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z);
95 }
96 > path.ts
97 > // Resolves . and .. elements in a path with directory names
98 function normalizeString(path: string, allowAboveRoot: boolean, separator: string, isPathSeparator: (code?: number) => boolean) {
99 let res = '';
163 return res;
164 }
165 > path.ts
166 function formatExt(ext: string): string {
167 return ext ? `${ext[0] === '.' ? '' : '.'}${ext}` : '';
168 }
169 > path.ts
170 function _format(sep: string, pathObject: ParsedPath) {
171 validateObject(pathObject, 'pathObject');
178 return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`;
179 }
180 > path.ts
181 > export interface ParsedPath {
182 > root: string;
183 > dir: string;
184 > base: string;
185 > ext: string;
186 > name: string;
187 > }
188 >
189 > export interface IPath {
190 > normalize(path: string): string;
191 > isAbsolute(path: string): boolean;
192 > join(...paths: string[]): string;
193 > resolve(...pathSegments: string[]): string;
194 > relative(from: string, to: string): string;
195 > dirname(path: string): string;
196 > basename(path: string, suffix?: string): string;
197 > extname(path: string): string;
198 > format(pathObject: ParsedPath): string;
199 > parse(path: string): ParsedPath;
200 > toNamespacedPath(path: string): string;
201 > sep: '\\' | '/';
202 > delimiter: string;
203 > win32: IPath | null;
204 > posix: IPath | null;
205 > }
206 >
207 > export const win32: IPath = {
208 > // path.resolve([from ...], to)
209 > resolve(...pathSegments: string[]): string {
210 let resolvedDevice = '';
211 let resolvedTail = '';
343 `${resolvedDevice}${resolvedTail}` || '.';
344 },
345 > path.ts
346 > normalize(path: string): string {
347 validateString(path, 'path');
348 const len = path.length;
450 return isAbsolute ? `${device}\\${tail}` : `${device}${tail}`;
451 },
452 > path.ts
453 > isAbsolute(path: string): boolean {
454 validateString(path, 'path');
455 const len = path.length;
466 isPathSeparator(path.charCodeAt(2)));
467 },
468 > path.ts
469 > join(...paths: string[]): string {
470 if (paths.length === 0) {
471 return '.';
536 return win32.normalize(joined);
537 },
538 > path.ts
539 >
540 > // It will solve the relative path from `from` to `to`, for instance:
541 > // from = 'C:\\orandea\\test\\aaa'
542 > // to = 'C:\\orandea\\impl\\bbb'
543 > // The output of the function should be: '..\\..\\impl\\bbb'
544 > relative(from: string, to: string): string {
545 validateString(from, 'from');
546 validateString(to, 'to');
699 return toOrig.slice(toStart, toEnd);
700 },
701 > path.ts
702 > toNamespacedPath(path: string): string {
703 // Note: this will *probably* throw somewhere.
704 if (typeof path !== 'string' || path.length === 0) {
730 return resolvedPath;
731 },
732 > path.ts
733 > dirname(path: string): string {
734 validateString(path, 'path');
735 const len = path.length;
818 return path.slice(0, end);
819 },
820 > path.ts
821 > basename(path: string, suffix?: string): string {
822 if (suffix !== undefined) {
823 validateString(suffix, 'suffix');
906 return path.slice(start, end);
907 },
908 > path.ts
909 > extname(path: string): string {
910 validateString(path, 'path');
911 let start = 0;
972 return path.slice(startDot, end);
973 },
974 > path.ts
975 > format: _format.bind(null, '\\'),
976 >
977 > parse(path) {
978 validateString(path, 'path');
979
1126 return ret;
1127 },
1128 > path.ts
1129 > sep: '\\',
1130 > delimiter: ';',
1131 > win32: null,
1132 > posix: null
1133 > };
1134 >
1135 > const posixCwd = (() => {
1136 > if (platformIsWin32) {
1137 // Converts Windows' backslash path separators to POSIX forward slashes
1138 // and truncates any drive indicator
1143 };
1144 }
1145 > path.ts
1146 > // We're already on POSIX, no need for any transformations
1147 > return () => process.cwd();
1148 > })();
1149 >
1150 > export const posix: IPath = {
1151 > // path.resolve([from ...], to)
1152 > resolve(...pathSegments: string[]): string {
1153 let resolvedPath = '';
1154 let resolvedAbsolute = false;
1186 return resolvedPath.length > 0 ? resolvedPath : '.';
1187 },
1188 > path.ts
1189 > normalize(path: string): string {
1190 validateString(path, 'path');
1191
1213 return isAbsolute ? `/${path}` : path;
1214 },
1215 > path.ts
1216 > isAbsolute(path: string): boolean {
1217 validateString(path, 'path');
1218 return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH;
1219 },
1220 > path.ts
1221 > join(...paths: string[]): string {
1222 if (paths.length === 0) {
1223 return '.';
1239 return posix.normalize(path.join('/'));
1240 },
1241 > path.ts
1242 > relative(from: string, to: string): string {
1243 validateString(from, 'from');
1244 validateString(to, 'to');
1312 return `${out}${to.slice(toStart + lastCommonSep)}`;
1313 },
1314 > path.ts
1315 > toNamespacedPath(path: string): string {
1316 // Non-op on posix systems
1317 return path;
1318 },
1319 > path.ts
1320 > dirname(path: string): string {
1321 validateString(path, 'path');
1322 if (path.length === 0) {
1346 return path.slice(0, end);
1347 },
1348 > path.ts
1349 > basename(path: string, suffix?: string): string {
1350 if (suffix !== undefined) {
1351 validateString(suffix, 'suffix');
1426 return path.slice(start, end);
1427 },
1428 > path.ts
1429 > extname(path: string): string {
1430 validateString(path, 'path');
1431 let startDot = -1;
1480 return path.slice(startDot, end);
1481 },
1482 > path.ts
1483 > format: _format.bind(null, '/'),
1484 >
1485 > parse(path: string): ParsedPath {
1486 validateString(path, 'path');
1487
1565 return ret;
1566 },
1567 > path.ts
1568 > sep: '/',
1569 > delimiter: ':',
1570 > win32: null,
1571 > posix: null
1572 > };
1573 >
1574 > posix.win32 = win32.win32 = win32;
1575 > posix.posix = win32.posix = posix;
1576 >
1577 > export const normalize = (platformIsWin32 ? win32.normalize : posix.normalize);
1578 > export const isAbsolute = (platformIsWin32 ? win32.isAbsolute : posix.isAbsolute);
1579 > export const join = (platformIsWin32 ? win32.join : posix.join);
1580 > export const resolve = (platformIsWin32 ? win32.resolve : posix.resolve);
1581 > export const relative = (platformIsWin32 ? win32.relative : posix.relative);
1582 > export const dirname = (platformIsWin32 ? win32.dirname : posix.dirname);
1583 > export const basename = (platformIsWin32 ? win32.basename : posix.basename);
1584 > export const extname = (platformIsWin32 ? win32.extname : posix.extname);
1585 > export const format = (platformIsWin32 ? win32.format : posix.format);
1586 > export const parse = (platformIsWin32 ? win32.parse : posix.parse);
1587 > export const toNamespacedPath = (platformIsWin32 ? win32.toNamespacedPath : posix.toNamespacedPath);
1588 > export const sep = (platformIsWin32 ? win32.sep : posix.sep);
1589 > export const delimiter = (platformIsWin32 ? win32.delimiter : posix.delimiter);
src/vs/platform/agentHost/common/agentHostConnectionsService.ts 126 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- agentHostConnectionsService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Event } from '../../../base/common/event.js';
7 > import type { URI } from '../../../base/common/uri.js';
8 > import { createDecorator } from '../../instantiation/common/instantiation.js';
9 > import type { IAgentConnection } from './agentService.js';
10 >
11 > /**
12 > * Chat-session resource scheme prefix for the window's ambient/local agent
13 > * host: `agent-host-<provider>`.
14 > *
15 > * Remote agent host session schemes (`remote-<authority>-<provider>`) are
16 > * handled by `agentHostSessionType.ts` (`isRemoteAgentHostSessionType` and
17 > * friends), which also owns the authority disambiguation.
18 > */
19 > export const LOCAL_AGENT_HOST_SCHEME_PREFIX = 'agent-host-';
20 >
21 > /**
22 > * Reserved connection authority for the window's ambient/primary agent host.
23 > *
24 > * NOTE: "ambient" is not the same as "local". In a local window the ambient
25 > * host is the in-process utility agent host; in a window attached to a remote
26 > * authority the ambient host is itself remote (the `EditorRemoteAgentHostServiceClient`).
27 > * The `'local'` string is reserved/canonical for this ambient connection — it
28 > * is already used as the agent-host URI authority for in-window resources
29 > * (see `toAgentHostUri` in `agentHostUri.ts`).
30 > */
31 > export const AMBIENT_AGENT_HOST_AUTHORITY = 'local';
32 >
33 > /**
34 > * A descriptor for a single agent-host connection exposed by
35 > * {@link IAgentHostConnectionsService}. Covers both the window's ambient host
36 > * and every connected remote host with one uniform shape.
37 > */
38 > export interface IAgentHostConnectionInfo {
39 > /**
40 > * Sanitized connection authority. The ambient host uses
41 > * {@link AMBIENT_AGENT_HOST_AUTHORITY}; remotes use the authority derived
42 > * from their address via `agentHostAuthority`.
43 > */
44 > readonly authority: string;
45 > /** Raw remote address. `undefined` for the ambient host. */
46 > readonly address: string | undefined;
47 > /** Human-readable label for the connection. */
48 > readonly name: string;
49 > /**
50 > * `true` for the window's ambient/primary host. Remember this host may
51 > * itself be remote in a remote window — see {@link AMBIENT_AGENT_HOST_AUTHORITY}.
52 > */
53 > readonly isAmbient: boolean;
54 > /** The live connection, or `undefined` when not currently connected. */
55 > readonly connection: IAgentConnection | undefined;
56 > }
57 >
58 > /**
59 > * The result of resolving a chat-session resource to its backing agent host:
60 > * the owning {@link IAgentConnection} and the canonical backend agent-session
61 > * URI (`<provider>:/<rawId>`) used for protocol operations on that connection.
62 > */
63 > export interface IAgentHostSessionResolution {
64 > readonly connection: IAgentConnection;
65 > readonly backendSession: URI;
66 > }
67 >
68 > export const IAgentHostConnectionsService = createDecorator<IAgentHostConnectionsService>('agentHostConnectionsService');
69 >
70 > /**
71 > * A thin, read-only facade over the window's ambient agent host
72 > * (`IAgentHostService`) and the registry of remote agent hosts
73 > * (`IRemoteAgentHostService`), so consumers can enumerate and resolve
74 > * {@link IAgentConnection}s without branching on local-vs-remote or
75 > * fanning out over "1 ambient + N remote" themselves.
76 > *
77 > * This service deliberately does NOT expose lifecycle/management operations:
78 > * ambient-process concerns (restart, inspect, auth-pending) stay on
79 > * `IAgentHostService`, and remote-registry mutations (add/remove/reconnect/
80 > * upgrade) stay on `IRemoteAgentHostService`. This facade only answers
81 > * "which connections exist?" and "give me the connection for X".
82 > */
83 > export interface IAgentHostConnectionsService {
84 > readonly _serviceBrand: undefined;
85 >
86 > /** Fires when the set of connections changes (ambient lifecycle or remotes added/removed). */
87 > readonly onDidChangeConnections: Event<void>;
88 >
89 > /**
90 > * All known connections as `[ambient, ...remotes]`. The ambient entry is
91 > * always present with a live `connection`; only remote entries may have
92 > * `connection: undefined` (e.g. while connecting/disconnected). Remote
93 > * entries reflect the current `IRemoteAgentHostService` registry.
94 > */
95 > readonly connections: readonly IAgentHostConnectionInfo[];
96 >
97 > /** The window's ambient/primary connection (local, or the window-remote bridge). */
98 > readonly ambientConnection: IAgentConnection;
99 >
100 > /**
101 > * Resolves a live connection by sanitized authority, including
102 > * {@link AMBIENT_AGENT_HOST_AUTHORITY} for the ambient host. Returns
103 > * `undefined` when no connected host matches.
104 > */
105 > getConnectionByAuthority(authority: string): IAgentConnection | undefined;
106 >
107 > /**
108 > * Resolves a live remote connection by raw address. The ambient host has no
109 > * address and is never returned here — use {@link ambientConnection} or
110 > * {@link getConnectionByAuthority} with {@link AMBIENT_AGENT_HOST_AUTHORITY}.
111 > */
112 > getConnectionByAddress(address: string): IAgentConnection | undefined;
113 >
114 > /**
115 > * Resolves an agent-host chat-session resource to its owning connection and
116 > * backend session URI. Handles both local schemes
117 > * (`agent-host-<provider>`) — backed by the ambient connection — and remote
118 > * schemes (`remote-<authority>-<provider>`) — resolved against the live
119 > * remote registry. Returns `undefined` when the resource is not an
120 > * agent-host session, or when the matching remote host is not connected.
121 > *
122 > * NOTE: provisional/untitled sessions are a workbench concern and are NOT
123 > * handled here — callers that support them should resolve those first.
124 > */
125 > resolveSessionResource(sessionResource: URI): IAgentHostSessionResolution | undefined;
126 > }
src/vs/base/common/observableInternal/observables/derivedImpl.ts 112 covered LOC · 23 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- derivedImpl.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable, IObservableWithChange, IObserver, IReaderWithStore, ISettableObservable, ITransaction, } from '../base.js';
7 > import { BaseObservable } from './baseObservable.js';
8 > import { DebugNameData } from '../debugName.js';
9 > import { BugIndicatingError, DisposableStore, EqualityComparer, assertFn, onBugIndicatingError } from '../commonFacade/deps.js';
10 > import { getLogger } from '../logging/logging.js';
11 > import { IChangeTracker } from '../changeTracker.js';
12 > import { DebugLocation } from '../debugLocation.js';
13 >
14 > export interface IDerivedReader<TChange = void> extends IReaderWithStore {
15 > /**
16 > * Call this to report a change delta or to force report a change, even if the new value is the same as the old value.
17 > */
18 > reportChange(change: TChange): void;
19 > }
20 >
21 > export const enum DerivedState {
22 > /** Initial state, no previous value, recomputation needed */
23 > initial = 0,
24 >
25 > /**
26 > * A dependency could have changed.
27 > * We need to explicitly ask them if at least one dependency changed.
28 > */
29 > dependenciesMightHaveChanged = 1,
30 >
31 > /**
32 > * A dependency changed and we need to recompute.
33 > * After recomputation, we need to check the previous value to see if we changed as well.
34 > */
35 > stale = 2,
36 >
37 > /**
38 > * No change reported, our cached value is up to date.
39 > */
40 > upToDate = 3,
41 > }
42 >
43 function derivedStateToString(state: DerivedState): string {
44 switch (state) {
50 }
51 }
53 > export class Derived<T, TChangeSummary = any, TChange = void> extends BaseObservable<T, TChange> implements IDerivedReader<TChange>, IObserver {
54 > private _state = DerivedState.initial;
55 > private _value: T | undefined = undefined;
56 > private _updateCount = 0;
57 > private _dependencies = new Set<IObservable<any>>();
58 > private _dependenciesToBeRemoved = new Set<IObservable<any>>();
59 > private _changeSummary: TChangeSummary | undefined = undefined;
60 > private _isUpdating = false;
61 > private _isComputing = false;
62 > private _didReportChange = false;
63 > private _isInBeforeUpdate = false;
64 > private _isReaderValid = false;
65 > private _store: DisposableStore | undefined = undefined;
66 > private _delayedStore: DisposableStore | undefined = undefined;
67 > private _removedObserverToCallEndUpdateOn: Set<IObserver> | null = null;
68 >
69 > public override get debugName(): string {
70 > return this._debugNameData.getDebugName(this) ?? '(anonymous)';
71 > }
72 >
73 > constructor(
74 public readonly _debugNameData: DebugNameData,
75 public readonly _computeFn: (reader: IDerivedReader<TChange>, changeSummary: TChangeSummary) => T,
82 this._changeSummary = this._changeTracker?.createChangeSummary(undefined);
83 }
85 > protected override onLastObserverRemoved(): void {
86 /**
87 * We are not tracking changes anymore, thus we have to assume
107 this._handleLastObserverRemoved?.();
108 }
110 > public override get(): T {
111 const checkEnabled = false; // TODO set to true
112 if (this._isComputing && checkEnabled) {
164 }
165 }
167 > private _recompute() {
168 let didChange = false;
169 this._isComputing = true;
238 }
239 }
241 > public override toString(): string {
242 return `LazyDerived<${this.debugName}>`;
243 }
245 > // IObserver Implementation
246 >
247 > public beginUpdate<T>(_observable: IObservable<T>): void {
248 if (this._isUpdating) {
249 throw new BugIndicatingError('Cyclic deriveds are not supported yet!');
272 }
273 }
275 > public endUpdate<T>(_observable: IObservable<T>): void {
276 this._updateCount--;
277 if (this._updateCount === 0) {
291 assertFn(() => this._updateCount >= 0);
292 }
294 > public handlePossibleChange<T>(observable: IObservable<T>): void {
295 // In all other states, observers already know that we might have changed.
296 if (this._state === DerivedState.upToDate && this._dependencies.has(observable) && !this._dependenciesToBeRemoved.has(observable)) {
301 }
302 }
304 > public handleChange<T, TChange>(observable: IObservableWithChange<T, TChange>, change: TChange): void {
305 if (this._dependencies.has(observable) && !this._dependenciesToBeRemoved.has(observable) || this._isInBeforeUpdate) {
306 getLogger()?.handleDerivedDependencyChanged(this, observable, change);
329 }
330 }
332 > // IReader Implementation
333 >
334 > private _ensureReaderValid(): void {
335 if (!this._isReaderValid) { throw new BugIndicatingError('The reader object cannot be used outside its compute function!'); }
336 }
338 > public readObservable<T>(observable: IObservable<T>): T {
339 this._ensureReaderValid();
340
348 return value;
349 }
351 > public reportChange(change: TChange): void {
352 this._ensureReaderValid();
353
358 }
359 }
361 > get store(): DisposableStore {
362 this._ensureReaderValid();
363
367 return this._store;
368 }
370 > get delayedStore(): DisposableStore {
371 this._ensureReaderValid();
372
376 return this._delayedStore;
377 }
379 > public override addObserver(observer: IObserver): void {
380 const shouldCallBeginUpdate = !this._observers.has(observer) && this._updateCount > 0;
381 super.addObserver(observer);
387 }
388 }
390 > public override removeObserver(observer: IObserver): void {
391 if (this._observers.has(observer) && this._updateCount > 0) {
392 if (!this._removedObserverToCallEndUpdateOn) {
397 super.removeObserver(observer);
398 }
400 > public debugGetState() {
401 return {
402 state: this._state,
408 };
409 }
411 > public debugSetValue(newValue: unknown) {
412 // eslint-disable-next-line local/code-no-any-casts
413 this._value = newValue as any;
414 }
416 > public debugRecompute(): void {
417 this.beginUpdate(this);
418 try {
426 }
427 }
429 > public setValue(newValue: T, tx: ITransaction, change: TChange): void {
430 this._value = newValue;
431 const observers = this._observers;
435 }
436 }
437 > } derivedImpl.ts
438 >
439 >
440 > export class DerivedWithSetter<T, TChangeSummary = any, TOutChanges = any> extends Derived<T, TChangeSummary, TOutChanges> implements ISettableObservable<T, TOutChanges> {
441 > constructor(
442 debugNameData: DebugNameData,
443 computeFn: (reader: IDerivedReader<TOutChanges>, changeSummary: TChangeSummary) => T,
src/vs/platform/instantiation/common/instantiation.ts 111 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- instantiation.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { DisposableStore } from '../../../base/common/lifecycle.js';
7 > import * as descriptors from './descriptors.js';
8 > import { ServiceCollection } from './serviceCollection.js';
9 >
10 > // ------ internal util
11 >
12 > export namespace _util {
13 >
14 > export const serviceIds = new Map<string, ServiceIdentifier<any>>();
15 >
16 > export const DI_TARGET = '$di$target';
17 > export const DI_DEPENDENCIES = '$di$dependencies';
18 >
19 > export function getServiceDependencies(ctor: DI_TARGET_OBJ): { id: ServiceIdentifier<any>; index: number }[] {
20 return ctor[DI_DEPENDENCIES] || [];
21 }
23 > export interface DI_TARGET_OBJ extends Function {
24 > [DI_TARGET]: Function;
25 > [DI_DEPENDENCIES]: { id: ServiceIdentifier<any>; index: number }[];
26 > }
27 > }
28 >
29 > // --- interfaces ------
30 >
31 > export type BrandedService = { _serviceBrand: undefined };
32 >
33 > export interface IConstructorSignature<T, Args extends any[] = []> {
34 > new <Services extends BrandedService[]>(...args: [...Args, ...Services]): T;
35 > }
36 >
37 > export interface ServicesAccessor {
38 > get<T>(id: ServiceIdentifier<T>): T;
39 > }
40 >
41 > export const IInstantiationService = createDecorator<IInstantiationService>('instantiationService');
42 >
43 > /**
44 > * Given a list of arguments as a tuple, attempt to extract the leading, non-service arguments
45 > * to their own tuple.
46 > */
47 > export type GetLeadingNonServiceArgs<TArgs extends any[]> =
48 > TArgs extends [] ? []
49 > : TArgs extends [...infer TFirst, BrandedService] ? GetLeadingNonServiceArgs<TFirst>
50 > : TArgs;
51 >
52 > export interface IInstantiationService {
53 >
54 > readonly _serviceBrand: undefined;
55 >
56 > /**
57 > * Synchronously creates an instance that is denoted by the descriptor
58 > */
59 > createInstance<T>(descriptor: descriptors.SyncDescriptor0<T>): T;
60 > createInstance<Ctor extends new (...args: any[]) => unknown, R extends InstanceType<Ctor>>(ctor: Ctor, ...args: GetLeadingNonServiceArgs<ConstructorParameters<Ctor>>): R;
61 >
62 > /**
63 > * Calls a function with a service accessor.
64 > */
65 > invokeFunction<R, TS extends any[] = []>(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R;
66 >
67 > /**
68 > * Creates a child of this service which inherits all current services
69 > * and adds/overwrites the given services.
70 > *
71 > * NOTE that the returned child is `disposable` and should be disposed when not used
72 > * anymore. This will also dispose all the services that this service has created.
73 > */
74 > createChild(services: ServiceCollection, store?: DisposableStore): IInstantiationService;
75 >
76 > /**
77 > * Disposes this instantiation service.
78 > *
79 > * - Will dispose all services that this instantiation service has created.
80 > * - Will dispose all its children but not its parent.
81 > * - Will NOT dispose services-instances that this service has been created with
82 > * - Will NOT dispose consumer-instances this service has created
83 > */
84 > dispose(): void;
85 > }
86 >
87 >
88 > /**
89 > * Identifies a service of type `T`.
90 > */
91 > export interface ServiceIdentifier<T> {
92 > (...args: any[]): void;
93 > type: T;
94 > }
95 >
96 >
97 function storeServiceDependency(id: ServiceIdentifier<unknown>, target: Function, index: number): void {
98 if ((target as _util.DI_TARGET_OBJ)[_util.DI_TARGET] === target) {
103 }
104 }
106 > /**
107 > * The *only* valid way to create a {{ServiceIdentifier}}.
108 > */
109 > export function createDecorator<T>(serviceId: string): ServiceIdentifier<T> {
110 >
111 > if (_util.serviceIds.has(serviceId)) {
112 return _util.serviceIds.get(serviceId)!;
113 }
115 > const id = function (target: Function, key: string, index: number) {
116 if (arguments.length !== 3) {
117 throw new Error('@IServiceName-decorator can only be used to decorate a parameter');
119 storeServiceDependency(id, target, index);
120 } as ServiceIdentifier<T>;
122 > id.toString = () => serviceId;
123 >
124 > _util.serviceIds.set(serviceId, id);
125 > return id;
126 > }
127 >
128 > export function refineServiceDecorator<T1, T extends T1>(serviceIdentifier: ServiceIdentifier<T1>): ServiceIdentifier<T> {
129 return <ServiceIdentifier<T>>serviceIdentifier;
130 }
src/vs/base/common/equals.ts 108 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- equals.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as arrays from './arrays.js';
7 >
8 > /*
9 > * Each function in this file which offers an equality comparison, has an accompanying
10 > * `*C` variant which returns an EqualityComparer function.
11 > *
12 > * The `*C` variant allows for easier composition of equality comparers and improved type-inference.
13 > */
14 >
15 >
16 > /** Represents a function that decides if two values are equal. */
17 > export type EqualityComparer<T> = (a: T, b: T) => boolean;
18 >
19 > export interface IEquatable<T> {
20 > equals(other: T): boolean;
21 > }
22 >
23 > /**
24 > * Compares two items for equality using strict equality.
25 > */
26 > export function strictEquals<T>(a: T, b: T): boolean {
27 return a === b;
28 }
29 > equals.ts
30 > export function strictEqualsC<T>(): EqualityComparer<T> {
31 return (a, b) => a === b;
32 }
33 > equals.ts
34 > /**
35 > * Checks if the items of two arrays are equal.
36 > * By default, strict equality is used to compare elements, but a custom equality comparer can be provided.
37 > */
38 > export function arrayEquals<T>(a: readonly T[], b: readonly T[], itemEquals?: EqualityComparer<T>): boolean {
39 return arrays.equals(a, b, itemEquals ?? strictEquals);
40 }
41 > equals.ts
42 > /**
43 > * Checks if the items of two arrays are equal.
44 > * By default, strict equality is used to compare elements, but a custom equality comparer can be provided.
45 > */
46 > export function arrayEqualsC<T>(itemEquals?: EqualityComparer<T>): EqualityComparer<readonly T[]> {
47 return (a, b) => arrays.equals(a, b, itemEquals ?? strictEquals);
48 }
49 > equals.ts
50 > /**
51 > * Drills into arrays (items ordered) and objects (keys unordered) and uses strict equality on everything else.
52 > */
53 > export function structuralEquals<T>(a: T, b: T): boolean {
54 if (a === b) {
55 return true;
95 return false;
96 }
97 > equals.ts
98 > export function structuralEqualsC<T>(): EqualityComparer<T> {
99 return (a, b) => structuralEquals(a, b);
100 }
101 > equals.ts
102 > /**
103 > * `getStructuralKey(a) === getStructuralKey(b) <=> structuralEquals(a, b)`
104 > * (assuming that a and b are not cyclic structures and nothing extends globalThis Array).
105 > */
106 > export function getStructuralKey(t: unknown): string {
107 return JSON.stringify(toNormalizedJsonStructure(t));
108 }
109 > equals.ts
110 > let objectId = 0;
111 > const objIds = new WeakMap<object, number>();
112 >
113 function toNormalizedJsonStructure(t: unknown): unknown {
114 if (Array.isArray(t)) {
136 return t;
137 }
138 > equals.ts
139 >
140 > /**
141 > * Two items are considered equal, if their stringified representations are equal.
142 > */
143 > export function jsonStringifyEquals<T>(a: T, b: T): boolean {
144 return JSON.stringify(a) === JSON.stringify(b);
145 }
146 > equals.ts
147 > /**
148 > * Two items are considered equal, if their stringified representations are equal.
149 > */
150 > export function jsonStringifyEqualsC<T>(): EqualityComparer<T> {
151 return (a, b) => JSON.stringify(a) === JSON.stringify(b);
152 }
153 > equals.ts
154 > /**
155 > * Uses `item.equals(other)` to determine equality.
156 > */
157 > export function thisEqualsC<T extends IEquatable<T>>(): EqualityComparer<T> {
158 return (a, b) => a.equals(b);
159 }
160 > equals.ts
161 > /**
162 > * Checks if two items are both null or undefined, or are equal according to the provided equality comparer.
163 > */
164 > export function equalsIfDefined<T>(v1: T | undefined | null, v2: T | undefined | null, equals: EqualityComparer<T>): boolean {
165 if (v1 === undefined || v1 === null || v2 === undefined || v2 === null) {
166 return v2 === v1;
168 return equals(v1, v2);
169 }
170 > equals.ts
171 > /**
172 > * Returns an equality comparer that checks if two items are both null or undefined, or are equal according to the provided equality comparer.
173 > */
174 > export function equalsIfDefinedC<T>(equals: EqualityComparer<T>): EqualityComparer<T | undefined | null> {
175 return (v1, v2) => {
176 if (v1 === undefined || v1 === null || v2 === undefined || v2 === null) {
180 };
181 }
182 > equals.ts
183 > /**
184 > * Each function in this file which offers an equality comparison, has an accompanying
185 > * `*C` variant which returns an EqualityComparer function.
186 > *
187 > * The `*C` variant allows for easier composition of equality comparers and improved type-inference.
188 > */
189 > export namespace equals {
190 > export const strict = strictEquals;
191 > export const strictC = strictEqualsC;
192 >
193 > export const array = arrayEquals;
194 > export const arrayC = arrayEqualsC;
195 >
196 > export const structural = structuralEquals;
197 > export const structuralC = structuralEqualsC;
198 >
199 > export const jsonStringify = jsonStringifyEquals;
200 > export const jsonStringifyC = jsonStringifyEqualsC;
201 >
202 > export const thisC = thisEqualsC;
203 >
204 > export const ifDefined = equalsIfDefined;
205 > export const ifDefinedC = equalsIfDefinedC;
206 > }
src/vs/base/common/observableInternal/observables/baseObservable.ts 104 covered LOC · 17 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- baseObservable.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservableWithChange, IObserver, IReader, IObservable } from '../base.js';
7 > import { DisposableStore } from '../commonFacade/deps.js';
8 > import { DebugLocation } from '../debugLocation.js';
9 > import { DebugOwner, getFunctionName } from '../debugName.js';
10 > import { debugGetObservableGraph } from '../logging/debugGetDependencyGraph.js';
11 > import { getLogger, logObservable } from '../logging/logging.js';
12 > import type { keepObserved, recomputeInitiallyAndOnChange } from '../utils/utils.js';
13 > import { derivedOpts } from './derived.js';
14 >
15 > let _derived: typeof derivedOpts;
16 > /**
17 > * @internal
18 > * This is to allow splitting files.
19 > */
20 > export function _setDerivedOpts(derived: typeof _derived) {
21 > _derived = derived;
22 > }
23 >
24 > let _recomputeInitiallyAndOnChange: typeof recomputeInitiallyAndOnChange;
25 > export function _setRecomputeInitiallyAndOnChange(recomputeInitiallyAndOnChange: typeof _recomputeInitiallyAndOnChange) {
26 > _recomputeInitiallyAndOnChange = recomputeInitiallyAndOnChange;
27 > }
28 >
29 > let _keepObserved: typeof keepObserved;
30 > export function _setKeepObserved(keepObserved: typeof _keepObserved) {
31 > _keepObserved = keepObserved;
32 > }
33 >
34 > let _debugGetObservableGraph: typeof debugGetObservableGraph;
35 > export function _setDebugGetObservableGraph(debugGetObservableGraph: typeof _debugGetObservableGraph) {
36 > _debugGetObservableGraph = debugGetObservableGraph;
37 > }
38 >
39 > export abstract class ConvenientObservable<T, TChange> implements IObservableWithChange<T, TChange> {
40 > get TChange(): TChange { return null!; }
41 >
42 > public abstract get(): T;
43 >
44 > public reportChanges(): void {
45 this.get();
46 }
48 > public abstract addObserver(observer: IObserver): void;
49 > public abstract removeObserver(observer: IObserver): void;
50 >
51 > /** @sealed */
52 > public read(reader: IReader | undefined): T {
53 if (reader) {
54 return reader.readObservable(this);
57 }
58 }
60 > /** @sealed */
61 > public map<TNew>(fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
62 > public map<TNew>(owner: DebugOwner, fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
63 > public map<TNew>(fnOrOwner: DebugOwner | ((value: T, reader: IReader) => TNew), fnOrUndefined?: (value: T, reader: IReader) => TNew, debugLocation: DebugLocation = DebugLocation.ofCaller()): IObservable<TNew> {
64 const owner = fnOrUndefined === undefined ? undefined : fnOrOwner as DebugOwner;
65 const fn = fnOrUndefined === undefined ? fnOrOwner as (value: T, reader: IReader) => TNew : fnOrUndefined;
91 );
92 }
94 > public abstract log(): IObservableWithChange<T, TChange>;
95 >
96 > /**
97 > * @sealed
98 > * Converts an observable of an observable value into a direct observable of the value.
99 > */
100 > public flatten<TNew>(this: IObservable<IObservableWithChange<TNew, any>>): IObservable<TNew> {
101 return _derived(
102 {
107 );
108 }
110 > public recomputeInitiallyAndOnChange(store: DisposableStore, handleValue?: (value: T) => void): IObservable<T> {
111 store.add(_recomputeInitiallyAndOnChange!(this, handleValue));
112 return this;
113 }
115 > /**
116 > * Ensures that this observable is observed. This keeps the cache alive.
117 > * However, in case of deriveds, it does not force eager evaluation (only when the value is read/get).
118 > * Use `recomputeInitiallyAndOnChange` for eager evaluation.
119 > */
120 > public keepObserved(store: DisposableStore): IObservable<T> {
121 store.add(_keepObserved!(this));
122 return this;
123 }
125 > public abstract get debugName(): string;
126 >
127 > protected get debugValue() {
128 return this.get();
129 }
131 > get debug(): DebugHelper {
132 return new DebugHelper(this);
133 }
135 >
136 > class DebugHelper {
137 > constructor(public readonly observable: IObservableWithChange<any, any>) {
138 }
140 > getDependencyGraph(): string {
141 return _debugGetObservableGraph(this.observable, { type: 'dependencies' });
142 }
144 > getObserverGraph(): string {
145 return _debugGetObservableGraph(this.observable, { type: 'observers' });
146 }
148 >
149 > export abstract class BaseObservable<T, TChange = void> extends ConvenientObservable<T, TChange> {
150 > protected readonly _observers = new Set<IObserver>();
151 >
152 > constructor(debugLocation: DebugLocation) {
153 super();
154 getLogger()?.handleObservableCreated(this, debugLocation);
155 }
157 > public addObserver(observer: IObserver): void {
158 const len = this._observers.size;
159 this._observers.add(observer);
165 }
166 }
168 > public removeObserver(observer: IObserver): void {
169 const deleted = this._observers.delete(observer);
170 if (deleted && this._observers.size === 0) {
175 }
176 }
178 > protected onFirstObserverAdded(): void { }
179 > protected onLastObserverRemoved(): void { }
180 >
181 > public override log(): IObservableWithChange<T, TChange> {
182 const hadLogger = !!getLogger();
183 logObservable(this);
src/vs/base/common/observableInternal/utils/promise.ts 104 covered LOC · 12 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- promise.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 > import { DisposableStore } from '../../lifecycle.js';
6 > import { IObservable, ISettableObservable } from '../base.js';
7 > import { autorun } from '../reactions/autorun.js';
8 > import { transaction } from '../transaction.js';
9 > import { derived } from '../observables/derived.js';
10 > import { observableValue } from '../observables/observableValue.js';
11 >
12 > export class ObservableLazy<T> {
13 > private readonly _value = observableValue<T | undefined>(this, undefined);
14 >
15 > /**
16 > * The cached value.
17 > * Does not force a computation of the value.
18 > */
19 > public get cachedValue(): IObservable<T | undefined> { return this._value; }
20 >
21 > constructor(private readonly _computeValue: () => T) {
22 }
23 > promise.ts
24 > /**
25 > * Returns the cached value.
26 > * Computes the value if the value has not been cached yet.
27 > */
28 > public getValue(): T {
29 let v = this._value.get();
30 if (!v) {
34 return v;
35 }
36 > } promise.ts
37 >
38 > /**
39 > * A promise whose state is observable.
40 > */
41 > export class ObservablePromise<T> {
42 > public static fromFn<T>(fn: () => Promise<T>): ObservablePromise<T> {
43 > return new ObservablePromise(fn());
44 > }
45 >
46 > public static resolved<T>(value: T): ObservablePromise<T> {
47 return new ObservablePromise(Promise.resolve(value));
48 }
49 > promise.ts
50 > private readonly _value = observableValue<PromiseResult<T> | undefined>(this, undefined);
51 >
52 > /**
53 > * The promise that this object wraps.
54 > */
55 > public readonly promise: Promise<T>;
56 >
57 > /**
58 > * The current state of the promise.
59 > * Is `undefined` if the promise didn't resolve yet.
60 > */
61 > public readonly promiseResult: IObservable<PromiseResult<T> | undefined> = this._value;
62 >
63 > constructor(promise: Promise<T>) {
64 this.promise = promise.then(value => {
65 transaction(tx => {
76 });
77 }
78 > promise.ts
79 > public readonly resolvedValue = derived(this, reader => {
80 > const result = this.promiseResult.read(reader); promise.ts
81 > if (!result) {
82 > return undefined;
83 > }
84 > return result.getDataOrThrow();
85 > }); promise.ts
86 > }
87 >
88 > export class PromiseResult<T> {
89 > constructor(
90 /**
91 * The value of the resolved promise.
101 ) {
102 }
103 > promise.ts
104 > /**
105 > * Returns the value if the promise resolved, otherwise throws the error.
106 > */
107 > public getDataOrThrow(): T {
108 if (this.error) {
109 throw this.error;
111 return this.data!;
112 }
113 > } promise.ts
114 >
115 > /**
116 > * Tracks a changing {@link ObservablePromise}, exposing the last resolved value
117 > * and whether a newer promise is still pending.
118 > */
119 > export class ObservableResolvedPromise<T> {
120 > private readonly _lastResolved: ISettableObservable<T>;
121 > public readonly lastResolved: IObservable<T>;
122 >
123 > private readonly _isResolving = observableValue<boolean>(this, false);
124 > public readonly isResolving: IObservable<boolean> = this._isResolving;
125 >
126 > private _runningPromise: ObservablePromise<T> | undefined;
127 >
128 > constructor(
129 source: IObservable<ObservablePromise<T>>,
130 initialValue: T,
149 }));
150 }
151 > } promise.ts
152 >
153 > /**
154 > * A lazy promise whose state is observable.
155 > */
156 > export class ObservableLazyPromise<T> {
157 > private readonly _lazyValue = new ObservableLazy(() => new ObservablePromise(this._computePromise()));
158 >
159 > /**
160 > * Does not enforce evaluation of the promise compute function.
161 > * Is undefined if the promise has not been computed yet.
162 > */
163 > public readonly cachedPromiseResult = derived(this, reader => this._lazyValue.cachedValue.read(reader)?.promiseResult.read(reader));
164 >
165 > constructor(private readonly _computePromise: () => Promise<T>) {
166 }
167 > promise.ts
168 > public getPromise(): Promise<T> {
169 return this._lazyValue.getValue().promise;
170 }
171 > } promise.ts
src/vs/base/common/arraysFind.ts 95 covered LOC · 16 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- arraysFind.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Comparator } from './arrays.js';
7 >
8 > export function findLast<T, R extends T>(array: readonly T[], predicate: (item: T, index: number) => item is R, fromIndex?: number): R | undefined;
9 > export function findLast<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex?: number): T | undefined;
10 > export function findLast<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex = array.length - 1): T | undefined {
11 const idx = findLastIdx(array, predicate, fromIndex);
12 if (idx === -1) {
15 return array[idx];
16 }
18 > export function findLastIdx<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex = array.length - 1): number {
19 for (let i = fromIndex; i >= 0; i--) {
20 const element = array[i];
27 return -1;
28 }
30 > export function findFirst<T, R extends T>(array: readonly T[], predicate: (item: T, index: number) => item is R, fromIndex?: number): R | undefined;
31 > export function findFirst<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex?: number): T | undefined;
32 > export function findFirst<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex = 0): T | undefined {
33 const idx = findFirstIdx(array, predicate, fromIndex);
34 if (idx === -1) {
37 return array[idx];
38 }
40 > export function findFirstIdx<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex = 0): number {
41 for (let i = fromIndex; i < array.length; i++) {
42 const element = array[i];
49 return -1;
50 }
52 > /**
53 > * Finds the last item where predicate is true using binary search.
54 > * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!
55 > *
56 > * @returns `undefined` if no item matches, otherwise the last item that matches the predicate.
57 > */
58 > export function findLastMonotonous<T>(array: readonly T[], predicate: (item: T) => boolean): T | undefined {
59 const idx = findLastIdxMonotonous(array, predicate);
60 return idx === -1 ? undefined : array[idx];
61 }
63 > /**
64 > * Finds the last item where predicate is true using binary search.
65 > * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!
66 > *
67 > * @returns `startIdx - 1` if predicate is false for all items, otherwise the index of the last item that matches the predicate.
68 > */
69 > export function findLastIdxMonotonous<T>(array: readonly T[], predicate: (item: T) => boolean, startIdx = 0, endIdxEx = array.length): number {
70 let i = startIdx;
71 let j = endIdxEx;
80 return i - 1;
81 }
83 > /**
84 > * Finds the first item where predicate is true using binary search.
85 > * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`!
86 > *
87 > * @returns `undefined` if no item matches, otherwise the first item that matches the predicate.
88 > */
89 > export function findFirstMonotonous<T>(array: readonly T[], predicate: (item: T) => boolean): T | undefined {
90 const idx = findFirstIdxMonotonousOrArrLen(array, predicate);
91 return idx === array.length ? undefined : array[idx];
92 }
94 > /**
95 > * Finds the first item where predicate is true using binary search.
96 > * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`!
97 > *
98 > * @returns `endIdxEx` if predicate is false for all items, otherwise the index of the first item that matches the predicate.
99 > */
100 > export function findFirstIdxMonotonousOrArrLen<T>(array: readonly T[], predicate: (item: T) => boolean, startIdx = 0, endIdxEx = array.length): number {
101 let i = startIdx;
102 let j = endIdxEx;
111 return i;
112 }
114 > export function findFirstIdxMonotonous<T>(array: readonly T[], predicate: (item: T) => boolean, startIdx = 0, endIdxEx = array.length): number {
115 const idx = findFirstIdxMonotonousOrArrLen(array, predicate, startIdx, endIdxEx);
116 return idx === array.length ? -1 : idx;
117 }
119 > /**
120 > * Use this when
121 > * * You have a sorted array
122 > * * You query this array with a monotonous predicate to find the last item that has a certain property.
123 > * * You query this array multiple times with monotonous predicates that get weaker and weaker.
124 > */
125 > export class MonotonousArray<T> {
126 > public static assertInvariants = false;
127 >
128 > private _findLastMonotonousLastIdx = 0;
129 > private _prevFindLastPredicate: ((item: T) => boolean) | undefined;
130 >
131 > constructor(private readonly _array: readonly T[]) {
132 }
134 > /**
135 > * The predicate must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!
136 > * For subsequent calls, current predicate must be weaker than (or equal to) the previous predicate, i.e. more entries must be `true`.
137 > */
138 > findLastMonotonous(predicate: (item: T) => boolean): T | undefined {
139 if (MonotonousArray.assertInvariants) {
140 if (this._prevFindLastPredicate) {
152 return idx === -1 ? undefined : this._array[idx];
153 }
154 > } arraysFind.ts
155 >
156 > /**
157 > * Returns the first item that is equal to or greater than every other item.
158 > */
159 > export function findFirstMax<T>(array: readonly T[], comparator: Comparator<T>): T | undefined {
160 if (array.length === 0) {
161 return undefined;
171 return max;
172 }
174 > /**
175 > * Returns the last item that is equal to or greater than every other item.
176 > */
177 > export function findLastMax<T>(array: readonly T[], comparator: Comparator<T>): T | undefined {
178 if (array.length === 0) {
179 return undefined;
189 return max;
190 }
192 > /**
193 > * Returns the first item that is equal to or less than every other item.
194 > */
195 > export function findFirstMin<T>(array: readonly T[], comparator: Comparator<T>): T | undefined {
196 return findFirstMax(array, (a, b) => -comparator(a, b));
197 }
199 > export function findMaxIdx<T>(array: readonly T[], comparator: Comparator<T>): number {
200 if (array.length === 0) {
201 return -1;
211 return maxIdx;
212 }
214 > /**
215 > * Returns the first mapped value of the array which is not undefined.
216 > */
217 > export function mapFindFirst<T, R>(items: Iterable<T>, mapFn: (value: T) => R | undefined): R | undefined {
218 for (const value of items) {
219 const mapped = mapFn(value);
src/vs/base/common/extpath.ts 91 covered LOC · 17 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extpath.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CharCode } from './charCode.js';
7 > import { isAbsolute, join, normalize, posix, sep } from './path.js';
8 > import { isWindows } from './platform.js';
9 > import { equalsIgnoreCase, rtrim, startsWithIgnoreCase } from './strings.js';
10 > import { isNumber } from './types.js';
11 >
12 > export function isPathSeparator(code: number) {
13 return code === CharCode.Slash || code === CharCode.Backslash;
14 }
15 > extpath.ts
16 > /**
17 > * Takes a Windows OS path and changes backward slashes to forward slashes.
18 > * This should only be done for OS paths from Windows (or user provided paths potentially from Windows).
19 > * Using it on a Linux or MaxOS path might change it.
20 > */
21 > export function toSlashes(osPath: string) {
22 return osPath.replace(/[\\/]/g, posix.sep);
23 }
24 > extpath.ts
25 > /**
26 > * Takes a Windows OS path (using backward or forward slashes) and turns it into a posix path:
27 > * - turns backward slashes into forward slashes
28 > * - makes it absolute if it starts with a drive letter
29 > * This should only be done for OS paths from Windows (or user provided paths potentially from Windows).
30 > * Using it on a Linux or MaxOS path might change it.
31 > */
32 > export function toPosixPath(osPath: string) {
33 if (osPath.indexOf('/') === -1) {
34 osPath = toSlashes(osPath);
39 return osPath;
40 }
41 > extpath.ts
42 > /**
43 > * Computes the _root_ this path, like `getRoot('c:\files') === c:\`,
44 > * `getRoot('files:///files/path') === files:///`,
45 > * or `getRoot('\\server\shares\path') === \\server\shares\`
46 > */
47 > export function getRoot(path: string, sep: string = posix.sep): string {
48 if (!path) {
49 return '';
111 return '';
112 }
113 > extpath.ts
114 > /**
115 > * Check if the path follows this pattern: `\\hostname\sharename`.
116 > *
117 > * @see https://msdn.microsoft.com/en-us/library/gg465305.aspx
118 > * @return A boolean indication if the path is a UNC path, on none-windows
119 > * always false.
120 > */
121 > export function isUNC(path: string): boolean {
122 if (!isWindows) {
123 // UNC is a windows concept
162 return true;
163 }
164 > extpath.ts
165 > // Reference: https://en.wikipedia.org/wiki/Filename
166 > const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g;
167 > const UNIX_INVALID_FILE_CHARS = /[/]/g;
168 > const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])(\.(.*?))?$/i;
169 > export function isValidBasename(name: string | null | undefined, isWindowsOS: boolean = isWindows): boolean {
170 const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS;
171
201 return true;
202 }
203 > extpath.ts
204 > /**
205 > * @deprecated please use `IUriIdentityService.extUri.isEqual` instead. If you are
206 > * in a context without services, consider to pass down the `extUri` from the outside
207 > * or use `extUriBiasedIgnorePathCase` if you know what you are doing.
208 > */
209 > export function isEqual(pathA: string, pathB: string, ignoreCase?: boolean): boolean {
210 const identityEquals = (pathA === pathB);
211 if (!ignoreCase || identityEquals) {
219 return equalsIgnoreCase(pathA, pathB);
220 }
221 > extpath.ts
222 > /**
223 > * @deprecated please use `IUriIdentityService.extUri.isEqualOrParent` instead. If
224 > * you are in a context without services, consider to pass down the `extUri` from the
225 > * outside, or use `extUriBiasedIgnorePathCase` if you know what you are doing.
226 > */
227 > export function isEqualOrParent(base: string, parentCandidate: string, ignoreCase?: boolean, forcePosixSemantics = false): boolean {
228 const separator = forcePosixSemantics ? posix.sep : sep;
229
272 return base.indexOf(parentCandidate) === 0;
273 }
274 > extpath.ts
275 > export function isWindowsDriveLetter(char0: number): boolean {
276 return char0 >= CharCode.A && char0 <= CharCode.Z || char0 >= CharCode.a && char0 <= CharCode.z;
277 }
278 > extpath.ts
279 > export function sanitizeFilePath(candidate: string, cwd: string): string {
280
281 // Special case: allow to open a drive letter without trailing backslash
295 return removeTrailingPathSeparator(candidate);
296 }
297 > extpath.ts
298 > export function removeTrailingPathSeparator(candidate: string): string {
299 if (isWindows) {
300 candidate = rtrim(candidate, sep);
316 return candidate;
317 }
318 > extpath.ts
319 > export function isRootOrDriveLetter(path: string): boolean {
320 const pathNormalized = normalize(path);
321
331 return pathNormalized === posix.sep;
332 }
333 > extpath.ts
334 > export function hasDriveLetter(path: string, isWindowsOS: boolean = isWindows): boolean {
335 if (isWindowsOS) {
336 return isWindowsDriveLetter(path.charCodeAt(0)) && path.charCodeAt(1) === CharCode.Colon;
339 return false;
340 }
341 > extpath.ts
342 > export function getDriveLetter(path: string, isWindowsOS: boolean = isWindows): string | undefined {
343 return hasDriveLetter(path, isWindowsOS) ? path[0] : undefined;
344 }
345 > extpath.ts
346 > export function indexOfPath(path: string, candidate: string, ignoreCase?: boolean): number {
347 if (candidate.length > path.length) {
348 return -1;
360 return path.indexOf(candidate);
361 }
362 > extpath.ts
363 > export interface IPathWithLineAndColumn {
364 > path: string;
365 > line?: number;
366 > column?: number;
367 > }
368 >
369 > export function parseLineAndColumnAware(rawPath: string): IPathWithLineAndColumn {
370 const segments = rawPath.split(':'); // C:\file.txt:<line>:<column>
371
395 };
396 }
397 > extpath.ts
398 > const pathChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
399 > const windowsSafePathFirstChars = 'BDEFGHIJKMOQRSTUVWXYZbdefghijkmoqrstuvwxyz0123456789';
400 >
401 > export function randomPath(parent?: string, prefix?: string, randomLength = 8): string {
402 let suffix = '';
403 for (let i = 0; i < randomLength; i++) {
src/vs/base/common/observableInternal/reactions/autorun.ts 91 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- autorun.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IReaderWithStore, IReader, IObservable, ISettableObservable } from '../base.js';
7 > import { IChangeTracker } from '../changeTracker.js';
8 > import { DisposableStore, IDisposable, toDisposable } from '../commonFacade/deps.js';
9 > import { DebugNameData, IDebugNameData } from '../debugName.js';
10 > import { AutorunObserver } from './autorunImpl.js';
11 > import { DebugLocation } from '../debugLocation.js';
12 > import { observableValue } from '../observables/observableValue.js';
13 > import { transaction } from '../transaction.js';
14 >
15 > /**
16 > * Runs immediately and whenever a transaction ends and an observed observable changed.
17 > * {@link fn} should start with a JS Doc using `@description` to name the autorun.
18 > */
19 > export function autorun(fn: (reader: IReaderWithStore) => void, debugLocation = DebugLocation.ofCaller()): IDisposable {
20 return new AutorunObserver(
21 new DebugNameData(undefined, undefined, fn),
25 );
26 }
27 > autorun.ts
28 > /**
29 > * Runs immediately and whenever a transaction ends and an observed observable changed.
30 > * {@link fn} should start with a JS Doc using `@description` to name the autorun.
31 > */
32 > export function autorunOpts(options: IDebugNameData & {}, fn: (reader: IReaderWithStore) => void, debugLocation = DebugLocation.ofCaller()): IDisposable {
33 return new AutorunObserver(
34 new DebugNameData(options.owner, options.debugName, options.debugReferenceFn ?? fn),
38 );
39 }
40 > autorun.ts
41 > /**
42 > * Runs immediately and whenever a transaction ends and an observed observable changed.
43 > * {@link fn} should start with a JS Doc using `@description` to name the autorun.
44 > *
45 > * Use `changeTracker.createChangeSummary` to create a "change summary" that can collect the changes.
46 > * Use `changeTracker.handleChange` to add a reported change to the change summary.
47 > * The run function is given the last change summary.
48 > * The change summary is discarded after the run function was called.
49 > *
50 > * @see autorun
51 > */
52 > export function autorunHandleChanges<TChangeSummary>(
53 options: IDebugNameData & {
54 changeTracker: IChangeTracker<TChangeSummary>;
64 );
65 }
66 > autorun.ts
67 > /**
68 > * @see autorunHandleChanges (but with a disposable store that is cleared before the next run or on dispose)
69 > */
70 > export function autorunWithStoreHandleChanges<TChangeSummary>(
71 options: IDebugNameData & {
72 changeTracker: IChangeTracker<TChangeSummary>;
92 });
93 }
94 > autorun.ts
95 > /**
96 > * @see autorun (but with a disposable store that is cleared before the next run or on dispose)
97 > *
98 > * @deprecated Use `autorun(reader => { reader.store.add(...) })` instead!
99 > */
100 > export function autorunWithStore(fn: (reader: IReader, store: DisposableStore) => void): IDisposable {
101 const store = new DisposableStore();
102 const disposable = autorunOpts(
116 });
117 }
118 > autorun.ts
119 > export function autorunDelta<T>(
120 observable: IObservable<T>,
121 handler: (args: { lastValue: T | undefined; newValue: T }) => void
129 });
130 }
131 > autorun.ts
132 > export function autorunIterableDelta<T>(
133 getValue: (reader: IReader) => Iterable<T>,
134 handler: (args: { addedValues: T[]; removedValues: T[] }) => void,
157 });
158 }
159 > autorun.ts
160 > /**
161 > * For each key-stable item in {@link items}, runs {@link setup} once when the
162 > * key is first observed and disposes the per-key {@link DisposableStore} when
163 > * the key is no longer present in the array (or when the returned disposable
164 > * is disposed).
165 > *
166 > * The {@link IObservable} handed to {@link setup} fires whenever the array
167 > * still contains an item with the same key but the item value itself has
168 > * changed (e.g. because the upstream state is immutable and produced a new
169 > * object with the same id). All per-key value updates triggered by a single
170 > * change to {@link items} are batched into one transaction, so dependent
171 > * autoruns observe a consistent snapshot.
172 > *
173 > * Per-key state should be stored in closures or in disposables registered
174 > * against the per-key {@link DisposableStore}. {@link setup} should not call
175 > * `.read()` on the outer {@link items} observable from its body (use the
176 > * provided per-key value observable, or create inner autoruns).
177 > */
178 > export function autorunPerKeyedItem<TIn, TKey>(
179 items: IObservable<readonly TIn[]>,
180 keyFn: (input: TIn) => TKey,
227 });
228 }
229 > autorun.ts
230 > export interface IReaderWithDispose extends IReaderWithStore, IDisposable { }
231 >
232 > /**
233 > * An autorun with a `dispose()` method on its `reader` which cancels the autorun.
234 > * It it safe to call `dispose()` synchronously.
235 > * @deprecated Use autorunSelfDisposable2
236 > */
237 > export function autorunSelfDisposable(fn: (reader: IReaderWithDispose) => void, debugLocation = DebugLocation.ofCaller()): IDisposable {
238 let ar: IDisposable | undefined;
239 let disposed = false;
258 return ar;
259 }
260 > autorun.ts
261 >
262 > /**
263 > * An autorun with a `dispose()` method on its `reader` which cancels the autorun.
264 > * It it safe to call `dispose()` synchronously.
265 > * TODO@hediet/copilot: rename to delete autorunSelfDisposable, and rename autorunSelfDisposable2 to autorunSelfDisposable.
266 > */
267 > export function registerAutorunSelfDisposable(store: DisposableStore, fn: (reader: IReaderWithDispose) => void, debugLocation = DebugLocation.ofCaller()): void {
268 let ar: IDisposable | undefined;
269 let disposeSync = false;
src/vs/base/common/cancellation.ts 90 covered LOC · 18 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- cancellation.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Emitter, Event } from './event.js';
7 > import { DisposableStore, IDisposable } from './lifecycle.js';
8 >
9 > export interface CancellationToken {
10 >
11 > /**
12 > * A flag signalling is cancellation has been requested.
13 > */
14 > readonly isCancellationRequested: boolean;
15 >
16 > /**
17 > * An event which fires when cancellation is requested. This event
18 > * only ever fires `once` as cancellation can only happen once. Listeners
19 > * that are registered after cancellation will be called (next event loop run),
20 > * but also only once.
21 > *
22 > * @event
23 > */
24 > readonly onCancellationRequested: (listener: (e: void) => unknown, thisArgs?: unknown, disposables?: IDisposable[]) => IDisposable;
25 > }
26 >
27 > const shortcutEvent: Event<void> = Object.freeze(function (callback, context?): IDisposable {
28 const handle = setTimeout(callback.bind(context), 0);
29 return { dispose() { clearTimeout(handle); } };
30 });
32 > export namespace CancellationToken {
33 >
34 > export function isCancellationToken(thing: unknown): thing is CancellationToken {
35 if (thing === CancellationToken.None || thing === CancellationToken.Cancelled) {
36 return true;
45 && typeof (thing as CancellationToken).onCancellationRequested === 'function';
46 }
48 >
49 > export const None = Object.freeze<CancellationToken>({
50 > isCancellationRequested: false,
51 > onCancellationRequested: Event.None
52 > });
53 >
54 > export const Cancelled = Object.freeze<CancellationToken>({
55 > isCancellationRequested: true,
56 > onCancellationRequested: shortcutEvent
57 > });
58 > }
59 >
60 class MutableToken implements CancellationToken {
61
62 private _isCancelled: boolean = false;
63 private _emitter: Emitter<void> | null = null;
65 > public cancel() {
66 if (!this._isCancelled) {
67 this._isCancelled = true;
72 }
73 }
75 > get isCancellationRequested(): boolean {
76 return this._isCancelled;
77 }
79 > get onCancellationRequested(): Event<void> {
80 if (this._isCancelled) {
81 return shortcutEvent;
86 return this._emitter.event;
87 }
89 > public dispose(): void {
90 if (this._emitter) {
91 this._emitter.dispose();
93 }
94 }
96 >
97 > export class CancellationTokenSource {
98 >
99 > private _token?: CancellationToken = undefined;
100 > private _parentListener?: IDisposable = undefined;
101 >
102 > constructor(parent?: CancellationToken) {
103 this._parentListener = parent && parent.onCancellationRequested(this.cancel, this);
104 }
106 > get token(): CancellationToken {
107 if (!this._token) {
108 // be lazy and create the token only when
112 return this._token;
113 }
115 > cancel(): void {
116 if (!this._token) {
117 // save an object by returning the default
125 }
126 }
128 > dispose(cancel: boolean = false): void {
129 if (cancel) {
130 this.cancel();
140 }
141 }
142 > } cancellation.ts
143 >
144 > export function cancelOnDispose(store: DisposableStore): CancellationToken {
145 const source = new CancellationTokenSource();
146 store.add({ dispose() { source.cancel(); } });
147 return source.token;
148 }
150 > /**
151 > * A pool that aggregates multiple cancellation tokens. The pool's own token
152 > * (accessible via `pool.token`) is cancelled only after every token added
153 > * to the pool has been cancelled. Adding tokens after the pool token has
154 > * been cancelled has no effect.
155 > */
156 > export class CancellationTokenPool {
157
158 private readonly _source = new CancellationTokenSource();
162 private _cancelled: number = 0;
163 private _isDone: boolean = false;
165 > get token(): CancellationToken {
166 return this._source.token;
167 }
169 > /**
170 > * Add a token to the pool. If the token is already cancelled it is counted
171 > * immediately. Tokens added after the pool token has been cancelled are ignored.
172 > */
173 > add(token: CancellationToken): void {
174 if (this._isDone) {
175 return;
191 this._listeners.add(d);
192 }
194 > private _check(): void {
195 if (!this._isDone && this._total > 0 && this._total === this._cancelled) {
196 this._isDone = true;
src/vs/base/common/observableInternal/utils/utils.ts 89 covered LOC · 21 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- utils.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { autorun } from '../reactions/autorun.js';
7 > import { IObservable, IObservableWithChange, IObserver, IReader, ITransaction } from '../base.js';
8 > import { observableValue } from '../observables/observableValue.js';
9 > import { DebugOwner } from '../debugName.js';
10 > import { DisposableStore, Event, IDisposable, toDisposable } from '../commonFacade/deps.js';
11 > import { derived, derivedOpts } from '../observables/derived.js';
12 > import { observableFromEvent } from '../observables/observableFromEvent.js';
13 > import { observableSignal } from '../observables/observableSignal.js';
14 > import { _setKeepObserved, _setRecomputeInitiallyAndOnChange } from '../observables/baseObservable.js';
15 > import { DebugLocation } from '../debugLocation.js';
16 >
17 > export function observableFromPromise<T>(promise: Promise<T>): IObservable<{ value?: T }> {
18 const observable = observableValue<{ value?: T }>('promiseValue', {});
19 promise.then((value) => {
22 return observable;
23 }
24 > utils.ts
25 > export function signalFromObservable<T>(owner: DebugOwner | undefined, observable: IObservable<T>): IObservable<void> {
26 return derivedOpts({
27 owner,
31 });
32 }
33 > utils.ts
34 > /**
35 > * Creates an observable that debounces the input observable.
36 > */
37 > export function debouncedObservable<T>(observable: IObservable<T>, debounceMs: number | ((lastValue: T | undefined, newValue: T) => number), debugLocation = DebugLocation.ofCaller()): IObservable<T> {
38 let hasValue = false;
39 let lastValue: T | undefined;
79 }, debugLocation);
80 }
81 > utils.ts
82 > /**
83 > * Creates an observable that throttles the input observable.
84 > * Unlike {@link debouncedObservable}, the timer starts on the first change
85 > * and is not reset by subsequent changes, preventing starvation.
86 > */
87 > export function throttledObservable<T>(observable: IObservable<T>, throttleMs: number, debugLocation = DebugLocation.ofCaller()): IObservable<T> {
88 let hasValue = false;
89 let lastValue: T | undefined;
126 }, debugLocation);
127 }
128 > utils.ts
129 > /**
130 > * Creates an observable that debounces the input observable.
131 > */
132 > export function debouncedObservable2<T>(observable: IObservable<T>, debounceMs: number | ((currentValue: T | undefined, newValue: T) => number), debugLocation = DebugLocation.ofCaller()): IObservable<T> {
133 const s = observableSignal('handleTimeout');
134
167 return d;
168 }
169 > utils.ts
170 > export function wasEventTriggeredRecently(event: Event<any>, timeoutMs: number, disposableStore: DisposableStore): IObservable<boolean> {
171 const observable = observableValue('triggeredRecently', false);
172
186 return observable;
187 }
188 > utils.ts
189 > /**
190 > * This makes sure the observable is being observed and keeps its cache alive.
191 > */
192 > export function keepObserved<T>(observable: IObservable<T>): IDisposable {
193 const o = new KeepAliveObserver(false, undefined);
194 observable.addObserver(o);
197 });
198 }
199 > utils.ts
200 > _setKeepObserved(keepObserved);
201 >
202 > /**
203 > * This converts the given observable into an autorun.
204 > */
205 > export function recomputeInitiallyAndOnChange<T>(observable: IObservable<T>, handleValue?: (value: T) => void): IDisposable {
206 const o = new KeepAliveObserver(true, handleValue);
207 observable.addObserver(o);
216 });
217 }
218 > utils.ts
219 > _setRecomputeInitiallyAndOnChange(recomputeInitiallyAndOnChange);
220 >
221 > export class KeepAliveObserver implements IObserver {
222 > private _counter = 0;
223 >
224 > constructor(
225 private readonly _forceRecompute: boolean,
226 private readonly _handleValue: ((value: any) => void) | undefined,
227 ) { }
228 > utils.ts
229 > beginUpdate<T>(observable: IObservable<T>): void {
230 this._counter++;
231 }
232 > utils.ts
233 > endUpdate<T>(observable: IObservable<T>): void {
234 if (this._counter === 1 && this._forceRecompute) {
235 if (this._handleValue) {
241 this._counter--;
242 }
243 > utils.ts
244 > handlePossibleChange<T>(observable: IObservable<T>): void {
245 // NO OP
246 }
247 > utils.ts
248 > handleChange<T, TChange>(observable: IObservableWithChange<T, TChange>, change: TChange): void {
249 // NO OP
250 }
251 > } utils.ts
252 >
253 > export function derivedObservableWithCache<T>(owner: DebugOwner, computeFn: (reader: IReader, lastValue: T | undefined) => T): IObservable<T> {
254 let lastValue: T | undefined = undefined;
255 const observable = derivedOpts({ owner, debugReferenceFn: computeFn }, reader => {
259 return observable;
260 }
261 > utils.ts
262 > export function derivedObservableWithWritableCache<T>(owner: object, computeFn: (reader: IReader, lastValue: T | undefined) => T): IObservable<T>
263 & { clearCache(transaction: ITransaction): void; setCache(newValue: T | undefined, tx: ITransaction | undefined): void } {
264 let lastValue: T | undefined = undefined;
280 });
281 }
282 > utils.ts
283 > /**
284 > * When the items array changes, referential equal items are not mapped again.
285 > */
286 > export function mapObservableArrayCached<TIn, TOut, TKey = TIn>(owner: DebugOwner, items: IObservable<readonly TIn[]>, map: (input: TIn, store: DisposableStore) => TOut, keySelector?: (input: TIn) => TKey): IObservable<readonly TOut[]> {
287 let m = new ArrayMap(map, keySelector);
288 const self = derivedOpts({
300 return self;
301 }
302 > utils.ts
303 > class ArrayMap<TIn, TOut, TKey> implements IDisposable {
304 > private readonly _cache = new Map<TKey, { out: TOut; store: DisposableStore }>();
305 > private _items: TOut[] = [];
306 > constructor(
307 private readonly _map: (input: TIn, store: DisposableStore) => TOut,
308 private readonly _keySelector?: (input: TIn) => TKey,
309 ) {
310 }
311 > utils.ts
312 > public dispose(): void {
313 this._cache.forEach(entry => entry.store.dispose());
314 this._cache.clear();
315 }
316 > utils.ts
317 > public setItems(items: readonly TIn[]): void {
318 const newItems: TOut[] = [];
319 const itemsToRemove = new Set(this._cache.keys());
342 this._items = newItems;
343 }
344 > utils.ts
345 > public getItems(): TOut[] {
346 return this._items;
347 }
348 > } utils.ts
349 >
350 > export function isObservable<T>(obj: unknown): obj is IObservable<T> {
351 return !!obj && (<IObservable<T>>obj).read !== undefined && (<IObservable<T>>obj).reportChanges !== undefined;
352 }
src/vs/base/common/cache.ts 88 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- cache.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CancellationToken, CancellationTokenSource } from './cancellation.js';
7 > import { IDisposable } from './lifecycle.js';
8 >
9 > export interface CacheResult<T> extends IDisposable {
10 > promise: Promise<T>;
11 > }
12 >
13 > export class Cache<T> {
14 >
15 > private result: CacheResult<T> | null = null;
16 > constructor(private task: (ct: CancellationToken) => Promise<T>) { }
17 >
18 > get(): CacheResult<T> {
19 if (this.result) {
20 return this.result;
35 return this.result;
36 }
37 > } cache.ts
38 >
39 > export function identity<T>(t: T): T {
40 return t;
41 }
42 > cache.ts
43 > interface ICacheOptions<TArg> {
44 > /**
45 > * The cache key is used to identify the cache entry.
46 > * Strict equality is used to compare cache keys.
47 > */
48 > getCacheKey: (arg: TArg) => unknown;
49 > }
50 >
51 > /**
52 > * Uses a LRU cache to make a given parametrized function cached.
53 > * Caches just the last key/value.
54 > */
55 > export class LRUCachedFunction<TArg, TComputed> {
56 > private lastCache: TComputed | undefined = undefined;
57 > private lastArgKey: unknown | undefined = undefined;
58 >
59 > private readonly _fn: (arg: TArg) => TComputed;
60 > private readonly _computeKey: (arg: TArg) => unknown;
61 >
62 > constructor(fn: (arg: TArg) => TComputed);
63 > constructor(options: ICacheOptions<TArg>, fn: (arg: TArg) => TComputed);
64 > constructor(arg1: ICacheOptions<TArg> | ((arg: TArg) => TComputed), arg2?: (arg: TArg) => TComputed) {
65 > if (typeof arg1 === 'function') {
66 > this._fn = arg1;
67 > this._computeKey = identity;
68 > } else {
69 this._fn = arg2!;
70 this._computeKey = arg1.getCacheKey;
71 }
72 > } cache.ts
73 >
74 > public get(arg: TArg): TComputed {
75 const key = this._computeKey(arg);
76 if (this.lastArgKey !== key) {
80 return this.lastCache!;
81 }
82 > } cache.ts
83 >
84 > /**
85 > * Uses an unbounded cache to memoize the results of the given function.
86 > */
87 > export class CachedFunction<TArg, TComputed> {
88 > private readonly _map = new Map<TArg, TComputed>();
89 > private readonly _map2 = new Map<unknown, TComputed>();
90 > public get cachedValues(): ReadonlyMap<TArg, TComputed> {
91 > return this._map;
92 > }
93 >
94 > private readonly _fn: (arg: TArg) => TComputed;
95 > private readonly _computeKey: (arg: TArg) => unknown;
96 >
97 > constructor(fn: (arg: TArg) => TComputed);
98 > constructor(options: ICacheOptions<TArg>, fn: (arg: TArg) => TComputed);
99 > constructor(arg1: ICacheOptions<TArg> | ((arg: TArg) => TComputed), arg2?: (arg: TArg) => TComputed) {
100 if (typeof arg1 === 'function') {
101 this._fn = arg1;
106 }
107 }
108 > cache.ts
109 > public get(arg: TArg): TComputed {
110 const key = this._computeKey(arg);
111 if (this._map2.has(key)) {
118 return value;
119 }
120 > } cache.ts
121 >
122 > /**
123 > * Uses an unbounded cache to memoize the results of the given function.
124 > */
125 > export class WeakCachedFunction<TArg, TComputed> {
126 > private readonly _map = new WeakMap<WeakKey, TComputed>();
127 >
128 > private readonly _fn: (arg: TArg) => TComputed;
129 > private readonly _computeKey: (arg: TArg) => unknown;
130 >
131 > constructor(fn: (arg: TArg) => TComputed);
132 > constructor(options: ICacheOptions<TArg>, fn: (arg: TArg) => TComputed);
133 > constructor(arg1: ICacheOptions<TArg> | ((arg: TArg) => TComputed), arg2?: (arg: TArg) => TComputed) {
134 if (typeof arg1 === 'function') {
135 this._fn = arg1;
140 }
141 }
142 > cache.ts
143 > public get(arg: TArg): TComputed {
144 const key = this._computeKey(arg) as WeakKey;
145 if (this._map.has(key)) {
151 return value;
152 }
153 > } cache.ts
src/vs/base/common/observableInternal/reactions/autorunImpl.ts 78 covered LOC · 18 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- autorunImpl.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable, IObservableWithChange, IObserver, IReaderWithStore } from '../base.js';
7 > import { DebugNameData } from '../debugName.js';
8 > import { assertFn, BugIndicatingError, DisposableStore, IDisposable, markAsDisposed, onBugIndicatingError, trackDisposable } from '../commonFacade/deps.js';
9 > import { getLogger } from '../logging/logging.js';
10 > import { IChangeTracker } from '../changeTracker.js';
11 > import { DebugLocation } from '../debugLocation.js';
12 >
13 > export const enum AutorunState {
14 > /**
15 > * A dependency could have changed.
16 > * We need to explicitly ask them if at least one dependency changed.
17 > */
18 > dependenciesMightHaveChanged = 1,
19 >
20 > /**
21 > * A dependency changed and we need to recompute.
22 > */
23 > stale = 2,
24 > upToDate = 3,
25 > }
26 >
27 function autorunStateToString(state: AutorunState): string {
28 switch (state) {
33 }
34 }
36 > export class AutorunObserver<TChangeSummary = any> implements IObserver, IReaderWithStore, IDisposable {
37 > private _state = AutorunState.stale;
38 > private _updateCount = 0;
39 > private _disposed = false;
40 > private _dependencies = new Set<IObservable<any>>();
41 > private _dependenciesToBeRemoved = new Set<IObservable<any>>();
42 > private _changeSummary: TChangeSummary | undefined;
43 > private _isRunning = false;
44 > private _iteration = 0;
45 >
46 > public get debugName(): string {
47 > return this._debugNameData.getDebugName(this) ?? '(anonymous)';
48 > }
49 >
50 > constructor(
51 public readonly _debugNameData: DebugNameData,
52 public readonly _runFn: (reader: IReaderWithStore, changeSummary: TChangeSummary) => void,
60 trackDisposable(this);
61 }
63 > public dispose(): void {
64 if (this._disposed) {
65 return;
81 markAsDisposed(this);
82 }
84 > private _run() {
85 const emptySet = this._dependenciesToBeRemoved;
86 this._dependenciesToBeRemoved = this._dependencies;
130 }
131 }
133 > public toString(): string {
134 return `Autorun<${this.debugName}>`;
135 }
137 > // IObserver implementation
138 > public beginUpdate(_observable: IObservable<any>): void {
139 if (this._state === AutorunState.upToDate) {
140 this._checkIterations();
143 this._updateCount++;
144 }
146 > public endUpdate(_observable: IObservable<any>): void {
147 try {
148 if (this._updateCount === 1) {
175 assertFn(() => this._updateCount >= 0);
176 }
178 > public handlePossibleChange(observable: IObservable<any>): void {
179 if (this._state === AutorunState.upToDate && this._isDependency(observable)) {
180 this._checkIterations();
182 }
183 }
185 > public handleChange<T, TChange>(observable: IObservableWithChange<T, TChange>, change: TChange): void {
186 if (this._isDependency(observable)) {
187 getLogger()?.handleAutorunDependencyChanged(this, observable, change);
203 }
204 }
206 > private _isDependency(observable: IObservableWithChange<any, any>): boolean {
207 return this._dependencies.has(observable) && !this._dependenciesToBeRemoved.has(observable);
208 }
210 > // IReader implementation
211 >
212 > private _ensureNoRunning(): void {
213 if (!this._isRunning) { throw new BugIndicatingError('The reader object cannot be used outside its compute function!'); }
214 }
216 > public readObservable<T>(observable: IObservable<T>): T {
217 this._ensureNoRunning();
218
228 return value;
229 }
231 > private _store: DisposableStore | undefined = undefined;
232 > get store(): DisposableStore {
233 this._ensureNoRunning();
234 if (this._disposed) {
241 return this._store;
242 }
244 > private _delayedStore: DisposableStore | undefined = undefined;
245 > get delayedStore(): DisposableStore {
246 this._ensureNoRunning();
247 if (this._disposed) {
254 return this._delayedStore;
255 }
257 > public debugGetState() {
258 return {
259 isRunning: this._isRunning,
264 };
265 }
267 > public debugRerun(): void {
268 if (!this._isRunning) {
269 this._run();
272 }
273 }
275 > private _checkIterations(): boolean {
276 if (this._iteration > 100) {
277 onBugIndicatingError(new BugIndicatingError(`Autorun '${this.debugName}' is stuck in an infinite update loop.`));
src/vs/base/common/observableInternal/logging/debugGetDependencyGraph.ts 75 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- debugGetDependencyGraph.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable, IObserver } from '../base.js';
7 > import { Derived } from '../observables/derivedImpl.js';
8 > import { FromEventObservable } from '../observables/observableFromEvent.js';
9 > import { ObservableValue } from '../observables/observableValue.js';
10 > import { AutorunObserver } from '../reactions/autorunImpl.js';
11 > import { formatValue } from './consoleObservableLogger.js';
12 >
13 > interface IOptions {
14 > type: 'dependencies' | 'observers';
15 > debugNamePostProcessor?: (name: string) => string;
16 > }
17 >
18 > export function debugGetObservableGraph(obs: IObservable<any> | IObserver, options: IOptions): string {
19 const debugNamePostProcessor = options?.debugNamePostProcessor ?? ((str: string) => str);
20 const info = Info.from(obs, debugNamePostProcessor);
31 }
32 }
34 function formatObservableInfoWithDependencies(info: Info, indentLevel: number, alreadyListed: Set<IObservable<any> | IObserver>, options: IOptions): string {
35 const indent = '\t\t'.repeat(indentLevel);
58 return lines.join('\n');
59 }
61 function formatObservableInfoWithObservers(info: Info, indentLevel: number, alreadyListed: Set<IObservable<any> | IObserver>, options: IOptions): string {
62 const indent = '\t\t'.repeat(indentLevel);
85 return lines.join('\n');
86 }
88 > class Info {
89 > public static from(obs: IObservable<any> | IObserver, debugNamePostProcessor: (name: string) => string): Info | undefined {
90 > if (obs instanceof AutorunObserver) {
91 > const state = obs.debugGetState(); debugGetDependencyGraph.ts
92 > return new Info(
93 > obs,
94 > debugNamePostProcessor(obs.debugName),
95 > 'autorun',
96 > undefined,
97 > state.stateStr,
98 > Array.from(state.dependencies),
99 > []
100 > );
101 > } else if (obs instanceof Derived) { debugGetDependencyGraph.ts
102 > const state = obs.debugGetState();
103 > return new Info(
104 > obs,
105 > debugNamePostProcessor(obs.debugName),
106 > 'derived',
107 > state.value,
108 > state.stateStr,
109 > Array.from(state.dependencies),
110 > Array.from(obs.debugGetObservers())
111 > );
112 > } else if (obs instanceof ObservableValue) {
113 > const state = obs.debugGetState();
114 > return new Info(
115 > obs,
116 > debugNamePostProcessor(obs.debugName),
117 > 'observableValue',
118 > state.value,
119 > 'upToDate',
120 > [],
121 > Array.from(obs.debugGetObservers())
122 > );
123 > } else if (obs instanceof FromEventObservable) {
124 > const state = obs.debugGetState(); debugGetDependencyGraph.ts
125 > return new Info(
126 > obs,
127 > debugNamePostProcessor(obs.debugName),
128 > 'fromEvent',
129 > state.value,
130 > state.hasValue ? 'upToDate' : 'initial',
131 > [],
132 > Array.from(obs.debugGetObservers())
133 > );
134 > }
135 > return undefined;
137 >
138 > public static unknown(obs: IObservable<any> | IObserver): Info {
139 return new Info(
140 obs,
147 );
148 }
150 > constructor(
151 public readonly sourceObj: IObservable<any> | IObserver,
152 public readonly name: string,
src/vs/base/common/collections.ts 74 covered LOC · 18 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- collections.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > /**
7 > * An interface for a JavaScript object that
8 > * acts a dictionary. The keys are strings.
9 > */
10 > export type IStringDictionary<V> = Record<string, V>;
11 >
12 > /**
13 > * An interface for a JavaScript object that
14 > * acts a dictionary. The keys are numbers.
15 > */
16 > export type INumberDictionary<V> = Record<number, V>;
17 >
18 > /**
19 > * Groups the collection into a dictionary based on the provided
20 > * group function.
21 > */
22 > export function groupBy<K extends string | number | symbol, V>(data: readonly V[], groupFn: (element: V) => K): Partial<Record<K, V[]>> {
23 const result: Partial<Record<K, V[]>> = Object.create(null);
24 for (const element of data) {
32 return result;
33 }
35 > export function groupByMap<K, V>(data: V[], groupFn: (element: V) => K): Map<K, V[]> {
36 const result = new Map<K, V[]>();
37 for (const element of data) {
46 return result;
47 }
49 > export function diffSets<T>(before: ReadonlySet<T>, after: ReadonlySet<T>): { removed: T[]; added: T[] } {
50 const removed: T[] = [];
51 const added: T[] = [];
62 return { removed, added };
63 }
65 > /**
66 > * Checks whether two sets contain exactly the same elements.
67 > *
68 > * @param a - The first set.
69 > * @param b - The second set.
70 > * @returns `true` if both sets have the same size and every element of `a` is also in `b`.
71 > */
72 > export function equalSets<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): boolean {
73 if (a === b) {
74 return true;
84 return true;
85 }
87 > export function diffMaps<K, V>(before: Map<K, V>, after: Map<K, V>): { removed: V[]; added: V[] } {
88 const removed: V[] = [];
89 const added: V[] = [];
100 return { removed, added };
101 }
103 > /**
104 > * Computes the intersection of two sets.
105 > *
106 > * @param setA - The first set.
107 > * @param setB - The second iterable.
108 > * @returns A new set containing the elements that are in both `setA` and `setB`.
109 > */
110 > export function intersection<T>(setA: Set<T>, setB: Iterable<T>): Set<T> {
111 const result = new Set<T>();
112 for (const elem of setB) {
117 return result;
118 }
120 > export class SetWithKey<T> implements Set<T> {
121 > private _map = new Map<unknown, T>();
122 >
123 > constructor(values: T[], private toKey: (t: T) => unknown) {
124 for (const value of values) {
125 this.add(value);
126 }
127 }
129 > get size(): number {
130 return this._map.size;
131 }
133 > add(value: T): this {
134 const key = this.toKey(value);
135 this._map.set(key, value);
136 return this;
137 }
139 > delete(value: T): boolean {
140 return this._map.delete(this.toKey(value));
141 }
143 > has(value: T): boolean {
144 return this._map.has(this.toKey(value));
145 }
147 > *entries(): SetIterator<[T, T]> {
148 for (const entry of this._map.values()) {
149 yield [entry, entry];
150 }
151 }
153 > keys(): SetIterator<T> {
154 return this.values();
155 }
157 > *values(): SetIterator<T> {
158 for (const entry of this._map.values()) {
159 yield entry;
160 }
161 }
163 > clear(): void {
164 this._map.clear();
165 }
167 > forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: unknown): void {
168 this._map.forEach(entry => callbackfn.call(thisArg, entry, entry, this));
169 }
171 > [Symbol.iterator](): SetIterator<T> {
172 return this.values();
173 }
175 > [Symbol.toStringTag]: string = 'SetWithKey';
176 > }
src/vs/base/common/observableInternal/logging/logging.ts 67 covered LOC · 17 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- logging.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { AutorunObserver } from '../reactions/autorunImpl.js';
7 > import { IObservable } from '../base.js';
8 > import { TransactionImpl } from '../transaction.js';
9 > import type { Derived } from '../observables/derivedImpl.js';
10 > import { DebugLocation } from '../debugLocation.js';
11 >
12 > let globalObservableLogger: IObservableLogger | undefined;
13 >
14 > export function addLogger(logger: IObservableLogger): void {
15 if (!globalObservableLogger) {
16 globalObservableLogger = logger;
21 }
22 }
23 > logging.ts
24 > export function getLogger(): IObservableLogger | undefined {
25 return globalObservableLogger;
26 }
27 > logging.ts
28 > let globalObservableLoggerFn: ((obs: IObservable<any>) => void) | undefined = undefined;
29 > export function setLogObservableFn(fn: (obs: IObservable<any>) => void): void {
30 > globalObservableLoggerFn = fn;
31 > }
32 >
33 > export function logObservable(obs: IObservable<any>): void {
34 if (globalObservableLoggerFn) {
35 globalObservableLoggerFn(obs);
36 }
37 }
38 > logging.ts
39 > export interface IChangeInformation {
40 > oldValue: unknown;
41 > newValue: unknown;
42 > change: unknown;
43 > didChange: boolean;
44 > hadValue: boolean;
45 > }
46 >
47 > export interface IObservableLogger {
48 > handleObservableCreated(observable: IObservable<any>, location: DebugLocation): void;
49 > handleOnListenerCountChanged(observable: IObservable<any>, newCount: number): void;
50 >
51 > handleObservableUpdated(observable: IObservable<any>, info: IChangeInformation): void;
52 >
53 > handleAutorunCreated(autorun: AutorunObserver, location: DebugLocation): void;
54 > handleAutorunDisposed(autorun: AutorunObserver): void;
55 > handleAutorunDependencyChanged(autorun: AutorunObserver, observable: IObservable<any>, change: unknown): void;
56 > handleAutorunStarted(autorun: AutorunObserver): void;
57 > handleAutorunFinished(autorun: AutorunObserver): void;
58 >
59 > handleDerivedDependencyChanged(derived: Derived<any, any, any>, observable: IObservable<any>, change: unknown): void;
60 > handleDerivedCleared(observable: Derived<any, any, any>): void;
61 >
62 > handleBeginTransaction(transaction: TransactionImpl): void;
63 > handleEndTransaction(transaction: TransactionImpl): void;
64 > }
65 >
66 > class ComposedLogger implements IObservableLogger {
67 > constructor(
68 public readonly loggers: IObservableLogger[],
69 ) { }
70 > logging.ts
71 > handleObservableCreated(observable: IObservable<any>, location: DebugLocation): void {
72 for (const logger of this.loggers) {
73 logger.handleObservableCreated(observable, location);
74 }
75 }
76 > handleOnListenerCountChanged(observable: IObservable<any>, newCount: number): void { logging.ts
77 for (const logger of this.loggers) {
78 logger.handleOnListenerCountChanged(observable, newCount);
79 }
80 }
81 > handleObservableUpdated(observable: IObservable<any>, info: IChangeInformation): void { logging.ts
82 for (const logger of this.loggers) {
83 logger.handleObservableUpdated(observable, info);
84 }
85 }
86 > handleAutorunCreated(autorun: AutorunObserver, location: DebugLocation): void { logging.ts
87 for (const logger of this.loggers) {
88 logger.handleAutorunCreated(autorun, location);
89 }
90 }
91 > handleAutorunDisposed(autorun: AutorunObserver): void { logging.ts
92 for (const logger of this.loggers) {
93 logger.handleAutorunDisposed(autorun);
94 }
95 }
96 > handleAutorunDependencyChanged(autorun: AutorunObserver, observable: IObservable<any>, change: unknown): void { logging.ts
97 for (const logger of this.loggers) {
98 logger.handleAutorunDependencyChanged(autorun, observable, change);
99 }
100 }
101 > handleAutorunStarted(autorun: AutorunObserver): void { logging.ts
102 for (const logger of this.loggers) {
103 logger.handleAutorunStarted(autorun);
104 }
105 }
106 > handleAutorunFinished(autorun: AutorunObserver): void { logging.ts
107 for (const logger of this.loggers) {
108 logger.handleAutorunFinished(autorun);
109 }
110 }
111 > handleDerivedDependencyChanged(derived: Derived<any>, observable: IObservable<any>, change: unknown): void { logging.ts
112 for (const logger of this.loggers) {
113 logger.handleDerivedDependencyChanged(derived, observable, change);
114 }
115 }
116 > handleDerivedCleared(observable: Derived<any>): void { logging.ts
117 for (const logger of this.loggers) {
118 logger.handleDerivedCleared(observable);
119 }
120 }
121 > handleBeginTransaction(transaction: TransactionImpl): void { logging.ts
122 for (const logger of this.loggers) {
123 logger.handleBeginTransaction(transaction);
124 }
125 }
126 > handleEndTransaction(transaction: TransactionImpl): void { logging.ts
127 for (const logger of this.loggers) {
128 logger.handleEndTransaction(transaction);
129 }
130 }
131 > } logging.ts
src/vs/base/common/themables.ts 65 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- themables.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Codicon } from './codicons.js';
7 >
8 > export type ColorIdentifier = string;
9 >
10 > export type IconIdentifier = string;
11 >
12 > export interface ThemeColor {
13 > id: string;
14 > }
15 >
16 > export namespace ThemeColor {
17 > export function isThemeColor(obj: unknown): obj is ThemeColor {
18 return !!obj && typeof obj === 'object' && typeof (<ThemeColor>obj).id === 'string';
19 }
20 > } themables.ts
21 >
22 > export function themeColorFromId(id: ColorIdentifier) {
23 return { id };
24 }
26 >
27 > export interface ThemeIcon {
28 > readonly id: string;
29 > readonly color?: ThemeColor;
30 > }
31 >
32 > export namespace ThemeIcon {
33 > export const iconNameSegment = '[A-Za-z0-9]+';
34 > export const iconNameExpression = '[A-Za-z0-9-]+';
35 > export const iconModifierExpression = '~[A-Za-z]+';
36 > export const iconNameCharacter = '[A-Za-z0-9~-]';
37 >
38 > const ThemeIconIdRegex = new RegExp(`^(${iconNameExpression})(${iconModifierExpression})?$`);
39 >
40 > export function asClassNameArray(icon: ThemeIcon): string[] {
41 const match = ThemeIconIdRegex.exec(icon.id);
42 if (!match) {
50 return classNames;
51 }
53 > export function asClassName(icon: ThemeIcon): string {
54 return asClassNameArray(icon).join(' ');
55 }
57 > export function asCSSSelector(icon: ThemeIcon): string {
58 return '.' + asClassNameArray(icon).join('.');
59 }
61 > export function isThemeIcon(obj: unknown): obj is ThemeIcon {
62 return !!obj && typeof obj === 'object' && typeof (<ThemeIcon>obj).id === 'string' && (typeof (<ThemeIcon>obj).color === 'undefined' || ThemeColor.isThemeColor((<ThemeIcon>obj).color));
63 }
65 > const _regexFromString = new RegExp(`^\\$\\((${ThemeIcon.iconNameExpression}(?:${ThemeIcon.iconModifierExpression})?)\\)$`);
66 >
67 > export function fromString(str: string): ThemeIcon | undefined {
68 const match = _regexFromString.exec(str);
69 if (!match) {
73 return { id: name };
74 }
76 > export function fromId(id: string): ThemeIcon {
77 return { id };
78 }
80 > export function modify(icon: ThemeIcon, modifier: 'disabled' | 'spin' | undefined): ThemeIcon {
81 let id = icon.id;
82 const tildeIndex = id.lastIndexOf('~');
89 return { id };
90 }
92 > export function getModifier(icon: ThemeIcon): string | undefined {
93 const tildeIndex = icon.id.lastIndexOf('~');
94 if (tildeIndex !== -1) {
97 return undefined;
98 }
100 > export function isEqual(ti1: ThemeIcon, ti2: ThemeIcon): boolean {
101 return ti1.id === ti2.id && ti1.color?.id === ti2.color?.id;
102 }
103 > themables.ts
104 > /**
105 > * Returns whether specified icon is defined and has 'file' ID.
106 > */
107 > export function isFile(icon: ThemeIcon | undefined): boolean {
108 return icon?.id === Codicon.file.id;
109 }
110 > themables.ts
111 > /**
112 > * Returns whether specified icon is defined and has 'folder' ID.
113 > */
114 > export function isFolder(icon: ThemeIcon | undefined): boolean {
115 return icon?.id === Codicon.folder.id;
116 }
117 > } themables.ts
src/vs/base/common/codicons.ts 64 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- codicons.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 > import { ThemeIcon } from './themables.js';
6 > import { register } from './codiconsUtil.js';
7 > import { codiconsLibrary } from './codiconsLibrary.js';
8 >
9 >
10 > /**
11 > * Only to be used by the iconRegistry.
12 > */
13 > export function getAllCodicons(): ThemeIcon[] {
14 return Object.values(Codicon);
15 }
17 > /**
18 > * Derived icons, that could become separate icons.
19 > * These mappings should be moved into the mapping file in the vscode-codicons repo at some point.
20 > */
21 > export const codiconsDerived = {
22 > dialogError: register('dialog-error', 'error'),
23 > dialogWarning: register('dialog-warning', 'warning'),
24 > dialogInfo: register('dialog-info', 'info'),
25 > dialogClose: register('dialog-close', 'close'),
26 > treeItemExpanded: register('tree-item-expanded', 'chevron-down'), // collapsed is done with rotation
27 > treeFilterOnTypeOn: register('tree-filter-on-type-on', 'list-filter'),
28 > treeFilterOnTypeOff: register('tree-filter-on-type-off', 'list-selection'),
29 > treeFilterClear: register('tree-filter-clear', 'close'),
30 > treeItemLoading: register('tree-item-loading', 'loading'),
31 > menuSelection: register('menu-selection', 'check'),
32 > menuSubmenu: register('menu-submenu', 'chevron-right'),
33 > menuBarMore: register('menubar-more', 'more'),
34 > scrollbarButtonLeft: register('scrollbar-button-left', 'triangle-left'),
35 > scrollbarButtonRight: register('scrollbar-button-right', 'triangle-right'),
36 > scrollbarButtonUp: register('scrollbar-button-up', 'triangle-up'),
37 > scrollbarButtonDown: register('scrollbar-button-down', 'triangle-down'),
38 > toolBarMore: register('toolbar-more', 'more'),
39 > quickInputBack: register('quick-input-back', 'arrow-left'),
40 > dropDownButton: register('drop-down-button', 0xeab4),
41 > symbolCustomColor: register('symbol-customcolor', 0xeb5c),
42 > exportIcon: register('export', 0xebac),
43 > workspaceUnspecified: register('workspace-unspecified', 0xebc3),
44 > newLine: register('newline', 0xebea),
45 > thumbsDownFilled: register('thumbsdown-filled', 0xec13),
46 > thumbsUpFilled: register('thumbsup-filled', 0xec14),
47 > gitFetch: register('git-fetch', 0xec1d),
48 > lightbulbSparkleAutofix: register('lightbulb-sparkle-autofix', 0xec1f),
49 > debugBreakpointPending: register('debug-breakpoint-pending', 0xebd9),
50 > chatImport: register('chat-import', 0xec86),
51 > chatExport: register('chat-export', 0xec87),
52 >
53 > } as const;
54 >
55 > /**
56 > * The Codicon library is a set of default icons that are built-in in VS Code.
57 > *
58 > * In the product (outside of base) Codicons should only be used as defaults. In order to have all icons in VS Code
59 > * themeable, component should define new, UI component specific icons using `iconRegistry.registerIcon`.
60 > * In that call a Codicon can be named as default.
61 > */
62 > export const Codicon = {
63 > ...codiconsLibrary,
64 > ...codiconsDerived
65 >
66 > } as const;
src/vs/base/common/iterator.ts 63 covered LOC · 22 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- iterator.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { isIterable } from './types.js';
7 >
8 > export namespace Iterable {
9 >
10 > export function is<T = unknown>(thing: unknown): thing is Iterable<T> {
11 return !!thing && typeof thing === 'object' && typeof (thing as Iterable<T>)[Symbol.iterator] === 'function';
12 }
14 > const _empty: Iterable<never> = Object.freeze([]);
15 > export function empty<T = never>(): readonly never[] {
16 return _empty as readonly never[];
17 }
19 > export function* single<T>(element: T): Iterable<T> {
20 yield element;
21 }
23 > export function wrap<T>(iterableOrElement: Iterable<T> | T): Iterable<T> {
24 if (is(iterableOrElement)) {
25 return iterableOrElement;
28 }
29 }
31 > export function from<T>(iterable: Iterable<T> | undefined | null): Iterable<T> {
32 return iterable ?? (_empty as Iterable<T>);
33 }
35 > export function* reverse<T>(array: ReadonlyArray<T>): Iterable<T> {
36 for (let i = array.length - 1; i >= 0; i--) {
37 yield array[i];
38 }
39 }
41 > export function isEmpty<T>(iterable: Iterable<T> | undefined | null): boolean {
42 return !iterable || iterable[Symbol.iterator]().next().done === true;
43 }
45 > export function first<T>(iterable: Iterable<T>): T | undefined {
46 return iterable[Symbol.iterator]().next().value;
47 }
49 > export function some<T>(iterable: Iterable<T>, predicate: (t: T, i: number) => unknown): boolean {
50 let i = 0;
51 for (const element of iterable) {
56 return false;
57 }
59 > export function every<T>(iterable: Iterable<T>, predicate: (t: T, i: number) => unknown): boolean {
60 let i = 0;
61 for (const element of iterable) {
66 return true;
67 }
69 > export function find<T, R extends T>(iterable: Iterable<T>, predicate: (t: T) => t is R): R | undefined;
70 > export function find<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): T | undefined;
71 > export function find<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): T | undefined {
72 for (const element of iterable) {
73 if (predicate(element)) {
78 return undefined;
79 }
81 > export function filter<T, R extends T>(iterable: Iterable<T>, predicate: (t: T) => t is R): Iterable<R>;
82 > export function filter<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): Iterable<T>;
83 > export function* filter<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): Iterable<T> {
84 for (const element of iterable) {
85 if (predicate(element)) {
88 }
89 }
91 > export function* map<T, R>(iterable: Iterable<T>, fn: (t: T, index: number) => R): Iterable<R> {
92 let index = 0;
93 for (const element of iterable) {
95 }
96 }
98 > export function* flatMap<T, R>(iterable: Iterable<T>, fn: (t: T, index: number) => Iterable<R>): Iterable<R> {
99 let index = 0;
100 for (const element of iterable) {
102 }
103 }
104 > iterator.ts
105 > export function* concat<T>(...iterables: (Iterable<T> | T)[]): Iterable<T> {
106 for (const item of iterables) {
107 if (isIterable(item)) {
112 }
113 }
114 > iterator.ts
115 > export function reduce<T, R>(iterable: Iterable<T>, reducer: (previousValue: R, currentValue: T) => R, initialValue: R): R {
116 let value = initialValue;
117 for (const element of iterable) {
120 return value;
121 }
122 > iterator.ts
123 > export function length<T>(iterable: Iterable<T>): number {
124 let count = 0;
125 for (const _ of iterable) {
128 return count;
129 }
130 > iterator.ts
131 > /**
132 > * Returns an iterable slice of the array, with the same semantics as `array.slice()`.
133 > */
134 > export function* slice<T>(arr: ReadonlyArray<T>, from: number, to = arr.length): Iterable<T> {
135 if (from < -arr.length) {
136 from = 0;
150 }
151 }
152 > iterator.ts
153 > /**
154 > * Consumes `atMost` elements from iterable and returns the consumed elements,
155 > * and an iterable for the rest of the elements.
156 > */
157 > export function consume<T>(iterable: Iterable<T>, atMost: number = Number.POSITIVE_INFINITY): [T[], Iterable<T>] {
158 const consumed: T[] = [];
159
176 return [consumed, { [Symbol.iterator]() { return iterator; } }];
177 }
178 > iterator.ts
179 > export async function asyncToArray<T>(iterable: AsyncIterable<T>): Promise<T[]> {
180 const result: T[] = [];
181 for await (const item of iterable) {
184 return result;
185 }
186 > iterator.ts
187 > export async function asyncToArrayFlat<T>(iterable: AsyncIterable<T[]>): Promise<T[]> {
188 let result: T[] = [];
189 for await (const item of iterable) {
src/vs/base/common/observableInternal/observables/observableValue.ts 58 covered LOC · 12 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- observableValue.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ISettableObservable, ITransaction } from '../base.js';
7 > import { TransactionImpl } from '../transaction.js';
8 > import { BaseObservable } from './baseObservable.js';
9 > import { EqualityComparer, IDisposable, strictEquals } from '../commonFacade/deps.js';
10 > import { DebugNameData } from '../debugName.js';
11 > import { getLogger } from '../logging/logging.js';
12 > import { DebugLocation } from '../debugLocation.js';
13 >
14 > /**
15 > * Creates an observable value.
16 > * Observers get informed when the value changes.
17 > * @template TChange An arbitrary type to describe how or why the value changed. Defaults to `void`.
18 > * Observers will receive every single change value.
19 > */
20 >
21 > export function observableValue<T, TChange = void>(name: string, initialValue: T): ISettableObservable<T, TChange>;
22 > export function observableValue<T, TChange = void>(owner: object, initialValue: T): ISettableObservable<T, TChange>;
23 > export function observableValue<T, TChange = void>(nameOrOwner: string | object, initialValue: T, debugLocation = DebugLocation.ofCaller()): ISettableObservable<T, TChange> {
24 let debugNameData: DebugNameData;
25 if (typeof nameOrOwner === 'string') {
30 return new ObservableValue(debugNameData, initialValue, strictEquals, debugLocation);
31 }
33 > export class ObservableValue<T, TChange = void>
34 > extends BaseObservable<T, TChange>
35 > implements ISettableObservable<T, TChange> {
36 > protected _value: T;
37 >
38 > get debugName() {
39 > return this._debugNameData.getDebugName(this) ?? 'ObservableValue';
40 > }
41 >
42 > constructor(
43 private readonly _debugNameData: DebugNameData,
44 initialValue: T,
51 getLogger()?.handleObservableUpdated(this, { hadValue: false, newValue: initialValue, change: undefined, didChange: true, oldValue: undefined });
52 }
53 > public override get(): T { observableValue.ts
54 return this._value;
55 }
57 > public set(value: T, tx: ITransaction | undefined, change: TChange): void {
58 if (change === undefined && this._equalityComparator(this._value, value)) {
59 return;
79 }
80 }
82 > override toString(): string {
83 return `${this.debugName}: ${this._value}`;
84 }
86 > protected _setValue(newValue: T): void {
87 this._value = newValue;
88 }
90 > public debugGetState() {
91 return {
92 value: this._value,
93 };
94 }
96 > public debugSetValue(value: unknown) {
97 this._value = value as T;
98 }
100 > /**
101 > * A disposable observable. When disposed, its value is also disposed.
102 > * When a new value is set, the previous value is disposed.
103 > */
104 >
105 > export function disposableObservableValue<T extends IDisposable | undefined, TChange = void>(nameOrOwner: string | object, initialValue: T, debugLocation = DebugLocation.ofCaller()): ISettableObservable<T, TChange> & IDisposable {
106 let debugNameData: DebugNameData;
107 if (typeof nameOrOwner === 'string') {
112 return new DisposableObservableValue(debugNameData, initialValue, strictEquals, debugLocation);
113 }
115 > export class DisposableObservableValue<T extends IDisposable | undefined, TChange = void> extends ObservableValue<T, TChange> implements IDisposable {
116 > protected override _setValue(newValue: T): void {
117 if (this._value === newValue) {
118 return;
src/vs/base/common/observableInternal/index.ts 57 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- index.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // This is a facade for the observable implementation. Only import from here!
7 >
8 > export { observableValueOpts } from './observables/observableValueOpts.js';
9 > export { autorun, autorunDelta, autorunHandleChanges, autorunOpts, autorunWithStore, autorunWithStoreHandleChanges, autorunIterableDelta, autorunPerKeyedItem, autorunSelfDisposable, registerAutorunSelfDisposable } from './reactions/autorun.js';
10 > export { type IObservable, type IObservableWithChange, type IObserver, type IReader, type ISettable, type IReaderWithStore, type ISettableObservable, type ITransaction } from './base.js';
11 > export { disposableObservableValue } from './observables/observableValue.js';
12 > export { derived, derivedDisposable, derivedHandleChanges, derivedOpts, derivedWithSetter, derivedWithStore } from './observables/derived.js';
13 > export { type IDerivedReader } from './observables/derivedImpl.js';
14 > export { ObservableLazy, ObservableLazyPromise, ObservablePromise, ObservableResolvedPromise, PromiseResult, } from './utils/promise.js';
15 > export { derivedWithCancellationToken, waitForState } from './utils/utilsCancellation.js';
16 > export {
17 > debouncedObservable, debouncedObservable2, derivedObservableWithCache,
18 > derivedObservableWithWritableCache, keepObserved, mapObservableArrayCached, observableFromPromise,
19 > recomputeInitiallyAndOnChange,
20 > signalFromObservable, throttledObservable, wasEventTriggeredRecently,
21 > isObservable,
22 > } from './utils/utils.js';
23 > export { type DebugOwner } from './debugName.js';
24 > export { type IChangeContext, type IChangeTracker, recordChanges, recordChangesLazy } from './changeTracker.js';
25 > export { constObservable } from './observables/constObservable.js';
26 > export { type IObservableSignal, observableSignal } from './observables/observableSignal.js';
27 > export { observableFromEventOpts } from './observables/observableFromEvent.js';
28 > export { observableSignalFromEvent } from './observables/observableSignalFromEvent.js';
29 > export { asyncTransaction, globalTransaction, subtransaction, transaction, TransactionImpl } from './transaction.js';
30 > export { observableFromValueWithChangeEvent, ValueWithChangeEventFromObservable } from './utils/valueWithChangeEvent.js';
31 > export { runOnChange, runOnChangeWithCancellationToken, runOnChangeWithStore, type RemoveUndefined } from './utils/runOnChange.js';
32 > export { derivedConstOnceDefined, latestChangedValue } from './experimental/utils.js';
33 > export { observableFromEvent } from './observables/observableFromEvent.js';
34 > export { observableValue } from './observables/observableValue.js';
35 >
36 > export { ObservableSet } from './set.js';
37 > export { ObservableMap } from './map.js';
38 > export { DebugLocation } from './debugLocation.js';
39 >
40 > import { addLogger, setLogObservableFn } from './logging/logging.js';
41 > import { ConsoleObservableLogger, logObservableToConsole } from './logging/consoleObservableLogger.js';
42 > import { DevToolsLogger } from './logging/debugger/devToolsLogger.js';
43 > import { env } from '../process.js';
44 > import { _setDebugGetObservableGraph } from './observables/baseObservable.js';
45 > import { debugGetObservableGraph } from './logging/debugGetDependencyGraph.js';
46 >
47 > _setDebugGetObservableGraph(debugGetObservableGraph);
48 > setLogObservableFn(logObservableToConsole);
49 >
50 > // Remove "//" in the next line to enable logging
51 > const enableLogging = false
52 > // || Boolean("true") // done "weirdly" so that a lint warning prevents you from pushing this
53 > ;
54 >
55 > if (enableLogging) {
56 addLogger(new ConsoleObservableLogger());
57 }
58 > index.ts
59 > if (env && env['VSCODE_DEV_DEBUG_OBSERVABLES']) {
60 // To debug observables you also need the extension "ms-vscode.debug-value-editor"
61 addLogger(DevToolsLogger.getInstance());
src/vs/base/common/observableInternal/observables/derived.ts 57 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- derived.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable, IReader, ITransaction, ISettableObservable, IObservableWithChange } from '../base.js';
7 > import { IChangeTracker } from '../changeTracker.js';
8 > import { DisposableStore, EqualityComparer, IDisposable, strictEquals } from '../commonFacade/deps.js';
9 > import { DebugLocation } from '../debugLocation.js';
10 > import { DebugOwner, DebugNameData, IDebugNameData } from '../debugName.js';
11 > import { _setDerivedOpts } from './baseObservable.js';
12 > import { IDerivedReader, Derived, DerivedWithSetter } from './derivedImpl.js';
13 >
14 > /**
15 > * Creates an observable that is derived from other observables.
16 > * The value is only recomputed when absolutely needed.
17 > *
18 > * {@link computeFn} should start with a JS Doc using `@description` to name the derived.
19 > */
20 > export function derived<T, TChange = void>(computeFn: (reader: IDerivedReader<TChange>, debugLocation?: DebugLocation) => T): IObservableWithChange<T, TChange>;
21 > export function derived<T, TChange = void>(owner: DebugOwner, computeFn: (reader: IDerivedReader<TChange>) => T, debugLocation?: DebugLocation): IObservableWithChange<T, TChange>;
22 > export function derived<T, TChange = void>(
23 computeFnOrOwner: ((reader: IDerivedReader<TChange>) => T) | DebugOwner,
24 computeFn?: ((reader: IDerivedReader<TChange>) => T) | undefined,
46 );
47 }
48 > derived.ts
49 > export function derivedWithSetter<T>(owner: DebugOwner | undefined, computeFn: (reader: IReader) => T, setter: (value: T, transaction: ITransaction | undefined) => void, debugLocation = DebugLocation.ofCaller()): ISettableObservable<T> {
50 return new DerivedWithSetter(
51 new DebugNameData(owner, undefined, computeFn),
58 );
59 }
60 > derived.ts
61 > export function derivedOpts<T>(
62 options: IDebugNameData & {
63 equalsFn?: EqualityComparer<T>;
76 );
77 }
78 > _setDerivedOpts(derivedOpts); derived.ts
79 >
80 > /**
81 > * Represents an observable that is derived from other observables.
82 > * The value is only recomputed when absolutely needed.
83 > *
84 > * {@link computeFn} should start with a JS Doc using `@description` to name the derived.
85 > *
86 > * Use `createEmptyChangeSummary` to create a "change summary" that can collect the changes.
87 > * Use `handleChange` to add a reported change to the change summary.
88 > * The compute function is given the last change summary.
89 > * The change summary is discarded after the compute function was called.
90 > *
91 > * @see derived
92 > */
93 > export function derivedHandleChanges<T, TDelta, TChangeSummary>(
94 options: IDebugNameData & {
95 changeTracker: IChangeTracker<TChangeSummary>;
108 );
109 }
110 > derived.ts
111 > /**
112 > * @deprecated Use `derived(reader => { reader.store.add(...) })` instead!
113 > */
114 > export function derivedWithStore<T>(computeFn: (reader: IReader, store: DisposableStore) => T): IObservable<T>;
115 >
116 > /**
117 > * @deprecated Use `derived(reader => { reader.store.add(...) })` instead!
118 > */
119 > export function derivedWithStore<T>(owner: DebugOwner, computeFn: (reader: IReader, store: DisposableStore) => T): IObservable<T>;
120 > export function derivedWithStore<T>(computeFnOrOwner: ((reader: IReader, store: DisposableStore) => T) | DebugOwner, computeFnOrUndefined?: ((reader: IReader, store: DisposableStore) => T), debugLocation = DebugLocation.ofCaller()): IObservable<T> {
121 let computeFn: (reader: IReader, store: DisposableStore) => T;
122 let owner: DebugOwner;
151 );
152 }
153 > derived.ts
154 > export function derivedDisposable<T extends IDisposable | undefined>(computeFn: (reader: IReader) => T): IObservable<T>;
155 > export function derivedDisposable<T extends IDisposable | undefined>(owner: DebugOwner, computeFn: (reader: IReader) => T): IObservable<T>;
156 > export function derivedDisposable<T extends IDisposable | undefined>(computeFnOrOwner: ((reader: IReader) => T) | DebugOwner, computeFnOrUndefined?: ((reader: IReader) => T), debugLocation = DebugLocation.ofCaller()): IObservable<T> {
157 let computeFn: (reader: IReader) => T;
158 let owner: DebugOwner;
src/vs/base/test/common/utils.ts 56 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- utils.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { DisposableStore, DisposableTracker, IDisposable, setDisposableTracker } from '../../common/lifecycle.js';
7 > import { join } from '../../common/path.js';
8 > import { isWindows } from '../../common/platform.js';
9 > import { URI } from '../../common/uri.js';
10 >
11 > export type ValueCallback<T = any> = (value: T | Promise<T>) => void;
12 >
13 > export function toResource(this: any, path: string): URI {
14 if (isWindows) {
15 return URI.file(join('C:\\', btoa(this.test.fullTitle()), path));
18 return URI.file(join('/', btoa(this.test.fullTitle()), path));
19 }
20 > utils.ts
21 > export function suiteRepeat(n: number, description: string, callback: (this: any) => void): void {
22 for (let i = 0; i < n; i++) {
23 suite(`${description} (iteration ${i})`, callback);
24 }
25 }
26 > utils.ts
27 > export function testRepeat(n: number, description: string, callback: (this: any) => any): void {
28 for (let i = 0; i < n; i++) {
29 test(`${description} (iteration ${i})`, callback);
30 }
31 }
32 > utils.ts
33 export async function assertThrowsAsync(block: () => any, message: string | Error = 'Missing expected exception'): Promise<void> {
34 try {
41 throw err;
42 }
43 > utils.ts
44 > /**
45 > * Use this function to ensure that all disposables are cleaned up at the end of each test in the current suite.
46 > *
47 > * Use `markAsSingleton` if disposable singletons are created lazily that are allowed to outlive the test.
48 > * Make sure that the singleton properly registers all child disposables so that they are excluded too.
49 > *
50 > * @returns A {@link DisposableStore} that can optionally be used to track disposables in the test.
51 > * This will be automatically disposed on test teardown.
52 > */
53 > export function ensureNoDisposablesAreLeakedInTestSuite(): Pick<DisposableStore, 'add'> {
54 > let tracker: DisposableTracker | undefined;
55 > let store: DisposableStore;
56 > setup(() => {
57 > store = new DisposableStore(); utils.ts
58 > tracker = new DisposableTracker();
59 > setDisposableTracker(tracker);
60 > }); utils.ts
61 >
62 > teardown(function (this: import('mocha').Context) {
63 > store.dispose(); utils.ts
64 > setDisposableTracker(null);
65 > if (this.currentTest?.state !== 'failed') {
66 > const result = tracker!.computeLeakingDisposables();
67 > if (result) {
68 console.error(result.details);
69 throw new Error(`There are ${result.leaks.length} undisposed disposables!${result.details}`);
70 }
71 > } utils.ts
72 > }); utils.ts
73 >
74 > // Wrap store as the suite function is called before it's initialized
75 > const testContext = {
76 > add<T extends IDisposable>(o: T): T {
77 return store.add(o);
78 }
79 > }; utils.ts
80 > return testContext;
81 > }
82 >
83 > export function throwIfDisposablesAreLeaked(body: () => void, logToConsole = true): void {
84 const tracker = new DisposableTracker();
85 setDisposableTracker(tracker);
88 computeLeakingDisposables(tracker, logToConsole);
89 }
90 > utils.ts
91 export async function throwIfDisposablesAreLeakedAsync(body: () => Promise<void>): Promise<void> {
92 const tracker = new DisposableTracker();
96 computeLeakingDisposables(tracker);
97 }
98 > utils.ts
99 function computeLeakingDisposables(tracker: DisposableTracker, logToConsole = true) {
100 const result = tracker.computeLeakingDisposables();
src/vs/base/common/observableInternal/logging/debugger/rpc.ts 53 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- rpc.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export type ChannelFactory = (handler: IChannelHandler) => IChannel;
7 >
8 > export interface IChannel {
9 > sendNotification(data: unknown): void;
10 > sendRequest(data: unknown): Promise<RpcRequestResult>;
11 > }
12 >
13 > export interface IChannelHandler {
14 > handleNotification(notificationData: unknown): void;
15 > handleRequest(requestData: unknown): Promise<RpcRequestResult> | RpcRequestResult;
16 > }
17 >
18 > export type RpcRequestResult = { type: 'result'; value: unknown } | { type: 'error'; value: unknown };
19 >
20 > export type API = {
21 > host: Side;
22 > client: Side;
23 > };
24 >
25 > export type Side = {
26 > notifications: Record<string, (...args: any[]) => void>;
27 > requests: Record<string, (...args: any[]) => Promise<unknown> | unknown>;
28 > };
29 >
30 > type MakeAsyncIfNot<TFn> = TFn extends (...args: infer TArgs) => infer TResult ? TResult extends Promise<unknown> ? TFn : (...args: TArgs) => Promise<TResult> : never;
31 >
32 > export type MakeSideAsync<T extends Side> = {
33 > notifications: T['notifications'];
34 > requests: { [K in keyof T['requests']]: MakeAsyncIfNot<T['requests'][K]> };
35 > };
36 >
37 > export class SimpleTypedRpcConnection<T extends Side> {
38 > public static createHost<T extends API>(channelFactory: ChannelFactory, getHandler: () => T['host']): SimpleTypedRpcConnection<MakeSideAsync<T['client']>> {
39 > return new SimpleTypedRpcConnection(channelFactory, getHandler);
40 > }
41 >
42 > public static createClient<T extends API>(channelFactory: ChannelFactory, getHandler: () => T['client']): SimpleTypedRpcConnection<MakeSideAsync<T['host']>> {
43 return new SimpleTypedRpcConnection(channelFactory, getHandler);
44 }
45 > rpc.ts
46 > public readonly api: T;
47 > private readonly _channel: IChannel;
48 >
49 > private constructor(
50 private readonly _channelFactory: ChannelFactory,
51 private readonly _getHandler: () => Side,
95 this.api = { notifications: notifications, requests: requests } as any;
96 }
97 > } rpc.ts
98 >
99 > type OutgoingMessage = [
100 > method: string,
101 > args: unknown[],
102 > ];
src/vs/base/common/process.ts 53 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- process.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { INodeProcess, isMacintosh, isWindows } from './platform.js';
7 >
8 > let safeProcess: Omit<INodeProcess, 'arch'> & { arch: string | undefined };
9 > declare const process: INodeProcess;
10 >
11 > // Native sandbox environment
12 > const vscodeGlobal = (globalThis as { vscode?: { process?: INodeProcess } }).vscode;
13 > if (typeof vscodeGlobal !== 'undefined' && typeof vscodeGlobal.process !== 'undefined') {
14 const sandboxProcess: INodeProcess = vscodeGlobal.process;
15 safeProcess = {
20 };
21 }
22 > process.ts
23 > // Native node.js environment
24 > else if (typeof process !== 'undefined' && typeof process?.versions?.node === 'string') {
25 > safeProcess = {
26 > get platform() { return process.platform; },
27 > get arch() { return process.arch; },
28 > get env() { return process.env; },
29 > cwd() { return process.env['VSCODE_CWD'] || process.cwd(); }
30 > };
31 }
32
44 };
45 }
46 > process.ts
47 > /**
48 > * Provides safe access to the `cwd` property in node.js, sandboxed or web
49 > * environments.
50 > *
51 > * Note: in web, this property is hardcoded to be `/`.
52 > *
53 > * @skipMangle
54 > */
55 > export const cwd = safeProcess.cwd;
56 >
57 > /**
58 > * Provides safe access to the `env` property in node.js, sandboxed or web
59 > * environments.
60 > *
61 > * Note: in web, this property is hardcoded to be `{}`.
62 > */
63 > export const env = safeProcess.env;
64 >
65 > /**
66 > * Provides safe access to the `platform` property in node.js, sandboxed or web
67 > * environments.
68 > */
69 > export const platform = safeProcess.platform;
70 >
71 > /**
72 > * Provides safe access to the `arch` method in node.js, sandboxed or web
73 > * environments.
74 > * Note: `arch` is `undefined` in web
75 > */
76 > export const arch = safeProcess.arch;
src/vs/base/common/observableInternal/debugName.ts 52 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- debugName.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export interface IDebugNameData {
7 > /**
8 > * The owner object of an observable.
9 > * Used for debugging only, such as computing a name for the observable by iterating over the fields of the owner.
10 > */
11 > readonly owner?: DebugOwner | undefined;
12 >
13 > /**
14 > * A string or function that returns a string that represents the name of the observable.
15 > * Used for debugging only.
16 > */
17 > readonly debugName?: DebugNameSource | undefined;
18 >
19 > /**
20 > * A function that points to the defining function of the object.
21 > * Used for debugging only.
22 > */
23 > readonly debugReferenceFn?: Function | undefined;
24 > }
25 >
26 > export class DebugNameData {
27 > constructor(
28 public readonly owner: DebugOwner | undefined,
29 public readonly debugNameSource: DebugNameSource | undefined,
30 public readonly referenceFn: Function | undefined,
31 ) { }
33 > public getDebugName(target: object): string | undefined {
34 return getDebugName(target, this);
35 }
36 > } debugName.ts
37 >
38 > /**
39 > * The owning object of an observable.
40 > * Is only used for debugging purposes, such as computing a name for the observable by iterating over the fields of the owner.
41 > */
42 > export type DebugOwner = object | undefined;
43 > export type DebugNameSource = string | (() => string | undefined);
44 >
45 > const countPerName = new Map<string, number>();
46 > const cachedDebugName = new WeakMap<object, string>();
47 >
48 > export function getDebugName(target: object, data: DebugNameData): string | undefined {
49 const cached = cachedDebugName.get(target);
50 if (cached) {
63 return undefined;
64 }
66 function computeDebugName(self: object, data: DebugNameData): string | undefined {
67 const cached = cachedDebugName.get(self);
101 return undefined;
102 }
103 > debugName.ts
104 function findKey(obj: object, value: object): string | undefined {
105 for (const key in obj) {
110 return undefined;
111 }
112 > debugName.ts
113 > const countPerClassName = new Map<string, number>();
114 > const ownerId = new WeakMap<object, string>();
115 >
116 function formatOwner(owner: object): string {
117 const id = ownerId.get(owner);
127 return result;
128 }
129 > debugName.ts
130 > export function getClassName(obj: object): string | undefined {
131 const ctor = obj.constructor;
132 if (ctor) {
138 return undefined;
139 }
140 > debugName.ts
141 > export function getFunctionName(fn: Function): string | undefined {
142 const fnSrc = fn.toString();
143 // Pattern: /** @description ... */
src/vs/base/common/observableInternal/logging/consoleObservableLogger.ts 52 covered LOC · 20 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- consoleObservableLogger.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable } from '../base.js';
7 > import { TransactionImpl } from '../transaction.js';
8 > import { IObservableLogger, IChangeInformation, addLogger } from './logging.js';
9 > import { FromEventObservable } from '../observables/observableFromEvent.js';
10 > import { getClassName } from '../debugName.js';
11 > import { Derived } from '../observables/derivedImpl.js';
12 > import { AutorunObserver } from '../reactions/autorunImpl.js';
13 >
14 > let consoleObservableLogger: ConsoleObservableLogger | undefined;
15 >
16 > export function logObservableToConsole(obs: IObservable<any>): void {
17 if (!consoleObservableLogger) {
18 consoleObservableLogger = new ConsoleObservableLogger();
21 consoleObservableLogger.addFilteredObj(obs);
22 }
24 > export class ConsoleObservableLogger implements IObservableLogger {
25 private indentation = 0;
26
118
119 private readonly changedObservablesSets = new WeakMap<object, Set<IObservable<any>>>();
121 > formatChanges(changes: Set<IObservable<any>>): ConsoleText | undefined {
122 if (changes.size === 0) {
123 return undefined;
130 );
131 }
133 > handleDerivedDependencyChanged(derived: Derived<any>, observable: IObservable<any>, change: unknown): void {
134 if (!this._isIncluded(derived)) { return; }
135
136 this.changedObservablesSets.get(derived)?.add(observable);
137 }
139 > _handleDerivedRecomputed(derived: Derived<unknown>, info: IChangeInformation): void {
140 if (!this._isIncluded(derived)) { return; }
141
151 changedObservables.clear();
152 }
154 > handleDerivedCleared(derived: Derived<unknown>): void {
155 if (!this._isIncluded(derived)) { return; }
156
160 ]));
161 }
163 > handleFromEventObservableTriggered(observable: FromEventObservable<any, any>, info: IChangeInformation): void {
164 if (!this._isIncluded(observable)) { return; }
165
171 ]));
172 }
174 > handleAutorunCreated(autorun: AutorunObserver): void {
175 if (!this._isIncluded(autorun)) { return; }
176
177 this.changedObservablesSets.set(autorun, new Set());
178 }
180 > handleAutorunDisposed(autorun: AutorunObserver): void {
181 }
183 > handleAutorunDependencyChanged(autorun: AutorunObserver, observable: IObservable<any>, change: unknown): void {
184 if (!this._isIncluded(autorun)) { return; }
185
186 this.changedObservablesSets.get(autorun)!.add(observable);
187 }
189 > handleAutorunStarted(autorun: AutorunObserver): void {
190 const changedObservables = this.changedObservablesSets.get(autorun);
191 if (!changedObservables) { return; }
202 this.indentation++;
203 }
205 > handleAutorunFinished(autorun: AutorunObserver): void {
206 this.indentation--;
207 }
209 > handleBeginTransaction(transaction: TransactionImpl): void {
210 let transactionName = transaction.getDebugName();
211 if (transactionName === undefined) {
221 this.indentation++;
222 }
224 > handleEndTransaction(): void {
225 this.indentation--;
226 }
228 > type ConsoleText = (ConsoleText | undefined)[] |
229 > { text: string; style: string; data?: unknown[] } |
230 > { data: unknown[] };
231 function consoleTextToArgs(text: ConsoleText): unknown[] {
232 const styles = new Array<any>();
294 };
295 }
297 > export function formatValue(value: unknown, availableLen: number): string {
298 switch (typeof value) {
299 case 'number':
325 }
326 }
328 function formatArray(value: unknown[], availableLen: number): string {
329 let result = '[ ';
343 return result;
344 }
346 function formatObject(value: object, availableLen: number): string {
347 if (typeof value.toString === 'function' && value.toString !== Object.prototype.toString) {
371 return result;
372 }
374 function repeat(str: string, count: number): string {
375 let result = '';
379 return result;
380 }
382 function padStr(str: string, length: number): string {
383 while (str.length < length) {
src/vs/platform/registry/common/platform.ts 52 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- platform.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as Assert from '../../../base/common/assert.js';
7 > import * as Types from '../../../base/common/types.js';
8 >
9 > export interface IRegistry {
10 >
11 > /**
12 > * Adds the extension functions and properties defined by data to the
13 > * platform. The provided id must be unique.
14 > * @param id a unique identifier
15 > * @param data a contribution
16 > */
17 > add(id: string, data: any): void;
18 >
19 > /**
20 > * Returns true iff there is an extension with the provided id.
21 > * @param id an extension identifier
22 > */
23 > knows(id: string): boolean;
24 >
25 > /**
26 > * Returns the extension functions and properties defined by the specified key or null.
27 > * @param id an extension identifier
28 > */
29 > as<T>(id: string): T;
30 > }
31 >
32 > class RegistryImpl implements IRegistry {
33 >
34 > private readonly data = new Map<string, any>();
35 >
36 > public add(id: string, data: any): void {
37 > Assert.ok(Types.isString(id)); platform.ts
38 > Assert.ok(Types.isObject(data));
39 > Assert.ok(!this.data.has(id), 'There is already an extension with this id');
40 >
41 > this.data.set(id, data);
42 > }
44 > public knows(id: string): boolean {
45 return this.data.has(id);
46 }
48 > public as(id: string): any {
49 return this.data.get(id) || null;
50 }
52 > public dispose() {
53 this.data.forEach((value) => {
54 if (Types.isFunction(value.dispose)) {
58 this.data.clear();
59 }
61 > }
62 >
63 > export const Registry: IRegistry = new RegistryImpl();
src/vs/base/common/observableInternal/observables/observableFromEvent.ts 51 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- observableFromEvent.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable, ITransaction } from '../base.js';
7 > import { subtransaction } from '../transaction.js';
8 > import { EqualityComparer, Event, IDisposable, strictEquals } from '../commonFacade/deps.js';
9 > import { DebugOwner, DebugNameData, IDebugNameData } from '../debugName.js';
10 > import { getLogger } from '../logging/logging.js';
11 > import { BaseObservable } from './baseObservable.js';
12 > import { DebugLocation } from '../debugLocation.js';
13 >
14 >
15 > export function observableFromEvent<T, TArgs = unknown>(
16 > owner: DebugOwner,
17 > event: Event<TArgs>,
18 > getValue: (args: TArgs | undefined) => T,
19 > debugLocation?: DebugLocation,
20 > ): IObservable<T>;
21 > export function observableFromEvent<T, TArgs = unknown>(
22 > event: Event<TArgs>,
23 > getValue: (args: TArgs | undefined) => T,
24 > ): IObservable<T>;
25 > export function observableFromEvent(...args:
26 [owner: DebugOwner, event: Event<any>, getValue: (args: any | undefined) => any, debugLocation?: DebugLocation] |
27 [event: Event<any>, getValue: (args: any | undefined) => any]
45 );
46 }
48 > export function observableFromEventOpts<T, TArgs = unknown>(
49 options: IDebugNameData & {
50 equalsFn?: EqualityComparer<T>;
64 );
65 }
67 > export class FromEventObservable<TArgs, T> extends BaseObservable<T> {
68 > public static globalTransaction: ITransaction | undefined;
69 >
70 > private _value: T | undefined;
71 > private _hasValue = false;
72 > private _subscription: IDisposable | undefined;
73 >
74 > constructor(
75 private readonly _debugNameData: DebugNameData,
76 private readonly event: Event<TArgs>,
131 }
132 };
134 > protected override onLastObserverRemoved(): void {
135 this._subscription!.dispose();
136 this._subscription = undefined;
138 this._value = undefined;
139 }
141 > public get(): T {
142 if (this._subscription) {
143 if (!this._hasValue) {
151 }
152 }
154 > public debugSetValue(value: unknown): void {
155 // eslint-disable-next-line local/code-no-any-casts
156 this._value = value as any;
157 }
159 > public debugGetState() {
160 return { value: this._value, hasValue: this._hasValue };
161 }
163 >
164 > export namespace observableFromEvent {
165 > export const Observer = FromEventObservable;
166 >
167 > export function batchEventsGlobally(tx: ITransaction, fn: () => void): void {
168 let didSet = false;
169 if (FromEventObservable.globalTransaction === undefined) {
src/vs/platform/agentHost/common/agentHostSessionType.ts 51 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- agentHostSessionType.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { type AgentProvider } from './agentService.js';
7 >
8 > const REMOTE_AGENT_HOST_SESSION_TYPE_PREFIX = 'remote-';
9 >
10 > /**
11 > * Builds the unique per-connection identifier for a remote agent host.
12 > *
13 > * This string is used as the resource URI scheme registered via
14 > * `registerChatSessionContentProvider` and as the language model vendor /
15 > * `targetChatSessionType` published by `AgentHostLanguageModelProvider`.
16 > */
17 > export function remoteAgentHostSessionTypeId(connectionAuthority: string, agentProvider: AgentProvider): string {
18 return `${remoteAgentHostSessionTypeAuthorityPrefix(connectionAuthority)}${agentProvider}`;
19 }
21 > /**
22 > * Builds the authority-specific prefix for remote agent host session types.
23 > */
24 > export function remoteAgentHostSessionTypeAuthorityPrefix(connectionAuthority: string): string {
25 return `${REMOTE_AGENT_HOST_SESSION_TYPE_PREFIX}${connectionAuthority}-`;
26 }
28 > /**
29 > * Returns whether the given session type uses the remote agent host scheme.
30 > */
31 > export function isRemoteAgentHostSessionType(sessionType: string): boolean {
32 return sessionType.startsWith(REMOTE_AGENT_HOST_SESSION_TYPE_PREFIX);
33 }
35 > /**
36 > * Finds the best matching remote agent host authority from a known candidate set.
37 > *
38 > * Remote session types are formatted as `remote-{authority}-{provider}` and
39 > * authorities may contain `-`, so callers should match against the full set of
40 > * known authorities instead of splitting the session type.
41 > */
42 > export function findRemoteAgentHostSessionTypeAuthority(sessionType: string, connectionAuthorities: Iterable<string>): string | undefined {
43 if (!isRemoteAgentHostSessionType(sessionType)) {
44 return undefined;
53 return bestMatch;
54 }
56 function isRemoteAgentHostSessionTypeForAuthority(sessionType: string, connectionAuthority: string): boolean {
57 return !!connectionAuthority && sessionType.startsWith(remoteAgentHostSessionTypeAuthorityPrefix(connectionAuthority));
58 }
60 > /**
61 > * Extracts the harness/provider suffix from a remote agent host session type.
62 > *
63 > * Remote session types are formatted as `remote-{authority}-{provider}`. The
64 > * authority may contain `-`, but provider names do not, so the harness is the
65 > * final `-`-delimited segment. Returns `undefined` for non-remote session types.
66 > */
67 > export function parseRemoteAgentHostHarness(sessionType: string): string | undefined {
68 if (!isRemoteAgentHostSessionType(sessionType)) {
69 return undefined;
73 return harness || undefined;
74 }
76 > /**
77 > * Extracts the connection authority from a remote agent host session type when the provider is known.
78 > */
79 > export function parseRemoteAgentHostSessionTypeAuthority(sessionType: string, agentProvider: AgentProvider): string | undefined {
80 if (!isRemoteAgentHostSessionType(sessionType)) {
81 return undefined;
src/vs/base/common/assert.ts 50 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- assert.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { BugIndicatingError, onUnexpectedError } from './errors.js';
7 >
8 > /**
9 > * Throws an error with the provided message if the provided value does not evaluate to a true Javascript value.
10 > *
11 > * @deprecated Use `assert(...)` instead.
12 > * This method is usually used like this:
13 > * ```ts
14 > * import * as assert from 'vs/base/common/assert';
15 > * assert.ok(...);
16 > * ```
17 > *
18 > * However, `assert` in that example is a user chosen name.
19 > * There is no tooling for generating such an import statement.
20 > * Thus, the `assert(...)` function should be used instead.
21 > */
22 > export function ok(value?: unknown, message?: string) {
23 > if (!value) { assert.ts
24 throw new Error(message ? `Assertion failed (${message})` : 'Assertion Failed');
25 }
26 > } assert.ts
27 > assert.ts
28 > export function assertNever(value: never, message = 'Unreachable'): never {
29 throw new Error(message);
30 }
31 > assert.ts
32 > export function softAssertNever(value: never): void {
33 // no-op
34 }
35 > assert.ts
36 > /**
37 > * Asserts that a condition is `truthy`.
38 > *
39 > * @throws provided {@linkcode messageOrError} if the {@linkcode condition} is `falsy`.
40 > *
41 > * @param condition The condition to assert.
42 > * @param messageOrError An error message or error object to throw if condition is `falsy`.
43 > */
44 > export function assert(
45 condition: boolean,
46 messageOrError: string | Error = 'unexpected state',
55 }
56 }
57 > assert.ts
58 > /**
59 > * Like assert, but doesn't throw.
60 > */
61 > export function softAssert(condition: boolean, message = 'Soft Assertion Failed'): void {
62 if (!condition) {
63 onUnexpectedError(new BugIndicatingError(message));
64 }
65 }
66 > assert.ts
67 > /**
68 > * condition must be side-effect free!
69 > */
70 > export function assertFn(condition: () => boolean): void {
71 if (!condition()) {
72 // eslint-disable-next-line no-debugger
77 }
78 }
79 > assert.ts
80 > export function checkAdjacentItems<T>(items: readonly T[], predicate: (item1: T, item2: T) => boolean): boolean {
81 let i = 0;
82 while (i < items.length - 1) {
src/vs/base/common/observableInternal/observables/lazyObservableValue.ts 49 covered LOC · 11 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lazyObservableValue.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { EqualityComparer } from '../commonFacade/deps.js';
7 > import { IObserver, ISettableObservable, ITransaction } from '../base.js';
8 > import { TransactionImpl } from '../transaction.js';
9 > import { DebugNameData } from '../debugName.js';
10 > import { getLogger } from '../logging/logging.js';
11 > import { BaseObservable } from './baseObservable.js';
12 > import { DebugLocation } from '../debugLocation.js';
13 >
14 > /**
15 > * Holds off updating observers until the value is actually read.
16 > */
17 > export class LazyObservableValue<T, TChange = void>
18 > extends BaseObservable<T, TChange>
19 > implements ISettableObservable<T, TChange> {
20 > protected _value: T;
21 > private _isUpToDate = true;
22 > private readonly _deltas: TChange[] = [];
23 >
24 > get debugName() {
25 > return this._debugNameData.getDebugName(this) ?? 'LazyObservableValue';
26 > }
27 >
28 > constructor(
29 private readonly _debugNameData: DebugNameData,
30 initialValue: T,
35 this._value = initialValue;
36 }
38 > public override get(): T {
39 this._update();
40 return this._value;
41 }
43 > private _update(): void {
44 if (this._isUpToDate) {
45 return;
62 }
63 }
65 > private _updateCounter = 0;
66 >
67 > private _beginUpdate(): void {
68 this._updateCounter++;
69 if (this._updateCounter === 1) {
73 }
74 }
76 > private _endUpdate(): void {
77 this._updateCounter--;
78 if (this._updateCounter === 0) {
86 }
87 }
89 > public override addObserver(observer: IObserver): void {
90 const shouldCallBeginUpdate = !this._observers.has(observer) && this._updateCounter > 0;
91 super.addObserver(observer);
95 }
96 }
98 > public override removeObserver(observer: IObserver): void {
99 const shouldCallEndUpdate = this._observers.has(observer) && this._updateCounter > 0;
100 super.removeObserver(observer);
105 }
106 }
108 > public set(value: T, tx: ITransaction | undefined, change: TChange): void {
109 if (change === undefined && this._equalityComparator(this._value, value)) {
110 return;
src/vs/base/common/linkedList.ts 44 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- linkedList.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > class Node<E> {
7 >
8 > static readonly Undefined = new Node<unknown>(undefined);
9 >
10 > element: E;
11 > next: Node<E> | typeof Node.Undefined;
12 > prev: Node<E> | typeof Node.Undefined;
13 >
14 > constructor(element: E) {
15 > this.element = element;
16 > this.next = Node.Undefined;
17 > this.prev = Node.Undefined;
18 > }
19 > }
20 >
21 > export class LinkedList<E> {
22
23 private _first: Node<E> | typeof Node.Undefined = Node.Undefined;
24 private _last: Node<E> | typeof Node.Undefined = Node.Undefined;
25 private _size: number = 0;
27 > get size(): number {
28 return this._size;
29 }
31 > isEmpty(): boolean {
32 return this._first === Node.Undefined;
33 }
35 > clear(): void {
36 let node = this._first;
37 while (node !== Node.Undefined) {
46 this._size = 0;
47 }
49 > unshift(element: E): () => void {
50 return this._insert(element, false);
51 }
53 > push(element: E): () => void {
54 return this._insert(element, true);
55 }
57 > private _insert(element: E, atTheEnd: boolean): () => void {
58 const newNode = new Node(element);
59 if (this._first === Node.Undefined) {
85 };
86 }
88 > shift(): E | undefined {
89 if (this._first === Node.Undefined) {
90 return undefined;
95 }
96 }
98 > pop(): E | undefined {
99 if (this._last === Node.Undefined) {
100 return undefined;
105 }
106 }
108 > peek(): E | undefined {
109 if (this._last === Node.Undefined) {
110 return undefined;
114 }
115 }
117 > private _remove(node: Node<E> | typeof Node.Undefined): void {
118 if (node.prev !== Node.Undefined && node.next !== Node.Undefined) {
119 // middle
141 this._size -= 1;
142 }
144 > *[Symbol.iterator](): Iterator<E> {
145 let node = this._first;
146 while (node !== Node.Undefined) {
src/vs/base/common/uint.ts 43 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- uint.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export const enum Constants {
7 > /**
8 > * MAX SMI (SMall Integer) as defined in v8.
9 > * one bit is lost for boxing/unboxing flag.
10 > * one bit is lost for sign flag.
11 > * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values
12 > */
13 > MAX_SAFE_SMALL_INTEGER = 1 << 30,
14 >
15 > /**
16 > * MIN SMI (SMall Integer) as defined in v8.
17 > * one bit is lost for boxing/unboxing flag.
18 > * one bit is lost for sign flag.
19 > * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values
20 > */
21 > MIN_SAFE_SMALL_INTEGER = -(1 << 30),
22 >
23 > /**
24 > * Max unsigned integer that fits on 8 bits.
25 > */
26 > MAX_UINT_8 = 255, // 2^8 - 1
27 >
28 > /**
29 > * Max unsigned integer that fits on 16 bits.
30 > */
31 > MAX_UINT_16 = 65535, // 2^16 - 1
32 >
33 > /**
34 > * Max unsigned integer that fits on 32 bits.
35 > */
36 > MAX_UINT_32 = 4294967295, // 2^32 - 1
37 >
38 > UNICODE_SUPPLEMENTARY_PLANE_BEGIN = 0x010000
39 > }
40 >
41 > export function toUint8(v: number): number {
42 if (v < 0) {
43 return 0;
48 return v | 0;
49 }
50 > uint.ts
51 > export function toUint32(v: number): number {
52 if (v < 0) {
53 return 0;
src/vs/base/common/observableInternal/debugLocation.ts 42 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- debugLocation.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export type DebugLocation = DebugLocationImpl | undefined;
7 >
8 > export namespace DebugLocation {
9 > let enabled = false;
10 >
11 > export function enable(): void {
12 enabled = true;
13 }
15 > export function ofCaller(): DebugLocation {
16 if (!enabled) {
17 return undefined;
26 return DebugLocationImpl.fromStack(stack, 2);
27 }
29 >
30 > class DebugLocationImpl implements ILocation {
31 > public static fromStack(stack: string, parentIdx: number): DebugLocationImpl | undefined {
32 > const lines = stack.split('\n');
33 > const location = parseLine(lines[parentIdx + 1]);
34 > if (location) {
35 > return new DebugLocationImpl(
36 > location.fileName,
37 > location.line,
38 > location.column,
39 > location.id
40 > );
41 > } else {
42 > return undefined;
43 > }
44 > }
45 >
46 > constructor(
47 public readonly fileName: string,
48 public readonly line: number,
51 ) {
52 }
54 >
55 >
56 > export interface ILocation {
57 > fileName: string;
58 > line: number;
59 > column: number;
60 > id: string;
61 > }
62 >
63 function parseLine(stackLine: string): ILocation | undefined {
64 const match = stackLine.match(/\((.*):(\d+):(\d+)\)/);
src/vs/base/common/lazy.ts 39 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lazy.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > enum LazyValueState {
7 > Uninitialized,
8 > Running,
9 > Completed,
10 > }
11 >
12 > export class Lazy<T> {
13 >
14 > private _state = LazyValueState.Uninitialized;
15 > private _value?: T;
16 > private _error: Error | undefined;
17 >
18 > constructor(
19 > private readonly executor: () => T, lazy.ts
20 > ) { }
21 > lazy.ts
22 > /**
23 > * True if the lazy value has been resolved.
24 > */
25 > get hasValue(): boolean { return this._state === LazyValueState.Completed; }
26 >
27 > /**
28 > * Get the wrapped value.
29 > *
30 > * This will force evaluation of the lazy value if it has not been resolved yet. Lazy values are only
31 > * resolved once. `getValue` will re-throw exceptions that are hit while resolving the value
32 > */
33 > get value(): T {
34 if (this._state === LazyValueState.Uninitialized) {
35 this._state = LazyValueState.Running;
50 return this._value!;
51 }
52 > lazy.ts
53 > /**
54 > * Get the wrapped value without forcing evaluation.
55 > */
56 > get rawValue(): T | undefined { return this._value; }
57 > }
src/vs/base/common/observableInternal/transaction.ts 39 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- transaction.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { handleBugIndicatingErrorRecovery, IObservable, IObserver, ITransaction } from './base.js';
7 > import { getFunctionName } from './debugName.js';
8 > import { getLogger } from './logging/logging.js';
9 >
10 > /**
11 > * Starts a transaction in which many observables can be changed at once.
12 > * {@link fn} should start with a JS Doc using `@description` to give the transaction a debug name.
13 > * Reaction run on demand or when the transaction ends.
14 > */
15 >
16 > export function transaction(fn: (tx: ITransaction) => void, getDebugName?: () => string): void {
17 const tx = new TransactionImpl(fn, getDebugName);
18 try {
22 }
23 }
24 > let _globalTransaction: ITransaction | undefined = undefined; transaction.ts
25 >
26 > export function globalTransaction(fn: (tx: ITransaction) => void) {
27 if (_globalTransaction) {
28 fn(_globalTransaction);
40 }
41 }
42 > /** @deprecated */ transaction.ts
43 >
44 export async function asyncTransaction(fn: (tx: ITransaction) => Promise<void>, getDebugName?: () => string): Promise<void> {
45 const tx = new TransactionImpl(fn, getDebugName);
50 }
51 }
52 > /** transaction.ts
53 > * Allows to chain transactions.
54 > */
55 >
56 > export function subtransaction(tx: ITransaction | undefined, fn: (tx: ITransaction) => void, getDebugName?: () => string): void {
57 if (!tx) {
58 transaction(fn, getDebugName);
60 fn(tx);
61 }
62 > } export class TransactionImpl implements ITransaction { transaction.ts
63 > private _updatingObservers: { observer: IObserver; observable: IObservable<any> }[] | null = [];
64 >
65 > constructor(public readonly _fn: Function, private readonly _getDebugName?: () => string) {
66 getLogger()?.handleBeginTransaction(this);
67 }
69 > public getDebugName(): string | undefined {
70 if (this._getDebugName) {
71 return this._getDebugName();
73 return getFunctionName(this._fn);
74 }
76 > public updateObserver(observer: IObserver, observable: IObservable<any>): void {
77 if (!this._updatingObservers) {
78 // This happens when a transaction is used in a callback or async function.
90 observer.beginUpdate(observable);
91 }
93 > public finish(): void {
94 const updatingObservers = this._updatingObservers;
95 if (!updatingObservers) {
106 getLogger()?.handleEndTransaction(this);
107 }
109 > public debugGetUpdatingObservers() {
110 return this._updatingObservers;
111 }
112 > } transaction.ts
113
src/vs/base/common/observableInternal/observables/observableSignalFromEvent.ts 38 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- observableSignalFromEvent.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable } from '../base.js';
7 > import { transaction } from '../transaction.js';
8 > import { Event, IDisposable } from '../commonFacade/deps.js';
9 > import { DebugOwner, DebugNameData } from '../debugName.js';
10 > import { BaseObservable } from './baseObservable.js';
11 > import { DebugLocation } from '../debugLocation.js';
12 >
13 > export function observableSignalFromEvent(
14 owner: DebugOwner | string,
15 event: Event<any>,
18 return new FromEventObservableSignal(typeof owner === 'string' ? owner : new DebugNameData(owner, undefined, undefined), event, debugLocation);
19 }
21 > class FromEventObservableSignal extends BaseObservable<void> {
22 > private subscription: IDisposable | undefined;
23 >
24 > public readonly debugName: string;
25 > constructor(
26 debugNameDataOrName: DebugNameData | string,
27 private readonly event: Event<any>,
33 : debugNameDataOrName.getDebugName(this) ?? 'Observable Signal From Event';
34 }
36 > protected override onFirstObserverAdded(): void {
37 this.subscription = this.event(this.handleEvent);
38 }
40 > private readonly handleEvent = () => {
41 > transaction( observableSignalFromEvent.ts
42 > (tx) => {
43 > for (const o of this._observers) {
44 > tx.updateObserver(o, this);
45 > o.handleChange(this, undefined);
46 > }
47 > },
48 > () => this.debugName
49 > );
50 > };
52 > protected override onLastObserverRemoved(): void {
53 this.subscription!.dispose();
54 this.subscription = undefined;
55 }
57 > public override get(): void {
58 // NO OP
59 }
src/vs/base/common/observableInternal/observables/observableSignal.ts 37 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- observableSignal.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservableWithChange, ITransaction } from '../base.js';
7 > import { transaction } from '../transaction.js';
8 > import { DebugNameData } from '../debugName.js';
9 > import { BaseObservable } from './baseObservable.js';
10 > import { DebugLocation } from '../debugLocation.js';
11 >
12 > /**
13 > * Creates a signal that can be triggered to invalidate observers.
14 > * Signals don't have a value - when they are triggered they indicate a change.
15 > * However, signals can carry a delta that is passed to observers.
16 > */
17 > export function observableSignal<TDelta = void>(debugName: string): IObservableSignal<TDelta>;
18 > export function observableSignal<TDelta = void>(owner: object): IObservableSignal<TDelta>;
19 > export function observableSignal<TDelta = void>(debugNameOrOwner: string | object, debugLocation = DebugLocation.ofCaller()): IObservableSignal<TDelta> {
20 if (typeof debugNameOrOwner === 'string') {
21 return new ObservableSignal<TDelta>(debugNameOrOwner, undefined, debugLocation);
24 }
25 }
27 > export interface IObservableSignal<TChange> extends IObservableWithChange<void, TChange> {
28 > trigger(tx: ITransaction | undefined, change: TChange): void;
29 > }
30 >
31 > class ObservableSignal<TChange> extends BaseObservable<void, TChange> implements IObservableSignal<TChange> {
32 > public get debugName() {
33 > return new DebugNameData(this._owner, this._debugName, undefined).getDebugName(this) ?? 'Observable Signal';
34 > }
35 >
36 > public override toString(): string {
37 return this.debugName;
38 }
40 > constructor(
41 private readonly _debugName: string | undefined,
42 private readonly _owner: object | undefined,
45 super(debugLocation);
46 }
48 > public trigger(tx: ITransaction | undefined, change: TChange): void {
49 if (!tx) {
50 transaction(tx => {
src/vs/base/common/observableInternal/changeTracker.ts 35 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- changeTracker.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { BugIndicatingError } from './commonFacade/deps.js';
7 > import { IObservableWithChange, IReader } from './base.js';
8 >
9 > export interface IChangeTracker<TChangeSummary> {
10 > createChangeSummary(previousChangeSummary: TChangeSummary | undefined): TChangeSummary;
11 > handleChange(ctx: IChangeContext, change: TChangeSummary): boolean;
12 > beforeUpdate?(reader: IReader, change: TChangeSummary): void;
13 > }
14 >
15 > export interface IChangeContext {
16 > readonly changedObservable: IObservableWithChange<any, any>;
17 > readonly change: unknown;
18 >
19 > /**
20 > * Returns if the given observable caused the change.
21 > */
22 > didChange<T, TChange>(observable: IObservableWithChange<T, TChange>): this is { change: TChange };
23 > }
24 >
25 > /**
26 > * Subscribes to and records changes and the last value of the given observables.
27 > * Don't use the key "changes", as it is reserved for the changes array!
28 > */
29 > export function recordChanges<TObs extends Record<any, IObservableWithChange<any, any>>>(obs: TObs):
30 IChangeTracker<{ [TKey in keyof TObs]: ReturnType<TObs[TKey]['get']> }
31 & { changes: readonly ({ [TKey in keyof TObs]: { key: TKey; change: TObs[TKey]['TChange'] } }[keyof TObs])[] }> {
56 };
57 }
59 > /**
60 > * Subscribes to and records changes and the last value of the given observables.
61 > * Don't use the key "changes", as it is reserved for the changes array!
62 > */
63 > export function recordChangesLazy<TObs extends Record<any, IObservableWithChange<any, any>>>(getObs: () => TObs):
64 IChangeTracker<{ [TKey in keyof TObs]: ReturnType<TObs[TKey]['get']> }
65 & { changes: readonly ({ [TKey in keyof TObs]: { key: TKey; change: TObs[TKey]['TChange'] } }[keyof TObs])[] }> {
src/vs/base/common/observableInternal/map.ts 35 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- map.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable, ITransaction } from '../observable.js';
7 > import { observableValueOpts } from './observables/observableValueOpts.js';
8 >
9 >
10 > export class ObservableMap<K, V> implements Map<K, V> {
11 private readonly _data = new Map<K, V>();
12
14
15 readonly observable: IObservable<Map<K, V>> = this._obs;
16 > map.ts
17 > get size(): number {
18 return this._data.size;
19 }
20 > map.ts
21 > has(key: K): boolean {
22 return this._data.has(key);
23 }
24 > map.ts
25 > get(key: K): V | undefined {
26 return this._data.get(key);
27 }
28 > map.ts
29 > set(key: K, value: V, tx?: ITransaction): this {
30 const hadKey = this._data.has(key);
31 const oldValue = this._data.get(key);
36 return this;
37 }
38 > map.ts
39 > delete(key: K, tx?: ITransaction): boolean {
40 const result = this._data.delete(key);
41 if (result) {
44 return result;
45 }
46 > map.ts
47 > clear(tx?: ITransaction): void {
48 if (this._data.size > 0) {
49 this._data.clear();
51 }
52 }
53 > map.ts
54 > forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: unknown): void {
55 this._data.forEach((value, key, _map) => {
56 callbackfn.call(thisArg, value, key, this);
57 });
58 }
59 > map.ts
60 > *entries(): MapIterator<[K, V]> {
61 yield* this._data.entries();
62 }
63 > map.ts
64 > *keys(): MapIterator<K> {
65 yield* this._data.keys();
66 }
67 > map.ts
68 > *values(): MapIterator<V> {
69 yield* this._data.values();
70 }
71 > map.ts
72 > [Symbol.iterator](): MapIterator<[K, V]> {
73 return this.entries();
74 }
75 > map.ts
76 > get [Symbol.toStringTag](): string {
77 return 'ObservableMap';
78 }
79 > } map.ts
src/vs/base/common/marshallingIds.ts 33 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- marshallingIds.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export const enum MarshalledId {
7 > Uri = 1,
8 > Regexp,
9 > ScmResource,
10 > ScmResourceGroup,
11 > ScmProvider,
12 > CommentController,
13 > CommentThread,
14 > CommentThreadInstance,
15 > CommentThreadReply,
16 > CommentNode,
17 > CommentThreadNode,
18 > TimelineActionContext,
19 > NotebookCellActionContext,
20 > NotebookActionContext,
21 > TerminalContext,
22 > TestItemContext,
23 > Date,
24 > TestMessageMenuArgs,
25 > ChatViewContext,
26 > LanguageModelToolResult,
27 > LanguageModelTextPart,
28 > LanguageModelThinkingPart,
29 > LanguageModelPromptTsxPart,
30 > LanguageModelDataPart,
31 > AgentSessionContext,
32 > ChatResponsePullRequestPart,
33 > }
src/vs/base/common/observableInternal/set.ts 32 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- set.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable, ITransaction } from '../observable.js';
7 > import { observableValueOpts } from './observables/observableValueOpts.js';
8 >
9 > export class ObservableSet<T> implements Set<T> {
10
11 private readonly _data = new Set<T>();
14
15 readonly observable: IObservable<Set<T>> = this._obs;
16 > set.ts
17 > get size(): number {
18 return this._data.size;
19 }
20 > set.ts
21 > has(value: T): boolean {
22 return this._data.has(value);
23 }
24 > set.ts
25 > add(value: T, tx?: ITransaction): this {
26 const hadValue = this._data.has(value);
27 if (!hadValue) {
31 return this;
32 }
33 > set.ts
34 > delete(value: T, tx?: ITransaction): boolean {
35 const result = this._data.delete(value);
36 if (result) {
39 return result;
40 }
41 > set.ts
42 > clear(tx?: ITransaction): void {
43 if (this._data.size > 0) {
44 this._data.clear();
46 }
47 }
48 > set.ts
49 > forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: unknown): void {
50 this._data.forEach((value, value2, _set) => {
51 callbackfn.call(thisArg, value, value2, this);
52 });
53 }
54 > set.ts
55 > *entries(): SetIterator<[T, T]> {
56 for (const value of this._data) {
57 yield [value, value];
58 }
59 }
60 > set.ts
61 > *keys(): SetIterator<T> {
62 yield* this._data.keys();
63 }
64 > set.ts
65 > *values(): SetIterator<T> {
66 yield* this._data.values();
67 }
68 > set.ts
69 > [Symbol.iterator](): SetIterator<T> {
70 return this.values();
71 }
72 > set.ts
73 > get [Symbol.toStringTag](): string {
74 return 'ObservableSet';
75 }
76 > } set.ts
src/vs/base/common/observableInternal/experimental/utils.ts 26 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- utils.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable, IReader } from '../base.js';
7 > import { BugIndicatingError, DisposableStore } from '../commonFacade/deps.js';
8 > import { DebugOwner, getDebugName, DebugNameData } from '../debugName.js';
9 > import { observableFromEvent } from '../observables/observableFromEvent.js';
10 > import { autorunOpts } from '../reactions/autorun.js';
11 > import { derivedObservableWithCache } from '../utils/utils.js';
12 >
13 > /**
14 > * Creates an observable that has the latest changed value of the given observables.
15 > * Initially (and when not observed), it has the value of the last observable.
16 > * When observed and any of the observables change, it has the value of the last changed observable.
17 > * If multiple observables change in the same transaction, the last observable wins.
18 > */
19 > export function latestChangedValue<T extends IObservable<any>[]>(owner: DebugOwner, observables: T): IObservable<ReturnType<T[number]['get']>> {
20 if (observables.length === 0) {
21 throw new BugIndicatingError();
50 return result;
51 }
52 > utils.ts
53 > /**
54 > * Works like a derived.
55 > * However, if the value is not undefined, it is cached and will not be recomputed anymore.
56 > * In that case, the derived will unsubscribe from its dependencies.
57 > */
58 > export function derivedConstOnceDefined<T>(owner: DebugOwner, fn: (reader: IReader) => T): IObservable<T | undefined> {
59 return derivedObservableWithCache<T | undefined>(owner, (reader, lastValue) => lastValue ?? fn(reader));
60 }
src/vs/base/common/observableInternal/observables/constObservable.ts 26 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- constObservable.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable, IObserver, IObservableWithChange } from '../base.js';
7 > import { ConvenientObservable } from './baseObservable.js';
8 >
9 > /**
10 > * Represents an efficient observable whose value never changes.
11 > */
12 >
13 > export function constObservable<T>(value: T): IObservable<T> {
14 return new ConstObservable(value);
15 }
16 > class ConstObservable<T> extends ConvenientObservable<T, void> { constObservable.ts
17 > constructor(private readonly value: T) {
18 super();
19 }
21 > public override get debugName(): string {
22 return this.toString();
23 }
25 > public get(): T {
26 return this.value;
27 }
28 > public addObserver(observer: IObserver): void { constObservable.ts
29 // NO OP
30 }
31 > public removeObserver(observer: IObserver): void { constObservable.ts
32 // NO OP
33 }
35 > override log(): IObservableWithChange<T, void> {
36 return this;
37 }
39 > override toString(): string {
40 return `Const: ${this.value}`;
41 }
src/vs/base/common/stopwatch.ts 25 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- stopwatch.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > declare const globalThis: { performance: { now(): number } };
7 > const performanceNow = globalThis.performance.now.bind(globalThis.performance);
8 >
9 > export class StopWatch {
10 >
11 > private _startTime: number;
12 > private _stopTime: number;
13 >
14 > private readonly _now: () => number;
15 >
16 > public static create(highResolution?: boolean): StopWatch {
17 return new StopWatch(highResolution);
18 }
20 > constructor(highResolution?: boolean) {
21 this._now = highResolution === false ? Date.now : performanceNow;
22 this._startTime = this._now();
23 this._stopTime = -1;
24 }
26 > public stop(): void {
27 this._stopTime = this._now();
28 }
30 > public reset(): void {
31 this._startTime = this._now();
32 this._stopTime = -1;
33 }
35 > public elapsed(): number {
36 if (this._stopTime !== -1) {
37 return this._stopTime - this._startTime;
39 return this._now() - this._startTime;
40 }
41 > } stopwatch.ts
src/vs/base/common/codiconsUtil.ts 24 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- codiconsUtil.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 > import { ThemeIcon } from './themables.js';
6 > import { isString } from './types.js';
7 >
8 >
9 > const _codiconFontCharacters: { [id: string]: number } = Object.create(null);
10 >
11 > export function register(id: string, fontCharacter: number | string): ThemeIcon {
12 > if (isString(fontCharacter)) {
13 > const val = _codiconFontCharacters[fontCharacter];
14 > if (val === undefined) {
15 throw new Error(`${id} references an unknown codicon: ${fontCharacter}`);
16 }
17 > fontCharacter = val; codiconsUtil.ts
18 > }
19 > _codiconFontCharacters[id] = fontCharacter;
20 > return { id };
21 > }
22 >
23 > /**
24 > * Only to be used by the iconRegistry.
25 > */
26 > export function getCodiconFontCharacters(): { [id: string]: number } {
27 return _codiconFontCharacters;
28 }
src/vs/base/common/observableInternal/logging/debugger/utils.ts 24 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- utils.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IDisposable } from '../../../lifecycle.js';
7 >
8 > export class Debouncer implements IDisposable {
9 private _timeout: Timeout | undefined = undefined;
10 > utils.ts
11 > public debounce(fn: () => void, timeoutMs: number): void {
12 if (this._timeout !== undefined) {
13 clearTimeout(this._timeout);
18 }, timeoutMs);
19 }
20 > utils.ts
21 > dispose(): void {
22 if (this._timeout !== undefined) {
23 clearTimeout(this._timeout);
24 }
25 }
26 > } utils.ts
27 >
28 > export class Throttler implements IDisposable {
29 private _timeout: Timeout | undefined = undefined;
30 > utils.ts
31 > public throttle(fn: () => void, timeoutMs: number): void {
32 if (this._timeout === undefined) {
33 this._timeout = setTimeout(() => {
37 }
38 }
39 > utils.ts
40 > dispose(): void {
41 if (this._timeout !== undefined) {
42 clearTimeout(this._timeout);
43 }
44 }
45 > } utils.ts
46 >
47 > export function deepAssign<T>(target: T, source: T): void {
48 for (const key in source) {
49 if (!!target[key] && typeof target[key] === 'object' && !!source[key] && typeof source[key] === 'object') {
54 }
55 }
56 > utils.ts
57 > export function deepAssignDeleteNulls<T>(target: T, source: T): void {
58 for (const key in source) {
59 if (source[key] === null) {
src/vs/base/common/observableInternal/utils/utilsCancellation.ts 24 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- utilsCancellation.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IReader, IObservable } from '../base.js';
7 > import { DebugOwner, DebugNameData } from '../debugName.js';
8 > import { CancellationError, CancellationToken, CancellationTokenSource } from '../commonFacade/cancellation.js';
9 > import { strictEquals } from '../commonFacade/deps.js';
10 > import { autorun } from '../reactions/autorun.js';
11 > import { Derived } from '../observables/derivedImpl.js';
12 > import { DebugLocation } from '../debugLocation.js';
13 >
14 > /**
15 > * Resolves the promise when the observables state matches the predicate.
16 > */
17 > export function waitForState<T>(observable: IObservable<T | null | undefined>): Promise<T>;
18 > export function waitForState<T, TState extends T>(observable: IObservable<T>, predicate: (state: T) => state is TState, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise<TState>;
19 > export function waitForState<T>(observable: IObservable<T>, predicate: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise<T>;
20 > export function waitForState<T>(observable: IObservable<T>, predicate?: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise<T> {
21 if (!predicate) {
22 predicate = state => state !== null && state !== undefined;
69 });
70 }
72 > export function derivedWithCancellationToken<T>(computeFn: (reader: IReader, cancellationToken: CancellationToken) => T): IObservable<T>;
73 > export function derivedWithCancellationToken<T>(owner: object, computeFn: (reader: IReader, cancellationToken: CancellationToken) => T): IObservable<T>;
74 > export function derivedWithCancellationToken<T>(computeFnOrOwner: ((reader: IReader, cancellationToken: CancellationToken) => T) | object, computeFnOrUndefined?: ((reader: IReader, cancellationToken: CancellationToken) => T)): IObservable<T> {
75 let computeFn: (reader: IReader, store: CancellationToken) => T;
76 let owner: DebugOwner;
src/vs/base/common/observableInternal/utils/valueWithChangeEvent.ts 19 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- valueWithChangeEvent.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservable } from '../base.js';
7 > import { Event, IValueWithChangeEvent } from '../commonFacade/deps.js';
8 > import { DebugOwner } from '../debugName.js';
9 > import { observableFromEvent } from '../observables/observableFromEvent.js';
10 >
11 > export class ValueWithChangeEventFromObservable<T> implements IValueWithChangeEvent<T> {
12 > constructor(public readonly observable: IObservable<T>) {
13 }
15 > get onDidChange(): Event<void> {
16 return Event.fromObservableLight(this.observable);
17 }
19 > get value(): T {
20 return this.observable.get();
21 }
23 >
24 > export function observableFromValueWithChangeEvent<T>(owner: DebugOwner, value: IValueWithChangeEvent<T>): IObservable<T> {
25 if (value instanceof ValueWithChangeEventFromObservable) {
26 return value.observable;
src/vs/base/common/observableInternal/logging/debugger/debuggerRpc.ts 17 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- debuggerRpc.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ChannelFactory, IChannelHandler, API, SimpleTypedRpcConnection, MakeSideAsync } from './rpc.js';
7 >
8 > export function registerDebugChannel<T extends { channelId: string } & API>(
9 channelId: T['channelId'],
10 createClient: () => T['client'],
43 });
44 }
46 > interface GlobalObj {
47 > $$debugValueEditor_debugChannels: Record<string, (host: IHost) => { handleRequest: (data: unknown) => unknown }>;
48 > }
49 >
50 > interface IHost {
51 > sendNotification: (data: unknown) => void;
52 > }
53 >
54 function createChannelFactoryFromDebugChannel(host: IHost): { channel: ChannelFactory; handler: { handleRequest: (data: unknown) => unknown } } {
55 let h: IChannelHandler | undefined;
src/vs/base/common/observableInternal/utils/runOnChange.ts 17 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- runOnChange.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IObservableWithChange } from '../base.js';
7 > import { CancellationToken, cancelOnDispose } from '../commonFacade/cancellation.js';
8 > import { DisposableStore, IDisposable } from '../commonFacade/deps.js';
9 > import { autorunWithStoreHandleChanges } from '../reactions/autorun.js';
10 >
11 > export type RemoveUndefined<T> = T extends undefined ? never : T;
12 >
13 > export function runOnChange<T, TChange>(observable: IObservableWithChange<T, TChange>, cb: (value: T, previousValue: T, deltas: RemoveUndefined<TChange>[]) => void): IDisposable {
14 let _previousValue: T | undefined;
15 let _firstRun = true;
42 });
43 }
45 > export function runOnChangeWithStore<T, TChange>(observable: IObservableWithChange<T, TChange>, cb: (value: T, previousValue: T, deltas: RemoveUndefined<TChange>[], store: DisposableStore) => void): IDisposable {
46 const store = new DisposableStore();
47 const disposable = runOnChange(observable, (value, previousValue: T, deltas) => {
56 };
57 }
59 > export function runOnChangeWithCancellationToken<T, TChange>(observable: IObservableWithChange<T, TChange>, cb: (value: T, previousValue: T, deltas: RemoveUndefined<TChange>[], token: CancellationToken) => Promise<void>): IDisposable {
60 return runOnChangeWithStore(observable, (value, previousValue, deltas, store) => {
61 cb(value, previousValue, deltas, cancelOnDispose(store));
src/vs/base/common/observableInternal/observables/observableValueOpts.ts 13 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- observableValueOpts.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { ISettableObservable } from '../base.js';
7 > import { DebugNameData, IDebugNameData } from '../debugName.js';
8 > import { EqualityComparer, strictEquals } from '../commonFacade/deps.js';
9 > import { ObservableValue } from './observableValue.js';
10 > import { LazyObservableValue } from './lazyObservableValue.js';
11 > import { DebugLocation } from '../debugLocation.js';
12 >
13 > export function observableValueOpts<T, TChange = void>(
14 options: IDebugNameData & {
15 equalsFn?: EqualityComparer<T>;
src/vs/base/common/observableInternal/commonFacade/deps.ts 10 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- deps.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export { assertFn } from '../../assert.js';
7 > export { type EqualityComparer, strictEquals } from '../../equals.js';
8 > export { BugIndicatingError, onBugIndicatingError, onUnexpectedError } from '../../errors.js';
9 > export { Event, type IValueWithChangeEvent } from '../../event.js';
10 > export { DisposableStore, type IDisposable, markAsDisposed, toDisposable, trackDisposable } from '../../lifecycle.js';
src/vs/base/common/functional.ts 9 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- functional.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > /**
7 > * Given a function, returns a function that is only calling that function once.
8 > */
9 > export function createSingleCallFunction<T extends Function>(this: unknown, fn: T, fnDidRunCallback?: () => void): T {
10 const _this = this;
11 let didCall = false;
src/vs/base/common/observable.ts 8 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- observable.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > // This is a facade for the observable implementation. Only import from here!
7 >
8 > export * from './observableInternal/index.js';
src/vs/base/common/observableInternal/commonFacade/cancellation.ts 7 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- cancellation.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export { CancellationError } from '../../errors.js';
7 > export { CancellationToken, CancellationTokenSource, cancelOnDispose } from '../../cancellation.js';