Atlas › Test

editorWebWorker.test|title=EditorWebWorker [Bug] Getting Message "Overlapping ranges are not allowed" and nothing happens with Inline-Chat|occurrence=1

Exact test identity: mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker [Bug] Getting Message "Overlapping ranges are not allowed" and nothing happens with Inline-Chat|occurrence=1

Package
mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services
Suite / test hierarchy
editorWebWorker.test|title=EditorWebWorker [Bug] Getting Message "Overlapping ranges are not allowed" and nothing happens with Inline-Chat|occurrence=1
Test
editorWebWorker.test|title=EditorWebWorker [Bug] Getting Message "Overlapping ranges are not allowed" and nothing happens with Inline-Chat|occurrence=1
Introduced at
editorWebWorker.test|title=EditorWebWorker [Bug] Getting Message "Overlapping ranges are not allowed" and nothing happens with Inline-Chat|occurrence=1 Frontier kind: Test frontier
Covered ranges
2391
Covered lines
20010
Covered files
91

Covered source

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

src/vs/editor/common/languages.ts 2475 covered LOC · 27 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languages.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 { VSBuffer } from '../../base/common/buffer.js';
7 > import { CancellationToken } from '../../base/common/cancellation.js';
8 > import { Codicon } from '../../base/common/codicons.js';
9 > import { Color } from '../../base/common/color.js';
10 > import { IReadonlyVSDataTransfer } from '../../base/common/dataTransfer.js';
11 > import { Event } from '../../base/common/event.js';
12 > import { HierarchicalKind } from '../../base/common/hierarchicalKind.js';
13 > import { IMarkdownString } from '../../base/common/htmlContent.js';
14 > import { IDisposable } from '../../base/common/lifecycle.js';
15 > import { ThemeIcon } from '../../base/common/themables.js';
16 > import { URI, UriComponents } from '../../base/common/uri.js';
17 > import { EditOperation, ISingleEditOperation } from './core/editOperation.js';
18 > import { IPosition, Position } from './core/position.js';
19 > import { IRange, Range } from './core/range.js';
20 > import { Selection } from './core/selection.js';
21 > import { LanguageId } from './encodedTokenAttributes.js';
22 > import { LanguageSelector } from './languageSelector.js';
23 > import * as model from './model.js';
24 > import { TokenizationRegistry as TokenizationRegistryImpl } from './tokenizationRegistry.js';
25 > import { ContiguousMultilineTokens } from './tokens/contiguousMultilineTokens.js';
26 > import { localize } from '../../nls.js';
27 > import { ExtensionIdentifier } from '../../platform/extensions/common/extensions.js';
28 > import { IMarkerData } from '../../platform/markers/common/markers.js';
29 > import { EditDeltaInfo } from './textModelEditSource.js';
30 > import { FontTokensUpdate } from './textModelEvents.js';
31 >
32 > /**
33 > * @internal
34 > */
35 > export interface ILanguageIdCodec {
36 > encodeLanguageId(languageId: string): LanguageId;
37 > decodeLanguageId(languageId: LanguageId): string;
38 > }
39 >
40 > export class Token {
41 > _tokenBrand: void = undefined;
42 >
43 > constructor(
44 public readonly offset: number,
45 public readonly type: string,
47 ) {
48 }
50 > public toString(): string {
51 return '(' + this.offset + ', ' + this.type + ')';
52 }
53 > } languages.ts
54 >
55 > /**
56 > * @internal
57 > */
58 > export class TokenizationResult {
59 > _tokenizationResultBrand: void = undefined;
60 >
61 > constructor(
62 public readonly tokens: Token[],
63 public readonly endState: IState,
64 ) {
65 }
66 > } languages.ts
67 >
68 > /**
69 > * @internal
70 > */
71 > export interface IFontToken {
72 > readonly startIndex: number;
73 > readonly endIndex: number;
74 > readonly fontFamily: string | null;
75 > readonly fontSizeMultiplier: number | null;
76 > readonly lineHeightMultiplier: number | null;
77 > }
78 >
79 > /**
80 > * @internal
81 > */
82 > export class EncodedTokenizationResult {
83 > _encodedTokenizationResultBrand: void = undefined;
84 >
85 > constructor(
86 /**
87 * The tokens in binary format. Each token occupies two array indices. For token i:
95 ) {
96 }
97 > } languages.ts
98 >
99 > export interface SyntaxNode {
100 > startIndex: number;
101 > endIndex: number;
102 > startPosition: IPosition;
103 > endPosition: IPosition;
104 > }
105 >
106 > export interface QueryCapture {
107 > name: string;
108 > text?: string;
109 > node: SyntaxNode;
110 > encodedLanguageId: number;
111 > }
112 >
113 > /**
114 > * @internal
115 > */
116 > export interface ITokenizationSupport {
117 > /**
118 > * If true, the background tokenizer will only be used to verify tokens against the default background tokenizer.
119 > * Used for debugging.
120 > */
121 > readonly backgroundTokenizerShouldOnlyVerifyTokens?: boolean;
122 >
123 > getInitialState(): IState;
124 >
125 > tokenize(line: string, hasEOL: boolean, state: IState): TokenizationResult;
126 >
127 > tokenizeEncoded(line: string, hasEOL: boolean, state: IState): EncodedTokenizationResult;
128 >
129 > /**
130 > * Can be/return undefined if default background tokenization should be used.
131 > */
132 > createBackgroundTokenizer?(textModel: model.ITextModel, store: IBackgroundTokenizationStore): IBackgroundTokenizer | undefined;
133 > }
134 >
135 > /**
136 > * @internal
137 > */
138 > export interface IBackgroundTokenizer extends IDisposable {
139 > /**
140 > * Instructs the background tokenizer to set the tokens for the given range again.
141 > *
142 > * This might be necessary if the renderer overwrote those tokens with heuristically computed ones for some viewport,
143 > * when the change does not even propagate to that viewport.
144 > */
145 > requestTokens(startLineNumber: number, endLineNumberExclusive: number): void;
146 >
147 > reportMismatchingTokens?(lineNumber: number): void;
148 > }
149 >
150 > /**
151 > * @internal
152 > */
153 > export interface IBackgroundTokenizationStore {
154 > setTokens(tokens: ContiguousMultilineTokens[]): void;
155 >
156 > setFontInfo(changes: FontTokensUpdate): void;
157 >
158 > setEndState(lineNumber: number, state: IState): void;
159 >
160 > /**
161 > * Should be called to indicate that the background tokenization has finished for now.
162 > * (This triggers bracket pair colorization to re-parse the bracket pairs with token information)
163 > */
164 > backgroundTokenizationFinished(): void;
165 > }
166 >
167 > /**
168 > * The state of the tokenizer between two lines.
169 > * It is useful to store flags such as in multiline comment, etc.
170 > * The model will clone the previous line's state and pass it in to tokenize the next line.
171 > */
172 > export interface IState {
173 > clone(): IState;
174 > equals(other: IState): boolean;
175 > }
176 >
177 > /**
178 > * A provider result represents the values a provider, like the {@link HoverProvider},
179 > * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves
180 > * to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a
181 > * thenable.
182 > */
183 > export type ProviderResult<T> = T | undefined | null | Thenable<T | undefined | null>;
184 >
185 > /**
186 > * A hover represents additional information for a symbol or word. Hovers are
187 > * rendered in a tooltip-like widget.
188 > */
189 > export interface Hover {
190 > /**
191 > * The contents of this hover.
192 > */
193 > contents: IMarkdownString[];
194 >
195 > /**
196 > * The range to which this hover applies. When missing, the
197 > * editor will use the range at the current position or the
198 > * current position itself.
199 > */
200 > range?: IRange;
201 >
202 > /**
203 > * Can increase the verbosity of the hover
204 > */
205 > canIncreaseVerbosity?: boolean;
206 >
207 > /**
208 > * Can decrease the verbosity of the hover
209 > */
210 > canDecreaseVerbosity?: boolean;
211 > }
212 >
213 > /**
214 > * The hover provider interface defines the contract between extensions and
215 > * the [hover](https://code.visualstudio.com/docs/editor/intellisense)-feature.
216 > */
217 > export interface HoverProvider<THover = Hover> {
218 > /**
219 > * Provide a hover for the given position, context and document. Multiple hovers at the same
220 > * position will be merged by the editor. A hover can have a range which defaults
221 > * to the word range at the position when omitted.
222 > */
223 > provideHover(model: model.ITextModel, position: Position, token: CancellationToken, context?: HoverContext<THover>): ProviderResult<THover>;
224 > }
225 >
226 > export interface HoverContext<THover = Hover> {
227 > /**
228 > * Hover verbosity request
229 > */
230 > verbosityRequest?: HoverVerbosityRequest<THover>;
231 > }
232 >
233 > export interface HoverVerbosityRequest<THover = Hover> {
234 > /**
235 > * The delta by which to increase/decrease the hover verbosity level
236 > */
237 > verbosityDelta: number;
238 > /**
239 > * The previous hover for the same position
240 > */
241 > previousHover: THover;
242 > }
243 >
244 > export enum HoverVerbosityAction {
245 > /**
246 > * Increase the verbosity of the hover
247 > */
248 > Increase,
249 > /**
250 > * Decrease the verbosity of the hover
251 > */
252 > Decrease
253 > }
254 >
255 > /**
256 > * An evaluatable expression represents additional information for an expression in a document. Evaluatable expressions are
257 > * evaluated by a debugger or runtime and their result is rendered in a tooltip-like widget.
258 > * @internal
259 > */
260 > export interface EvaluatableExpression {
261 > /**
262 > * The range to which this expression applies.
263 > */
264 > range: IRange;
265 > /**
266 > * This expression overrides the expression extracted from the range.
267 > */
268 > expression?: string;
269 > }
270 >
271 >
272 > /**
273 > * The evaluatable expression provider interface defines the contract between extensions and
274 > * the debug hover.
275 > * @internal
276 > */
277 > export interface EvaluatableExpressionProvider {
278 > /**
279 > * Provide a hover for the given position and document. Multiple hovers at the same
280 > * position will be merged by the editor. A hover can have a range which defaults
281 > * to the word range at the position when omitted.
282 > */
283 > provideEvaluatableExpression(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<EvaluatableExpression>;
284 > }
285 >
286 > /**
287 > * A value-object that contains contextual information when requesting inline values from a InlineValuesProvider.
288 > * @internal
289 > */
290 > export interface InlineValueContext {
291 > frameId: number;
292 > stoppedLocation: Range;
293 > }
294 >
295 > /**
296 > * Provide inline value as text.
297 > * @internal
298 > */
299 > export interface InlineValueText {
300 > type: 'text';
301 > range: IRange;
302 > text: string;
303 > }
304 >
305 > /**
306 > * Provide inline value through a variable lookup.
307 > * @internal
308 > */
309 > export interface InlineValueVariableLookup {
310 > type: 'variable';
311 > range: IRange;
312 > variableName?: string;
313 > caseSensitiveLookup: boolean;
314 > }
315 >
316 > /**
317 > * Provide inline value through an expression evaluation.
318 > * @internal
319 > */
320 > export interface InlineValueExpression {
321 > type: 'expression';
322 > range: IRange;
323 > expression?: string;
324 > }
325 >
326 > /**
327 > * Inline value information can be provided by different means:
328 > * - directly as a text value (class InlineValueText).
329 > * - as a name to use for a variable lookup (class InlineValueVariableLookup)
330 > * - as an evaluatable expression (class InlineValueEvaluatableExpression)
331 > * The InlineValue types combines all inline value types into one type.
332 > * @internal
333 > */
334 > export type InlineValue = InlineValueText | InlineValueVariableLookup | InlineValueExpression;
335 >
336 > /**
337 > * The inline values provider interface defines the contract between extensions and
338 > * the debugger's inline values feature.
339 > * @internal
340 > */
341 > export interface InlineValuesProvider {
342 > /**
343 > */
344 > onDidChangeInlineValues?: Event<void> | undefined;
345 > /**
346 > * Provide the "inline values" for the given range and document. Multiple hovers at the same
347 > * position will be merged by the editor. A hover can have a range which defaults
348 > * to the word range at the position when omitted.
349 > */
350 > provideInlineValues(model: model.ITextModel, viewPort: Range, context: InlineValueContext, token: CancellationToken): ProviderResult<InlineValue[]>;
351 > }
352 >
353 > export const enum CompletionItemKind {
354 > Method,
355 > Function,
356 > Constructor,
357 > Field,
358 > Variable,
359 > Class,
360 > Struct,
361 > Interface,
362 > Module,
363 > Property,
364 > Event,
365 > Operator,
366 > Unit,
367 > Value,
368 > Constant,
369 > Enum,
370 > EnumMember,
371 > Keyword,
372 > Text,
373 > Color,
374 > File,
375 > Reference,
376 > Customcolor,
377 > Folder,
378 > TypeParameter,
379 > User,
380 > Issue,
381 > Tool,
382 > Snippet, // <- highest value (used for compare!)
383 > }
384 >
385 > /**
386 > * @internal
387 > */
388 > export namespace CompletionItemKinds {
389 >
390 > const byKind = new Map<CompletionItemKind, ThemeIcon>();
391 > byKind.set(CompletionItemKind.Method, Codicon.symbolMethod);
392 > byKind.set(CompletionItemKind.Function, Codicon.symbolFunction);
393 > byKind.set(CompletionItemKind.Constructor, Codicon.symbolConstructor);
394 > byKind.set(CompletionItemKind.Field, Codicon.symbolField);
395 > byKind.set(CompletionItemKind.Variable, Codicon.symbolVariable);
396 > byKind.set(CompletionItemKind.Class, Codicon.symbolClass);
397 > byKind.set(CompletionItemKind.Struct, Codicon.symbolStruct);
398 > byKind.set(CompletionItemKind.Interface, Codicon.symbolInterface);
399 > byKind.set(CompletionItemKind.Module, Codicon.symbolModule);
400 > byKind.set(CompletionItemKind.Property, Codicon.symbolProperty);
401 > byKind.set(CompletionItemKind.Event, Codicon.symbolEvent);
402 > byKind.set(CompletionItemKind.Operator, Codicon.symbolOperator);
403 > byKind.set(CompletionItemKind.Unit, Codicon.symbolUnit);
404 > byKind.set(CompletionItemKind.Value, Codicon.symbolValue);
405 > byKind.set(CompletionItemKind.Enum, Codicon.symbolEnum);
406 > byKind.set(CompletionItemKind.Constant, Codicon.symbolConstant);
407 > byKind.set(CompletionItemKind.EnumMember, Codicon.symbolEnumMember);
408 > byKind.set(CompletionItemKind.Keyword, Codicon.symbolKeyword);
409 > byKind.set(CompletionItemKind.Snippet, Codicon.symbolSnippet);
410 > byKind.set(CompletionItemKind.Text, Codicon.symbolText);
411 > byKind.set(CompletionItemKind.Color, Codicon.symbolColor);
412 > byKind.set(CompletionItemKind.File, Codicon.symbolFile);
413 > byKind.set(CompletionItemKind.Reference, Codicon.symbolReference);
414 > byKind.set(CompletionItemKind.Customcolor, Codicon.symbolCustomColor);
415 > byKind.set(CompletionItemKind.Folder, Codicon.symbolFolder);
416 > byKind.set(CompletionItemKind.TypeParameter, Codicon.symbolTypeParameter);
417 > byKind.set(CompletionItemKind.User, Codicon.account);
418 > byKind.set(CompletionItemKind.Issue, Codicon.issues);
419 > byKind.set(CompletionItemKind.Tool, Codicon.tools);
420 >
421 > /**
422 > * @internal
423 > */
424 > export function toIcon(kind: CompletionItemKind): ThemeIcon {
425 let codicon = byKind.get(kind);
426 if (!codicon) {
430 return codicon;
431 }
432 > languages.ts
433 > /**
434 > * @internal
435 > */
436 > export function toLabel(kind: CompletionItemKind): string {
437 switch (kind) {
438 case CompletionItemKind.Method: return localize('suggestWidget.kind.method', 'Method');
468 }
469 }
470 > languages.ts
471 > const data = new Map<string, CompletionItemKind>();
472 > data.set('method', CompletionItemKind.Method);
473 > data.set('function', CompletionItemKind.Function);
474 > data.set('constructor', CompletionItemKind.Constructor);
475 > data.set('field', CompletionItemKind.Field);
476 > data.set('variable', CompletionItemKind.Variable);
477 > data.set('class', CompletionItemKind.Class);
478 > data.set('struct', CompletionItemKind.Struct);
479 > data.set('interface', CompletionItemKind.Interface);
480 > data.set('module', CompletionItemKind.Module);
481 > data.set('property', CompletionItemKind.Property);
482 > data.set('event', CompletionItemKind.Event);
483 > data.set('operator', CompletionItemKind.Operator);
484 > data.set('unit', CompletionItemKind.Unit);
485 > data.set('value', CompletionItemKind.Value);
486 > data.set('constant', CompletionItemKind.Constant);
487 > data.set('enum', CompletionItemKind.Enum);
488 > data.set('enum-member', CompletionItemKind.EnumMember);
489 > data.set('enumMember', CompletionItemKind.EnumMember);
490 > data.set('keyword', CompletionItemKind.Keyword);
491 > data.set('snippet', CompletionItemKind.Snippet);
492 > data.set('text', CompletionItemKind.Text);
493 > data.set('color', CompletionItemKind.Color);
494 > data.set('file', CompletionItemKind.File);
495 > data.set('reference', CompletionItemKind.Reference);
496 > data.set('customcolor', CompletionItemKind.Customcolor);
497 > data.set('folder', CompletionItemKind.Folder);
498 > data.set('type-parameter', CompletionItemKind.TypeParameter);
499 > data.set('typeParameter', CompletionItemKind.TypeParameter);
500 > data.set('account', CompletionItemKind.User);
501 > data.set('issue', CompletionItemKind.Issue);
502 > data.set('tool', CompletionItemKind.Tool);
503 >
504 > /**
505 > * @internal
506 > */
507 > export function fromString(value: string): CompletionItemKind;
508 > /**
509 > * @internal
510 > */
511 > export function fromString(value: string, strict: true): CompletionItemKind | undefined;
512 > /**
513 > * @internal
514 > */
515 > export function fromString(value: string, strict?: boolean): CompletionItemKind | undefined {
516 let res = data.get(value);
517 if (typeof res === 'undefined' && !strict) {
520 return res;
521 }
522 > } languages.ts
523 >
524 > export interface CompletionItemLabel {
525 > label: string;
526 > detail?: string;
527 > description?: string;
528 > }
529 >
530 > export const enum CompletionItemTag {
531 > Deprecated = 1
532 > }
533 >
534 > export const enum CompletionItemInsertTextRule {
535 > None = 0,
536 >
537 > /**
538 > * Adjust whitespace/indentation of multiline insert texts to
539 > * match the current line indentation.
540 > */
541 > KeepWhitespace = 0b001,
542 >
543 > /**
544 > * `insertText` is a snippet.
545 > */
546 > InsertAsSnippet = 0b100,
547 > }
548 >
549 > export interface CompletionItemRanges {
550 > insert: IRange;
551 > replace: IRange;
552 > }
553 >
554 > /**
555 > * A completion item represents a text snippet that is
556 > * proposed to complete text that is being typed.
557 > */
558 > export interface CompletionItem {
559 > /**
560 > * The label of this completion item. By default
561 > * this is also the text that is inserted when selecting
562 > * this completion.
563 > */
564 > label: string | CompletionItemLabel;
565 > /**
566 > * The kind of this completion item. Based on the kind
567 > * an icon is chosen by the editor.
568 > */
569 > kind: CompletionItemKind;
570 > /**
571 > * A modifier to the `kind` which affect how the item
572 > * is rendered, e.g. Deprecated is rendered with a strikeout
573 > */
574 > tags?: ReadonlyArray<CompletionItemTag>;
575 > /**
576 > * A human-readable string with additional information
577 > * about this item, like type or symbol information.
578 > */
579 > detail?: string;
580 > /**
581 > * A human-readable string that represents a doc-comment.
582 > */
583 > documentation?: string | IMarkdownString;
584 > /**
585 > * A string that should be used when comparing this item
586 > * with other items. When `falsy` the {@link CompletionItem.label label}
587 > * is used.
588 > */
589 > sortText?: string;
590 > /**
591 > * A string that should be used when filtering a set of
592 > * completion items. When `falsy` the {@link CompletionItem.label label}
593 > * is used.
594 > */
595 > filterText?: string;
596 > /**
597 > * Select this item when showing. *Note* that only one completion item can be selected and
598 > * that the editor decides which item that is. The rule is that the *first* item of those
599 > * that match best is selected.
600 > */
601 > preselect?: boolean;
602 > /**
603 > * A string or snippet that should be inserted in a document when selecting
604 > * this completion.
605 > */
606 > insertText: string;
607 > /**
608 > * Additional rules (as bitmask) that should be applied when inserting
609 > * this completion.
610 > */
611 > insertTextRules?: CompletionItemInsertTextRule;
612 > /**
613 > * A range of text that should be replaced by this completion item.
614 > *
615 > * *Note:* The range must be a {@link Range.isSingleLine single line} and it must
616 > * {@link Range.contains contain} the position at which completion has been {@link CompletionItemProvider.provideCompletionItems requested}.
617 > */
618 > range: IRange | CompletionItemRanges;
619 > /**
620 > * An optional set of characters that when pressed while this completion is active will accept it first and
621 > * then type that character. *Note* that all commit characters should have `length=1` and that superfluous
622 > * characters will be ignored.
623 > */
624 > commitCharacters?: string[];
625 > /**
626 > * An optional array of additional text edits that are applied when
627 > * selecting this completion. Edits must not overlap with the main edit
628 > * nor with themselves.
629 > */
630 > additionalTextEdits?: ISingleEditOperation[];
631 > /**
632 > * A command that should be run upon acceptance of this item.
633 > */
634 > command?: Command;
635 > /**
636 > * A command that should be run upon acceptance of this item.
637 > */
638 > action?: Command;
639 > /**
640 > * @internal
641 > */
642 > extensionId?: ExtensionIdentifier;
643 >
644 > /**
645 > * @internal
646 > */
647 > _id?: [number, number];
648 > }
649 >
650 > export interface CompletionList {
651 > suggestions: CompletionItem[];
652 > incomplete?: boolean;
653 > dispose?(): void;
654 >
655 > /**
656 > * @internal
657 > */
658 > duration?: number;
659 > }
660 >
661 > /**
662 > * Info provided on partial acceptance.
663 > */
664 > export interface PartialAcceptInfo {
665 > kind: PartialAcceptTriggerKind;
666 > acceptedLength: number;
667 > }
668 >
669 > /**
670 > * How a partial acceptance was triggered.
671 > */
672 > export const enum PartialAcceptTriggerKind {
673 > Word = 0,
674 > Line = 1,
675 > Suggest = 2,
676 > }
677 >
678 > /**
679 > * How a suggest provider was triggered.
680 > */
681 > export const enum CompletionTriggerKind {
682 > Invoke = 0,
683 > TriggerCharacter = 1,
684 > TriggerForIncompleteCompletions = 2
685 > }
686 > /**
687 > * Contains additional information about the context in which
688 > * {@link CompletionItemProvider.provideCompletionItems completion provider} is triggered.
689 > */
690 > export interface CompletionContext {
691 > /**
692 > * How the completion was triggered.
693 > */
694 > triggerKind: CompletionTriggerKind;
695 > /**
696 > * Character that triggered the completion item provider.
697 > *
698 > * `undefined` if provider was not triggered by a character.
699 > */
700 > triggerCharacter?: string;
701 > }
702 > /**
703 > * The completion item provider interface defines the contract between extensions and
704 > * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense).
705 > *
706 > * When computing *complete* completion items is expensive, providers can optionally implement
707 > * the `resolveCompletionItem`-function. In that case it is enough to return completion
708 > * items with a {@link CompletionItem.label label} from the
709 > * {@link CompletionItemProvider.provideCompletionItems provideCompletionItems}-function. Subsequently,
710 > * when a completion item is shown in the UI and gains focus this provider is asked to resolve
711 > * the item, like adding {@link CompletionItem.documentation doc-comment} or {@link CompletionItem.detail details}.
712 > */
713 > export interface CompletionItemProvider {
714 >
715 > /**
716 > * Used to identify completions in the (debug) UI and telemetry. This isn't the extension identifier because extensions
717 > * often contribute multiple completion item providers.
718 > *
719 > * @internal
720 > */
721 > _debugDisplayName: string;
722 >
723 > triggerCharacters?: string[];
724 > /**
725 > * Provide completion items for the given position and document.
726 > */
727 > provideCompletionItems(model: model.ITextModel, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult<CompletionList>;
728 >
729 > /**
730 > * Given a completion item fill in more data, like {@link CompletionItem.documentation doc-comment}
731 > * or {@link CompletionItem.detail details}.
732 > *
733 > * The editor will only resolve a completion item once.
734 > */
735 > resolveCompletionItem?(item: CompletionItem, token: CancellationToken): ProviderResult<CompletionItem>;
736 > }
737 >
738 > /**
739 > * How an {@link InlineCompletionsProvider inline completion provider} was triggered.
740 > */
741 > export enum InlineCompletionTriggerKind {
742 > /**
743 > * Completion was triggered automatically while editing.
744 > * It is sufficient to return a single completion item in this case.
745 > */
746 > Automatic = 0,
747 >
748 > /**
749 > * Completion was triggered explicitly by a user gesture.
750 > * Return multiple completion items to enable cycling through them.
751 > */
752 > Explicit = 1,
753 > }
754 >
755 > /**
756 > * Arbitrary data that the provider can pass when firing {@link InlineCompletionsProvider.onDidChangeInlineCompletions}.
757 > * This data is passed back to the provider in {@link InlineCompletionContext.changeHint}.
758 > */
759 > export interface IInlineCompletionChangeHint {
760 > /**
761 > * Arbitrary data that the provider can use to identify what triggered the change.
762 > * This data must be JSON serializable.
763 > */
764 > readonly data?: unknown;
765 > }
766 >
767 > export interface InlineCompletionContext {
768 >
769 > /**
770 > * How the completion was triggered.
771 > */
772 > readonly triggerKind: InlineCompletionTriggerKind;
773 > readonly selectedSuggestionInfo: SelectedSuggestionInfo | undefined;
774 > /**
775 > * @experimental
776 > * @internal
777 > */
778 > readonly userPrompt?: string | undefined;
779 > /**
780 > * @experimental
781 > * @internal
782 > */
783 > readonly requestUuid: string;
784 >
785 > readonly includeInlineEdits: boolean;
786 > readonly includeInlineCompletions: boolean;
787 > readonly requestIssuedDateTime: number;
788 > readonly earliestShownDateTime: number;
789 >
790 > /**
791 > * The change hint that was passed to {@link InlineCompletionsProvider.onDidChangeInlineCompletions}.
792 > * Only set if this request was triggered by such an event.
793 > */
794 > readonly changeHint?: IInlineCompletionChangeHint;
795 > }
796 >
797 > export interface IInlineCompletionModelInfo {
798 > models: IInlineCompletionModel[];
799 > currentModelId: string;
800 > }
801 >
802 > export interface IInlineCompletionModel {
803 > name: string;
804 > id: string;
805 > }
806 >
807 > export interface IInlineCompletionProviderOption {
808 > readonly id: string;
809 > readonly label: string;
810 > readonly values: readonly IInlineCompletionProviderOptionValue[];
811 > readonly currentValueId: string;
812 > }
813 >
814 > export interface IInlineCompletionProviderOptionValue {
815 > readonly id: string;
816 > readonly label: string;
817 > }
818 >
819 > export class SelectedSuggestionInfo {
820 > constructor(
821 public readonly range: IRange,
822 public readonly text: string,
825 ) {
826 }
827 > languages.ts
828 > public equals(other: SelectedSuggestionInfo): boolean {
829 return Range.lift(this.range).equalsRange(other.range)
830 && this.text === other.text
832 && this.isSnippetText === other.isSnippetText;
833 }
834 > } languages.ts
835 >
836 > export interface InlineCompletion {
837 > /**
838 > * The text to insert.
839 > * If the text contains a line break, the range must end at the end of a line.
840 > * If existing text should be replaced, the existing text must be a prefix of the text to insert.
841 > *
842 > * The text can also be a snippet. In that case, a preview with default parameters is shown.
843 > * When accepting the suggestion, the full snippet is inserted.
844 > */
845 > readonly insertText: string | { snippet: string } | undefined;
846 >
847 > /**
848 > * The range to replace.
849 > * Must begin and end on the same line.
850 > * Refers to the current document or `uri` if provided.
851 > */
852 > readonly range?: IRange;
853 >
854 > /**
855 > * An optional array of additional text edits that are applied when
856 > * selecting this completion. Edits must not overlap with the main edit
857 > * nor with themselves.
858 > * Refers to the current document or `uri` if provided.
859 > */
860 > readonly additionalTextEdits?: ISingleEditOperation[];
861 >
862 > /**
863 > * The file for which the edit applies to.
864 > */
865 > readonly uri?: UriComponents;
866 >
867 > /**
868 > * A command that is run upon acceptance of this item.
869 > */
870 > readonly command?: Command;
871 >
872 > readonly gutterMenuLinkAction?: Command;
873 >
874 > /**
875 > * Is called the first time an inline completion is shown.
876 > * @deprecated. Use `onDidShow` of the provider instead.
877 > */
878 > readonly shownCommand?: Command;
879 >
880 > /**
881 > * If set to `true`, unopened closing brackets are removed and unclosed opening brackets are closed.
882 > * Defaults to `false`.
883 > */
884 > readonly completeBracketPairs?: boolean;
885 >
886 > readonly isInlineEdit?: boolean;
887 > readonly showInlineEditMenu?: boolean;
888 >
889 > /** Only show the inline suggestion when the cursor is in the showRange. */
890 > readonly showRange?: IRange;
891 >
892 > readonly warning?: InlineCompletionWarning;
893 >
894 > readonly hint?: IInlineCompletionHint;
895 >
896 > readonly supportsRename?: boolean;
897 >
898 > /**
899 > * Used for telemetry.
900 > */
901 > readonly correlationId?: string | undefined;
902 >
903 > readonly jumpToPosition?: IPosition;
904 >
905 > readonly doNotLog?: boolean;
906 > }
907 >
908 > export interface InlineCompletionWarning {
909 > message: IMarkdownString | string;
910 > icon?: IconPath;
911 > }
912 >
913 > export enum InlineCompletionHintStyle {
914 > Code = 1,
915 > Label = 2
916 > }
917 >
918 > export interface IInlineCompletionHint {
919 > /** Refers to the current document. */
920 > range: IRange;
921 > style: InlineCompletionHintStyle;
922 > content: string;
923 > }
924 >
925 > // TODO: add `| URI | { light: URI; dark: URI }`.
926 > export type IconPath = ThemeIcon;
927 >
928 > export interface InlineCompletions<TItem extends InlineCompletion = InlineCompletion> {
929 > readonly items: readonly TItem[];
930 > /**
931 > * A list of commands associated with the inline completions of this list.
932 > */
933 > readonly commands?: InlineCompletionCommand[];
934 >
935 > readonly suppressSuggestions?: boolean | undefined;
936 >
937 > /**
938 > * When set and the user types a suggestion without derivating from it, the inline suggestion is not updated.
939 > */
940 > readonly enableForwardStability?: boolean | undefined;
941 > }
942 >
943 > export type InlineCompletionCommand = { command: Command; icon?: ThemeIcon };
944 >
945 > export type InlineCompletionProviderGroupId = string;
946 >
947 > export interface InlineCompletionsProvider<T extends InlineCompletions = InlineCompletions> {
948 > provideInlineCompletions(model: model.ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult<T>;
949 >
950 > /**
951 > * Will be called when an item is shown.
952 > * @param updatedInsertText Is useful to understand bracket completion.
953 > */
954 > handleItemDidShow?(completions: T, item: T['items'][number], updatedInsertText: string, editDeltaInfo: EditDeltaInfo): void;
955 >
956 > /**
957 > * Will be called when an item is partially accepted. TODO: also handle full acceptance here!
958 > * @param acceptedCharacters Deprecated. Use `info.acceptedCharacters` instead.
959 > */
960 > handlePartialAccept?(completions: T, item: T['items'][number], acceptedCharacters: number, info: PartialAcceptInfo): void;
961 >
962 > /**
963 > * @deprecated Use `handleEndOfLifetime` instead.
964 > */
965 > handleRejection?(completions: T, item: T['items'][number]): void;
966 >
967 > /**
968 > * Is called when an inline completion item is no longer being used.
969 > * Provides a reason of why it is not used anymore.
970 > */
971 > handleEndOfLifetime?(completions: T, item: T['items'][number], reason: InlineCompletionEndOfLifeReason<T['items'][number]>, lifetimeSummary: LifetimeSummary): void;
972 >
973 > /**
974 > * Will be called when a completions list is no longer in use and can be garbage-collected.
975 > */
976 > disposeInlineCompletions(completions: T, reason: InlineCompletionsDisposeReason): void;
977 >
978 > /**
979 > * Fired when the provider wants to trigger a new completion request.
980 > * The event can pass a {@link IInlineCompletionChangeHint} which will be
981 > * included in the {@link InlineCompletionContext} of the subsequent request.
982 > */
983 > onDidChangeInlineCompletions?: Event<IInlineCompletionChangeHint | void>;
984 >
985 > /**
986 > * Only used for {@link yieldsToGroupIds}.
987 > * Multiple providers can have the same group id.
988 > */
989 > groupId?: InlineCompletionProviderGroupId;
990 >
991 > /** @internal */
992 > providerId?: ProviderId;
993 >
994 > /**
995 > * Returns a list of preferred provider {@link groupId}s.
996 > * The current provider is only requested for completions if no provider with a preferred group id returned a result.
997 > */
998 > yieldsToGroupIds?: InlineCompletionProviderGroupId[];
999 >
1000 > excludesGroupIds?: InlineCompletionProviderGroupId[];
1001 >
1002 > displayName?: string;
1003 >
1004 > debounceDelayMs?: number;
1005 >
1006 > modelInfo?: IInlineCompletionModelInfo;
1007 > onDidModelInfoChange?: Event<void>;
1008 > setModelId?(modelId: string): Promise<void>;
1009 >
1010 > providerOptions?: readonly IInlineCompletionProviderOption[];
1011 > onDidProviderOptionsChange?: Event<void>;
1012 > setProviderOption?(optionId: string, valueId: string): Promise<void>;
1013 >
1014 > toString?(): string;
1015 > }
1016 >
1017 >
1018 > /** @internal */
1019 > export class ProviderId {
1020 > public static fromExtensionId(extensionId: string | undefined): ProviderId {
1021 > return new ProviderId(extensionId, undefined, undefined);
1022 > }
1023 >
1024 > constructor(
1025 public readonly extensionId: string | undefined,
1026 public readonly extensionVersion: string | undefined,
1028 ) {
1029 }
1030 > languages.ts
1031 > toString(): string {
1032 let result = '';
1033 if (this.extensionId) {
1045 return result;
1046 }
1047 > languages.ts
1048 > toStringWithoutVersion(): string {
1049 let result = '';
1050 if (this.extensionId) {
1056 return result;
1057 }
1058 > } languages.ts
1059 >
1060 > /** @internal */
1061 > export class VersionedExtensionId {
1062 > public static tryCreate(extensionId: string | undefined, version: string | undefined): VersionedExtensionId | undefined {
1063 > if (!extensionId || !version) {
1064 > return undefined;
1065 > }
1066 > return new VersionedExtensionId(extensionId, version);
1067 > }
1068 >
1069 > constructor(
1070 public readonly extensionId: string,
1071 public readonly version: string,
1072 ) { }
1073 > languages.ts
1074 > toString(): string {
1075 return `${this.extensionId}@${this.version}`;
1076 }
1077 > } languages.ts
1078 >
1079 > export type InlineCompletionsDisposeReason = { kind: 'lostRace' | 'tokenCancellation' | 'other' | 'empty' | 'notTaken' };
1080 >
1081 > export enum InlineCompletionEndOfLifeReasonKind {
1082 > Accepted = 0,
1083 > Rejected = 1,
1084 > Ignored = 2,
1085 > }
1086 >
1087 > export type InlineCompletionEndOfLifeReason<TInlineCompletion = InlineCompletion> = {
1088 > kind: InlineCompletionEndOfLifeReasonKind.Accepted; // User did an explicit action to accept
1089 > alternativeAction: boolean; // Whether the user performed an alternative action.
1090 > } | {
1091 > kind: InlineCompletionEndOfLifeReasonKind.Rejected; // User did an explicit action to reject
1092 > } | {
1093 > kind: InlineCompletionEndOfLifeReasonKind.Ignored;
1094 > supersededBy?: TInlineCompletion;
1095 > userTypingDisagreed: boolean;
1096 > };
1097 >
1098 > export type LifetimeSummary = {
1099 > requestUuid: string;
1100 > correlationId: string | undefined;
1101 > partiallyAccepted: number;
1102 > partiallyAcceptedCountSinceOriginal: number;
1103 > partiallyAcceptedRatioSinceOriginal: number;
1104 > partiallyAcceptedCharactersSinceOriginal: number;
1105 > shown: boolean;
1106 > shownDuration: number;
1107 > shownDurationUncollapsed: number;
1108 > timeUntilShown: number | undefined;
1109 > timeUntilActuallyShown: number | undefined;
1110 > timeUntilProviderRequest: number;
1111 > timeUntilProviderResponse: number;
1112 > notShownReason: string | undefined;
1113 > editorType: string;
1114 > viewKind: string | undefined;
1115 > preceeded: boolean;
1116 > languageId: string;
1117 > requestReason: string;
1118 > performanceMarkers?: string;
1119 > cursorColumnDistance?: number;
1120 > cursorLineDistance?: number;
1121 > lineCountOriginal?: number;
1122 > lineCountModified?: number;
1123 > characterCountOriginal?: number;
1124 > characterCountModified?: number;
1125 > disjointReplacements?: number;
1126 > sameShapeReplacements?: boolean;
1127 > typingInterval: number;
1128 > typingIntervalCharacterCount: number;
1129 > selectedSuggestionInfo: boolean;
1130 > availableProviders: string;
1131 > skuPlan: string | undefined;
1132 > skuType: string | undefined;
1133 > renameCreated: boolean | undefined;
1134 > renameDuration: number | undefined;
1135 > renameTimedOut: boolean | undefined;
1136 > renameDroppedOtherEdits: number | undefined;
1137 > renameDroppedRenameEdits: number | undefined;
1138 > editKind: string | undefined;
1139 > longDistanceHintVisible?: boolean;
1140 > longDistanceHintDistance?: number;
1141 > isForAnotherDocument?: boolean;
1142 > };
1143 >
1144 > export interface CodeAction {
1145 > title: string;
1146 > command?: Command;
1147 > edit?: WorkspaceEdit;
1148 > diagnostics?: IMarkerData[];
1149 > kind?: string;
1150 > isPreferred?: boolean;
1151 > isAI?: boolean;
1152 > disabled?: string;
1153 > ranges?: IRange[];
1154 > }
1155 >
1156 > export const enum CodeActionTriggerType {
1157 > Invoke = 1,
1158 > Auto = 2,
1159 > }
1160 >
1161 > /**
1162 > * @internal
1163 > */
1164 > export interface CodeActionContext {
1165 > only?: string;
1166 > trigger: CodeActionTriggerType;
1167 > }
1168 >
1169 > export interface CodeActionList extends IDisposable {
1170 > readonly actions: ReadonlyArray<CodeAction>;
1171 > }
1172 >
1173 > /**
1174 > * The code action interface defines the contract between extensions and
1175 > * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature.
1176 > * @internal
1177 > */
1178 > export interface CodeActionProvider {
1179 >
1180 > displayName?: string;
1181 >
1182 > extensionId?: string;
1183 >
1184 > /**
1185 > * Provide commands for the given document and range.
1186 > */
1187 > provideCodeActions(model: model.ITextModel, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult<CodeActionList>;
1188 >
1189 > /**
1190 > * Given a code action fill in the edit. Will only invoked when missing.
1191 > */
1192 > resolveCodeAction?(codeAction: CodeAction, token: CancellationToken): ProviderResult<CodeAction>;
1193 >
1194 > /**
1195 > * Optional list of CodeActionKinds that this provider returns.
1196 > */
1197 > readonly providedCodeActionKinds?: ReadonlyArray<string>;
1198 >
1199 > readonly documentation?: ReadonlyArray<{ readonly kind: string; readonly command: Command }>;
1200 >
1201 > /**
1202 > * @internal
1203 > */
1204 > _getAdditionalMenuItems?(context: CodeActionContext, actions: readonly CodeAction[]): Command[];
1205 > }
1206 >
1207 > /**
1208 > * @internal
1209 > */
1210 > export interface DocumentPasteEdit {
1211 > readonly title: string;
1212 > readonly kind: HierarchicalKind;
1213 > readonly handledMimeType?: string;
1214 > yieldTo?: readonly DropYieldTo[];
1215 > insertText: string | { readonly snippet: string };
1216 > additionalEdit?: WorkspaceEdit;
1217 > }
1218 >
1219 > /**
1220 > * @internal
1221 > */
1222 > export enum DocumentPasteTriggerKind {
1223 > Automatic = 0,
1224 > PasteAs = 1,
1225 > }
1226 >
1227 > /**
1228 > * @internal
1229 > */
1230 > export interface DocumentPasteContext {
1231 > readonly only?: HierarchicalKind;
1232 > readonly triggerKind: DocumentPasteTriggerKind;
1233 > }
1234 >
1235 > /**
1236 > * @internal
1237 > */
1238 > export interface DocumentPasteEditsSession {
1239 > edits: readonly DocumentPasteEdit[];
1240 > dispose(): void;
1241 > }
1242 >
1243 > /**
1244 > * @internal
1245 > */
1246 > export interface DocumentPasteEditProvider {
1247 > readonly id?: string;
1248 > readonly copyMimeTypes: readonly string[];
1249 > readonly pasteMimeTypes: readonly string[];
1250 > readonly providedPasteEditKinds: readonly HierarchicalKind[];
1251 >
1252 > prepareDocumentPaste?(model: model.ITextModel, ranges: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<undefined | IReadonlyVSDataTransfer>;
1253 >
1254 > provideDocumentPasteEdits?(model: model.ITextModel, ranges: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, context: DocumentPasteContext, token: CancellationToken): Promise<DocumentPasteEditsSession | undefined>;
1255 >
1256 > resolveDocumentPasteEdit?(edit: DocumentPasteEdit, token: CancellationToken): Promise<DocumentPasteEdit>;
1257 > }
1258 >
1259 > /**
1260 > * Represents a parameter of a callable-signature. A parameter can
1261 > * have a label and a doc-comment.
1262 > */
1263 > export interface ParameterInformation {
1264 > /**
1265 > * The label of this signature. Will be shown in
1266 > * the UI.
1267 > */
1268 > label: string | [number, number];
1269 > /**
1270 > * The human-readable doc-comment of this signature. Will be shown
1271 > * in the UI but can be omitted.
1272 > */
1273 > documentation?: string | IMarkdownString;
1274 > }
1275 > /**
1276 > * Represents the signature of something callable. A signature
1277 > * can have a label, like a function-name, a doc-comment, and
1278 > * a set of parameters.
1279 > */
1280 > export interface SignatureInformation {
1281 > /**
1282 > * The label of this signature. Will be shown in
1283 > * the UI.
1284 > */
1285 > label: string;
1286 > /**
1287 > * The human-readable doc-comment of this signature. Will be shown
1288 > * in the UI but can be omitted.
1289 > */
1290 > documentation?: string | IMarkdownString;
1291 > /**
1292 > * The parameters of this signature.
1293 > */
1294 > parameters: ParameterInformation[];
1295 > /**
1296 > * Index of the active parameter.
1297 > *
1298 > * If provided, this is used in place of `SignatureHelp.activeSignature`.
1299 > */
1300 > activeParameter?: number;
1301 > }
1302 > /**
1303 > * Signature help represents the signature of something
1304 > * callable. There can be multiple signatures but only one
1305 > * active and only one active parameter.
1306 > */
1307 > export interface SignatureHelp {
1308 > /**
1309 > * One or more signatures.
1310 > */
1311 > signatures: SignatureInformation[];
1312 > /**
1313 > * The active signature.
1314 > */
1315 > activeSignature: number;
1316 > /**
1317 > * The active parameter of the active signature.
1318 > */
1319 > activeParameter: number;
1320 > }
1321 >
1322 > export interface SignatureHelpResult extends IDisposable {
1323 > value: SignatureHelp;
1324 > }
1325 >
1326 > export enum SignatureHelpTriggerKind {
1327 > Invoke = 1,
1328 > TriggerCharacter = 2,
1329 > ContentChange = 3,
1330 > }
1331 >
1332 > export interface SignatureHelpContext {
1333 > readonly triggerKind: SignatureHelpTriggerKind;
1334 > readonly triggerCharacter?: string;
1335 > readonly isRetrigger: boolean;
1336 > readonly activeSignatureHelp?: SignatureHelp;
1337 > }
1338 >
1339 > /**
1340 > * The signature help provider interface defines the contract between extensions and
1341 > * the [parameter hints](https://code.visualstudio.com/docs/editor/intellisense)-feature.
1342 > */
1343 > export interface SignatureHelpProvider {
1344 >
1345 > readonly signatureHelpTriggerCharacters?: ReadonlyArray<string>;
1346 > readonly signatureHelpRetriggerCharacters?: ReadonlyArray<string>;
1347 >
1348 > /**
1349 > * Provide help for the signature at the given position and document.
1350 > */
1351 > provideSignatureHelp(model: model.ITextModel, position: Position, token: CancellationToken, context: SignatureHelpContext): ProviderResult<SignatureHelpResult>;
1352 > }
1353 >
1354 > /**
1355 > * A document highlight kind.
1356 > */
1357 > export enum DocumentHighlightKind {
1358 > /**
1359 > * A textual occurrence.
1360 > */
1361 > Text,
1362 > /**
1363 > * Read-access of a symbol, like reading a variable.
1364 > */
1365 > Read,
1366 > /**
1367 > * Write-access of a symbol, like writing to a variable.
1368 > */
1369 > Write
1370 > }
1371 > /**
1372 > * A document highlight is a range inside a text document which deserves
1373 > * special attention. Usually a document highlight is visualized by changing
1374 > * the background color of its range.
1375 > */
1376 > export interface DocumentHighlight {
1377 > /**
1378 > * The range this highlight applies to.
1379 > */
1380 > range: IRange;
1381 > /**
1382 > * The highlight kind, default is {@link DocumentHighlightKind.Text text}.
1383 > */
1384 > kind?: DocumentHighlightKind;
1385 > }
1386 >
1387 > /**
1388 > * Represents a set of document highlights for a specific URI.
1389 > */
1390 > export interface MultiDocumentHighlight {
1391 > /**
1392 > * The URI of the document that the highlights belong to.
1393 > */
1394 > uri: URI;
1395 >
1396 > /**
1397 > * The set of highlights for the document.
1398 > */
1399 > highlights: DocumentHighlight[];
1400 > }
1401 >
1402 > /**
1403 > * The document highlight provider interface defines the contract between extensions and
1404 > * the word-highlight-feature.
1405 > */
1406 > export interface DocumentHighlightProvider {
1407 > /**
1408 > * Provide a set of document highlights, like all occurrences of a variable or
1409 > * all exit-points of a function.
1410 > */
1411 > provideDocumentHighlights(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<DocumentHighlight[]>;
1412 > }
1413 >
1414 > /**
1415 > * A provider that can provide document highlights across multiple documents.
1416 > */
1417 > export interface MultiDocumentHighlightProvider {
1418 > readonly selector: LanguageSelector;
1419 >
1420 > /**
1421 > * Provide a Map of URI --> document highlights, like all occurrences of a variable or
1422 > * all exit-points of a function.
1423 > *
1424 > * Used in cases such as split view, notebooks, etc. where there can be multiple documents
1425 > * with shared symbols.
1426 > *
1427 > * @param primaryModel The primary text model.
1428 > * @param position The position at which to provide document highlights.
1429 > * @param otherModels The other text models to search for document highlights.
1430 > * @param token A cancellation token.
1431 > * @returns A map of URI to document highlights.
1432 > */
1433 > provideMultiDocumentHighlights(primaryModel: model.ITextModel, position: Position, otherModels: model.ITextModel[], token: CancellationToken): ProviderResult<Map<URI, DocumentHighlight[]>>;
1434 > }
1435 >
1436 > /**
1437 > * The linked editing range provider interface defines the contract between extensions and
1438 > * the linked editing feature.
1439 > */
1440 > export interface LinkedEditingRangeProvider {
1441 >
1442 > /**
1443 > * Provide a list of ranges that can be edited together.
1444 > */
1445 > provideLinkedEditingRanges(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<LinkedEditingRanges>;
1446 > }
1447 >
1448 > /**
1449 > * Represents a list of ranges that can be edited together along with a word pattern to describe valid contents.
1450 > */
1451 > export interface LinkedEditingRanges {
1452 > /**
1453 > * A list of ranges that can be edited together. The ranges must have
1454 > * identical length and text content. The ranges cannot overlap
1455 > */
1456 > ranges: IRange[];
1457 >
1458 > /**
1459 > * An optional word pattern that describes valid contents for the given ranges.
1460 > * If no pattern is provided, the language configuration's word pattern will be used.
1461 > */
1462 > wordPattern?: RegExp;
1463 > }
1464 >
1465 > /**
1466 > * Value-object that contains additional information when
1467 > * requesting references.
1468 > */
1469 > export interface ReferenceContext {
1470 > /**
1471 > * Include the declaration of the current symbol.
1472 > */
1473 > includeDeclaration: boolean;
1474 > }
1475 > /**
1476 > * The reference provider interface defines the contract between extensions and
1477 > * the [find references](https://code.visualstudio.com/docs/editor/editingevolved#_peek)-feature.
1478 > */
1479 > export interface ReferenceProvider {
1480 > /**
1481 > * Provide a set of project-wide references for the given position and document.
1482 > */
1483 > provideReferences(model: model.ITextModel, position: Position, context: ReferenceContext, token: CancellationToken): ProviderResult<Location[]>;
1484 > }
1485 >
1486 > /**
1487 > * Represents a location inside a resource, such as a line
1488 > * inside a text file.
1489 > */
1490 > export interface Location {
1491 > /**
1492 > * The resource identifier of this location.
1493 > */
1494 > uri: URI;
1495 > /**
1496 > * The document range of this locations.
1497 > */
1498 > range: IRange;
1499 > }
1500 >
1501 > export interface LocationLink {
1502 > /**
1503 > * A range to select where this link originates from.
1504 > */
1505 > originSelectionRange?: IRange;
1506 >
1507 > /**
1508 > * The target uri this link points to.
1509 > */
1510 > uri: URI;
1511 >
1512 > /**
1513 > * The full range this link points to.
1514 > */
1515 > range: IRange;
1516 >
1517 > /**
1518 > * A range to select this link points to. Must be contained
1519 > * in `LocationLink.range`.
1520 > */
1521 > targetSelectionRange?: IRange;
1522 > }
1523 >
1524 > /**
1525 > * @internal
1526 > */
1527 > export function isLocationLink(thing: unknown): thing is LocationLink {
1528 return !!thing
1529 && URI.isUri((thing as LocationLink).uri)
1531 && (Range.isIRange((thing as LocationLink).originSelectionRange) || Range.isIRange((thing as LocationLink).targetSelectionRange));
1532 }
1533 > languages.ts
1534 > /**
1535 > * @internal
1536 > */
1537 > export function isLocation(thing: unknown): thing is Location {
1538 return !!thing
1539 && URI.isUri((thing as Location).uri)
1540 && Range.isIRange((thing as Location).range);
1541 }
1542 > languages.ts
1543 >
1544 > export type Definition = Location | Location[] | LocationLink[];
1545 >
1546 > /**
1547 > * The definition provider interface defines the contract between extensions and
1548 > * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition)
1549 > * and peek definition features.
1550 > */
1551 > export interface DefinitionProvider {
1552 > /**
1553 > * Provide the definition of the symbol at the given position and document.
1554 > */
1555 > provideDefinition(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<Definition | LocationLink[]>;
1556 > }
1557 >
1558 > /**
1559 > * The definition provider interface defines the contract between extensions and
1560 > * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition)
1561 > * and peek definition features.
1562 > */
1563 > export interface DeclarationProvider {
1564 > /**
1565 > * Provide the declaration of the symbol at the given position and document.
1566 > */
1567 > provideDeclaration(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<Definition | LocationLink[]>;
1568 > }
1569 >
1570 > /**
1571 > * The implementation provider interface defines the contract between extensions and
1572 > * the go to implementation feature.
1573 > */
1574 > export interface ImplementationProvider {
1575 > /**
1576 > * Provide the implementation of the symbol at the given position and document.
1577 > */
1578 > provideImplementation(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<Definition | LocationLink[]>;
1579 > }
1580 >
1581 > /**
1582 > * The type definition provider interface defines the contract between extensions and
1583 > * the go to type definition feature.
1584 > */
1585 > export interface TypeDefinitionProvider {
1586 > /**
1587 > * Provide the type definition of the symbol at the given position and document.
1588 > */
1589 > provideTypeDefinition(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<Definition | LocationLink[]>;
1590 > }
1591 >
1592 > /**
1593 > * A symbol kind.
1594 > */
1595 > export const enum SymbolKind {
1596 > File = 0,
1597 > Module = 1,
1598 > Namespace = 2,
1599 > Package = 3,
1600 > Class = 4,
1601 > Method = 5,
1602 > Property = 6,
1603 > Field = 7,
1604 > Constructor = 8,
1605 > Enum = 9,
1606 > Interface = 10,
1607 > Function = 11,
1608 > Variable = 12,
1609 > Constant = 13,
1610 > String = 14,
1611 > Number = 15,
1612 > Boolean = 16,
1613 > Array = 17,
1614 > Object = 18,
1615 > Key = 19,
1616 > Null = 20,
1617 > EnumMember = 21,
1618 > Struct = 22,
1619 > Event = 23,
1620 > Operator = 24,
1621 > TypeParameter = 25
1622 > }
1623 >
1624 > /**
1625 > * @internal
1626 > */
1627 > export const symbolKindNames: { [symbol: number]: string } = {
1628 > [SymbolKind.Array]: localize('Array', "array"),
1629 > [SymbolKind.Boolean]: localize('Boolean', "boolean"),
1630 > [SymbolKind.Class]: localize('Class', "class"),
1631 > [SymbolKind.Constant]: localize('Constant', "constant"),
1632 > [SymbolKind.Constructor]: localize('Constructor', "constructor"),
1633 > [SymbolKind.Enum]: localize('Enum', "enumeration"),
1634 > [SymbolKind.EnumMember]: localize('EnumMember', "enumeration member"),
1635 > [SymbolKind.Event]: localize('Event', "event"),
1636 > [SymbolKind.Field]: localize('Field', "field"),
1637 > [SymbolKind.File]: localize('File', "file"),
1638 > [SymbolKind.Function]: localize('Function', "function"),
1639 > [SymbolKind.Interface]: localize('Interface', "interface"),
1640 > [SymbolKind.Key]: localize('Key', "key"),
1641 > [SymbolKind.Method]: localize('Method', "method"),
1642 > [SymbolKind.Module]: localize('Module', "module"),
1643 > [SymbolKind.Namespace]: localize('Namespace', "namespace"),
1644 > [SymbolKind.Null]: localize('Null', "null"),
1645 > [SymbolKind.Number]: localize('Number', "number"),
1646 > [SymbolKind.Object]: localize('Object', "object"),
1647 > [SymbolKind.Operator]: localize('Operator', "operator"),
1648 > [SymbolKind.Package]: localize('Package', "package"),
1649 > [SymbolKind.Property]: localize('Property', "property"),
1650 > [SymbolKind.String]: localize('String', "string"),
1651 > [SymbolKind.Struct]: localize('Struct', "struct"),
1652 > [SymbolKind.TypeParameter]: localize('TypeParameter', "type parameter"),
1653 > [SymbolKind.Variable]: localize('Variable', "variable"),
1654 > };
1655 >
1656 > /**
1657 > * @internal
1658 > */
1659 > export function getAriaLabelForSymbol(symbolName: string, kind: SymbolKind): string {
1660 return localize('symbolAriaLabel', '{0} ({1})', symbolName, symbolKindNames[kind]);
1661 }
1662 > languages.ts
1663 > export const enum SymbolTag {
1664 > Deprecated = 1,
1665 > }
1666 >
1667 > /**
1668 > * @internal
1669 > */
1670 > export namespace SymbolKinds {
1671 >
1672 > const byKind = new Map<SymbolKind, ThemeIcon>();
1673 > byKind.set(SymbolKind.File, Codicon.symbolFile);
1674 > byKind.set(SymbolKind.Module, Codicon.symbolModule);
1675 > byKind.set(SymbolKind.Namespace, Codicon.symbolNamespace);
1676 > byKind.set(SymbolKind.Package, Codicon.symbolPackage);
1677 > byKind.set(SymbolKind.Class, Codicon.symbolClass);
1678 > byKind.set(SymbolKind.Method, Codicon.symbolMethod);
1679 > byKind.set(SymbolKind.Property, Codicon.symbolProperty);
1680 > byKind.set(SymbolKind.Field, Codicon.symbolField);
1681 > byKind.set(SymbolKind.Constructor, Codicon.symbolConstructor);
1682 > byKind.set(SymbolKind.Enum, Codicon.symbolEnum);
1683 > byKind.set(SymbolKind.Interface, Codicon.symbolInterface);
1684 > byKind.set(SymbolKind.Function, Codicon.symbolFunction);
1685 > byKind.set(SymbolKind.Variable, Codicon.symbolVariable);
1686 > byKind.set(SymbolKind.Constant, Codicon.symbolConstant);
1687 > byKind.set(SymbolKind.String, Codicon.symbolString);
1688 > byKind.set(SymbolKind.Number, Codicon.symbolNumber);
1689 > byKind.set(SymbolKind.Boolean, Codicon.symbolBoolean);
1690 > byKind.set(SymbolKind.Array, Codicon.symbolArray);
1691 > byKind.set(SymbolKind.Object, Codicon.symbolObject);
1692 > byKind.set(SymbolKind.Key, Codicon.symbolKey);
1693 > byKind.set(SymbolKind.Null, Codicon.symbolNull);
1694 > byKind.set(SymbolKind.EnumMember, Codicon.symbolEnumMember);
1695 > byKind.set(SymbolKind.Struct, Codicon.symbolStruct);
1696 > byKind.set(SymbolKind.Event, Codicon.symbolEvent);
1697 > byKind.set(SymbolKind.Operator, Codicon.symbolOperator);
1698 > byKind.set(SymbolKind.TypeParameter, Codicon.symbolTypeParameter);
1699 > /**
1700 > * @internal
1701 > */
1702 > export function toIcon(kind: SymbolKind): ThemeIcon {
1703 let icon = byKind.get(kind);
1704 if (!icon) {
1708 return icon;
1709 }
1710 > languages.ts
1711 > const byCompletionKind = new Map<SymbolKind, CompletionItemKind>();
1712 > byCompletionKind.set(SymbolKind.File, CompletionItemKind.File);
1713 > byCompletionKind.set(SymbolKind.Module, CompletionItemKind.Module);
1714 > byCompletionKind.set(SymbolKind.Namespace, CompletionItemKind.Module);
1715 > byCompletionKind.set(SymbolKind.Package, CompletionItemKind.Module);
1716 > byCompletionKind.set(SymbolKind.Class, CompletionItemKind.Class);
1717 > byCompletionKind.set(SymbolKind.Method, CompletionItemKind.Method);
1718 > byCompletionKind.set(SymbolKind.Property, CompletionItemKind.Property);
1719 > byCompletionKind.set(SymbolKind.Field, CompletionItemKind.Field);
1720 > byCompletionKind.set(SymbolKind.Constructor, CompletionItemKind.Constructor);
1721 > byCompletionKind.set(SymbolKind.Enum, CompletionItemKind.Enum);
1722 > byCompletionKind.set(SymbolKind.Interface, CompletionItemKind.Interface);
1723 > byCompletionKind.set(SymbolKind.Function, CompletionItemKind.Function);
1724 > byCompletionKind.set(SymbolKind.Variable, CompletionItemKind.Variable);
1725 > byCompletionKind.set(SymbolKind.Constant, CompletionItemKind.Constant);
1726 > byCompletionKind.set(SymbolKind.String, CompletionItemKind.Text);
1727 > byCompletionKind.set(SymbolKind.Number, CompletionItemKind.Value);
1728 > byCompletionKind.set(SymbolKind.Boolean, CompletionItemKind.Value);
1729 > byCompletionKind.set(SymbolKind.Array, CompletionItemKind.Value);
1730 > byCompletionKind.set(SymbolKind.Object, CompletionItemKind.Value);
1731 > byCompletionKind.set(SymbolKind.Key, CompletionItemKind.Keyword);
1732 > byCompletionKind.set(SymbolKind.Null, CompletionItemKind.Value);
1733 > byCompletionKind.set(SymbolKind.EnumMember, CompletionItemKind.EnumMember);
1734 > byCompletionKind.set(SymbolKind.Struct, CompletionItemKind.Struct);
1735 > byCompletionKind.set(SymbolKind.Event, CompletionItemKind.Event);
1736 > byCompletionKind.set(SymbolKind.Operator, CompletionItemKind.Operator);
1737 > byCompletionKind.set(SymbolKind.TypeParameter, CompletionItemKind.TypeParameter);
1738 > /**
1739 > * @internal
1740 > */
1741 > export function toCompletionKind(kind: SymbolKind): CompletionItemKind {
1742 let completionKind = byCompletionKind.get(kind);
1743 if (completionKind === undefined) {
1747 return completionKind;
1748 }
1749 > } languages.ts
1750 >
1751 > export interface DocumentSymbol {
1752 > name: string;
1753 > detail: string;
1754 > kind: SymbolKind;
1755 > tags: ReadonlyArray<SymbolTag>;
1756 > containerName?: string;
1757 > range: IRange;
1758 > selectionRange: IRange;
1759 > children?: DocumentSymbol[];
1760 > }
1761 >
1762 > /**
1763 > * The document symbol provider interface defines the contract between extensions and
1764 > * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature.
1765 > */
1766 > export interface DocumentSymbolProvider {
1767 >
1768 > displayName?: string;
1769 >
1770 > /**
1771 > * Provide symbol information for the given document.
1772 > */
1773 > provideDocumentSymbols(model: model.ITextModel, token: CancellationToken): ProviderResult<DocumentSymbol[]>;
1774 > }
1775 >
1776 > export interface TextEdit {
1777 > range: IRange;
1778 > text: string;
1779 > eol?: model.EndOfLineSequence;
1780 > }
1781 >
1782 > /** @internal */
1783 > export abstract class TextEdit {
1784 > static asEditOperation(edit: TextEdit): ISingleEditOperation {
1785 const range = Range.lift(edit.range);
1786 return range.isEmpty()
1788 : EditOperation.replace(range, edit.text);
1789 }
1790 > static isTextEdit(thing: unknown): thing is TextEdit { languages.ts
1791 const possibleTextEdit = thing as TextEdit;
1792 return typeof possibleTextEdit.text === 'string' && Range.isIRange(possibleTextEdit.range);
1793 }
1794 > } languages.ts
1795 >
1796 > /**
1797 > * Interface used to format a model
1798 > */
1799 > export interface FormattingOptions {
1800 > /**
1801 > * Size of a tab in spaces.
1802 > */
1803 > tabSize: number;
1804 > /**
1805 > * Prefer spaces over tabs.
1806 > */
1807 > insertSpaces: boolean;
1808 > }
1809 > /**
1810 > * The document formatting provider interface defines the contract between extensions and
1811 > * the formatting-feature.
1812 > */
1813 > export interface DocumentFormattingEditProvider {
1814 >
1815 > /**
1816 > * @internal
1817 > */
1818 > readonly extensionId?: ExtensionIdentifier;
1819 >
1820 > readonly displayName?: string;
1821 >
1822 > /**
1823 > * Provide formatting edits for a whole document.
1824 > */
1825 > provideDocumentFormattingEdits(model: model.ITextModel, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]>;
1826 > }
1827 > /**
1828 > * The document formatting provider interface defines the contract between extensions and
1829 > * the formatting-feature.
1830 > */
1831 > export interface DocumentRangeFormattingEditProvider {
1832 > /**
1833 > * @internal
1834 > */
1835 > readonly extensionId?: ExtensionIdentifier;
1836 >
1837 > readonly displayName?: string;
1838 >
1839 > /**
1840 > * Provide formatting edits for a range in a document.
1841 > *
1842 > * The given range is a hint and providers can decide to format a smaller
1843 > * or larger range. Often this is done by adjusting the start and end
1844 > * of the range to full syntax nodes.
1845 > */
1846 > provideDocumentRangeFormattingEdits(model: model.ITextModel, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]>;
1847 >
1848 > provideDocumentRangesFormattingEdits?(model: model.ITextModel, ranges: Range[], options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]>;
1849 > }
1850 > /**
1851 > * The document formatting provider interface defines the contract between extensions and
1852 > * the formatting-feature.
1853 > */
1854 > export interface OnTypeFormattingEditProvider {
1855 >
1856 >
1857 > /**
1858 > * @internal
1859 > */
1860 > readonly extensionId?: ExtensionIdentifier;
1861 >
1862 > autoFormatTriggerCharacters: string[];
1863 >
1864 > /**
1865 > * Provide formatting edits after a character has been typed.
1866 > *
1867 > * The given position and character should hint to the provider
1868 > * what range the position to expand to, like find the matching `{`
1869 > * when `}` has been entered.
1870 > */
1871 > provideOnTypeFormattingEdits(model: model.ITextModel, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]>;
1872 > }
1873 >
1874 > /**
1875 > * @internal
1876 > */
1877 > export interface IInplaceReplaceSupportResult {
1878 > value: string;
1879 > range: IRange;
1880 > }
1881 >
1882 > /**
1883 > * A link inside the editor.
1884 > */
1885 > export interface ILink {
1886 > range: IRange;
1887 > url?: URI | string;
1888 > tooltip?: string;
1889 > }
1890 >
1891 > export interface ILinksList {
1892 > links: ILink[];
1893 > dispose?(): void;
1894 > }
1895 > /**
1896 > * A provider of links.
1897 > */
1898 > export interface LinkProvider {
1899 > provideLinks(model: model.ITextModel, token: CancellationToken): ProviderResult<ILinksList>;
1900 > resolveLink?: (link: ILink, token: CancellationToken) => ProviderResult<ILink>;
1901 > }
1902 >
1903 > /**
1904 > * A color in RGBA format.
1905 > */
1906 > export interface IColor {
1907 >
1908 > /**
1909 > * The red component in the range [0-1].
1910 > */
1911 > readonly red: number;
1912 >
1913 > /**
1914 > * The green component in the range [0-1].
1915 > */
1916 > readonly green: number;
1917 >
1918 > /**
1919 > * The blue component in the range [0-1].
1920 > */
1921 > readonly blue: number;
1922 >
1923 > /**
1924 > * The alpha component in the range [0-1].
1925 > */
1926 > readonly alpha: number;
1927 > }
1928 >
1929 > /**
1930 > * String representations for a color
1931 > */
1932 > export interface IColorPresentation {
1933 > /**
1934 > * The label of this color presentation. It will be shown on the color
1935 > * picker header. By default this is also the text that is inserted when selecting
1936 > * this color presentation.
1937 > */
1938 > label: string;
1939 > /**
1940 > * An {@link TextEdit edit} which is applied to a document when selecting
1941 > * this presentation for the color.
1942 > */
1943 > textEdit?: TextEdit;
1944 > /**
1945 > * An optional array of additional {@link TextEdit text edits} that are applied when
1946 > * selecting this color presentation.
1947 > */
1948 > additionalTextEdits?: TextEdit[];
1949 > }
1950 >
1951 > /**
1952 > * A color range is a range in a text model which represents a color.
1953 > */
1954 > export interface IColorInformation {
1955 >
1956 > /**
1957 > * The range within the model.
1958 > */
1959 > range: IRange;
1960 >
1961 > /**
1962 > * The color represented in this range.
1963 > */
1964 > color: IColor;
1965 > }
1966 >
1967 > /**
1968 > * A provider of colors for editor models.
1969 > */
1970 > export interface DocumentColorProvider {
1971 > /**
1972 > * Provides the color ranges for a specific model.
1973 > */
1974 > provideDocumentColors(model: model.ITextModel, token: CancellationToken): ProviderResult<IColorInformation[]>;
1975 > /**
1976 > * Provide the string representations for a color.
1977 > */
1978 > provideColorPresentations(model: model.ITextModel, colorInfo: IColorInformation, token: CancellationToken): ProviderResult<IColorPresentation[]>;
1979 > }
1980 >
1981 > export interface SelectionRange {
1982 > range: IRange;
1983 > }
1984 >
1985 > export interface SelectionRangeProvider {
1986 > /**
1987 > * Provide ranges that should be selected from the given position.
1988 > */
1989 > provideSelectionRanges(model: model.ITextModel, positions: Position[], token: CancellationToken): ProviderResult<SelectionRange[][]>;
1990 > }
1991 >
1992 > export interface FoldingContext {
1993 > }
1994 > /**
1995 > * A provider of folding ranges for editor models.
1996 > */
1997 > export interface FoldingRangeProvider {
1998 >
1999 > /**
2000 > * @internal
2001 > */
2002 > readonly id?: string;
2003 >
2004 > /**
2005 > * An optional event to signal that the folding ranges from this provider have changed.
2006 > */
2007 > onDidChange?: Event<this>;
2008 >
2009 > /**
2010 > * Provides the folding ranges for a specific model.
2011 > */
2012 > provideFoldingRanges(model: model.ITextModel, context: FoldingContext, token: CancellationToken): ProviderResult<FoldingRange[]>;
2013 > }
2014 >
2015 > export interface FoldingRange {
2016 >
2017 > /**
2018 > * The one-based start line of the range to fold. The folded area starts after the line's last character.
2019 > */
2020 > start: number;
2021 >
2022 > /**
2023 > * The one-based end line of the range to fold. The folded area ends with the line's last character.
2024 > */
2025 > end: number;
2026 >
2027 > /**
2028 > * Describes the {@link FoldingRangeKind Kind} of the folding range such as {@link FoldingRangeKind.Comment Comment} or
2029 > * {@link FoldingRangeKind.Region Region}. The kind is used to categorize folding ranges and used by commands
2030 > * like 'Fold all comments'. See
2031 > * {@link FoldingRangeKind} for an enumeration of standardized kinds.
2032 > */
2033 > kind?: FoldingRangeKind;
2034 > }
2035 > export class FoldingRangeKind {
2036 > /**
2037 > * Kind for folding range representing a comment. The value of the kind is 'comment'.
2038 > */
2039 > static readonly Comment = new FoldingRangeKind('comment');
2040 > /**
2041 > * Kind for folding range representing a import. The value of the kind is 'imports'.
2042 > */
2043 > static readonly Imports = new FoldingRangeKind('imports');
2044 > /**
2045 > * Kind for folding range representing regions (for example marked by `#region`, `#endregion`).
2046 > * The value of the kind is 'region'.
2047 > */
2048 > static readonly Region = new FoldingRangeKind('region');
2049 >
2050 > /**
2051 > * Returns a {@link FoldingRangeKind} for the given value.
2052 > *
2053 > * @param value of the kind.
2054 > */
2055 > static fromValue(value: string) {
2056 switch (value) {
2057 case 'comment': return FoldingRangeKind.Comment;
2061 return new FoldingRangeKind(value);
2062 }
2063 > languages.ts
2064 > /**
2065 > * Creates a new {@link FoldingRangeKind}.
2066 > *
2067 > * @param value of the kind.
2068 > */
2069 > public constructor(public value: string) {
2070 > }
2071 > }
2072 >
2073 >
2074 > export interface WorkspaceEditMetadata {
2075 > needsConfirmation: boolean;
2076 > label: string;
2077 > description?: string;
2078 > /**
2079 > * @internal
2080 > */
2081 > iconPath?: ThemeIcon | URI | { light: URI; dark: URI };
2082 > }
2083 >
2084 > export interface WorkspaceFileEditOptions {
2085 > overwrite?: boolean;
2086 > ignoreIfNotExists?: boolean;
2087 > ignoreIfExists?: boolean;
2088 > recursive?: boolean;
2089 > copy?: boolean;
2090 > folder?: boolean;
2091 > skipTrashBin?: boolean;
2092 > maxSize?: number;
2093 >
2094 > /**
2095 > * @internal
2096 > */
2097 > contents?: Promise<VSBuffer>;
2098 > }
2099 >
2100 > export interface IWorkspaceFileEdit {
2101 > oldResource?: URI;
2102 > newResource?: URI;
2103 > options?: WorkspaceFileEditOptions;
2104 > metadata?: WorkspaceEditMetadata;
2105 > }
2106 >
2107 > export interface IWorkspaceTextEdit {
2108 > resource: URI;
2109 > textEdit: TextEdit & { insertAsSnippet?: boolean; keepWhitespace?: boolean };
2110 > versionId: number | undefined;
2111 > metadata?: WorkspaceEditMetadata;
2112 > }
2113 >
2114 > export interface WorkspaceEdit {
2115 > edits: Array<IWorkspaceTextEdit | IWorkspaceFileEdit | ICustomEdit>;
2116 > }
2117 >
2118 > export interface ICustomEdit {
2119 > readonly resource: URI;
2120 > readonly metadata?: WorkspaceEditMetadata;
2121 > undo(): Promise<void> | void;
2122 > redo(): Promise<void> | void;
2123 > }
2124 >
2125 > export interface Rejection {
2126 > rejectReason?: string;
2127 > }
2128 > export interface RenameLocation {
2129 > range: IRange;
2130 > text: string;
2131 > }
2132 >
2133 > export interface RenameProvider {
2134 > provideRenameEdits(model: model.ITextModel, position: Position, newName: string, token: CancellationToken): ProviderResult<WorkspaceEdit & Rejection>;
2135 > resolveRenameLocation?(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<RenameLocation & Rejection>;
2136 > }
2137 >
2138 > export enum NewSymbolNameTag {
2139 > AIGenerated = 1
2140 > }
2141 >
2142 > export enum NewSymbolNameTriggerKind {
2143 > Invoke = 0,
2144 > Automatic = 1,
2145 > }
2146 >
2147 > export interface NewSymbolName {
2148 > readonly newSymbolName: string;
2149 > readonly tags?: readonly NewSymbolNameTag[];
2150 > }
2151 >
2152 > export interface NewSymbolNamesProvider {
2153 > supportsAutomaticNewSymbolNamesTriggerKind?: Promise<boolean | undefined>;
2154 > provideNewSymbolNames(model: model.ITextModel, range: IRange, triggerKind: NewSymbolNameTriggerKind, token: CancellationToken): ProviderResult<NewSymbolName[]>;
2155 > }
2156 >
2157 > export interface Command {
2158 > id: string;
2159 > title: string;
2160 > tooltip?: string;
2161 > arguments?: unknown[];
2162 > }
2163 >
2164 > /**
2165 > * @internal
2166 > */
2167 > export namespace Command {
2168 >
2169 > /**
2170 > * @internal
2171 > */
2172 > export function is(obj: unknown): obj is Command {
2173 if (!obj || typeof obj !== 'object') {
2174 return false;
2177 typeof (<Command>obj).title === 'string';
2178 }
2179 > } languages.ts
2180 >
2181 > /**
2182 > * @internal
2183 > */
2184 > export interface CommentThreadTemplate {
2185 > controllerHandle: number;
2186 > label: string;
2187 > acceptInputCommand?: Command;
2188 > additionalCommands?: Command[];
2189 > deleteCommand?: Command;
2190 > }
2191 >
2192 > /**
2193 > * @internal
2194 > */
2195 > export interface CommentInfo<T = IRange> {
2196 > extensionId?: string;
2197 > threads: CommentThread<T>[];
2198 > pendingCommentThreads?: PendingCommentThread[];
2199 > commentingRanges: CommentingRanges;
2200 > }
2201 >
2202 >
2203 > /**
2204 > * @internal
2205 > */
2206 > export interface CommentingRangeResourceHint {
2207 > schemes: readonly string[];
2208 > }
2209 >
2210 > /**
2211 > * @internal
2212 > */
2213 > export enum CommentThreadCollapsibleState {
2214 > /**
2215 > * Determines an item is collapsed
2216 > */
2217 > Collapsed = 0,
2218 > /**
2219 > * Determines an item is expanded
2220 > */
2221 > Expanded = 1
2222 > }
2223 >
2224 > /**
2225 > * @internal
2226 > */
2227 > export enum CommentThreadState {
2228 > Unresolved = 0,
2229 > Resolved = 1
2230 > }
2231 >
2232 > /**
2233 > * @internal
2234 > */
2235 > export enum CommentThreadApplicability {
2236 > Current = 0,
2237 > Outdated = 1
2238 > }
2239 >
2240 > /**
2241 > * @internal
2242 > */
2243 > export interface CommentWidget {
2244 > commentThread: CommentThread;
2245 > comment?: Comment;
2246 > input: string;
2247 > readonly onDidChangeInput: Event<string>;
2248 > }
2249 >
2250 > /**
2251 > * @internal
2252 > */
2253 > export interface CommentInput {
2254 > value: string;
2255 > uri: URI;
2256 > }
2257 >
2258 > export interface CommentThreadRevealOptions {
2259 > preserveFocus: boolean;
2260 > focusReply: boolean;
2261 > }
2262 >
2263 > /**
2264 > * @internal
2265 > */
2266 > export interface CommentThread<T = IRange> {
2267 > isDocumentCommentThread(): this is CommentThread<IRange>;
2268 > commentThreadHandle: number;
2269 > controllerHandle: number;
2270 > extensionId?: string;
2271 > threadId: string;
2272 > resource: string | null;
2273 > range: T | undefined;
2274 > label: string | undefined;
2275 > contextValue: string | undefined;
2276 > comments: ReadonlyArray<Comment> | undefined;
2277 > readonly onDidChangeComments: Event<readonly Comment[] | undefined>;
2278 > collapsibleState?: CommentThreadCollapsibleState;
2279 > initialCollapsibleState?: CommentThreadCollapsibleState;
2280 > readonly onDidChangeInitialCollapsibleState: Event<CommentThreadCollapsibleState | undefined>;
2281 > state?: CommentThreadState;
2282 > applicability?: CommentThreadApplicability;
2283 > canReply: boolean | CommentAuthorInformation;
2284 > input?: CommentInput;
2285 > readonly onDidChangeInput: Event<CommentInput | undefined>;
2286 > readonly onDidChangeLabel: Event<string | undefined>;
2287 > readonly onDidChangeCollapsibleState: Event<CommentThreadCollapsibleState | undefined>;
2288 > readonly onDidChangeState: Event<CommentThreadState | undefined>;
2289 > readonly onDidChangeCanReply: Event<boolean>;
2290 > isDisposed: boolean;
2291 > isTemplate: boolean;
2292 > }
2293 >
2294 > /**
2295 > * @internal
2296 > */
2297 > export interface AddedCommentThread<T = IRange> extends CommentThread<T> {
2298 > editorId?: string;
2299 > }
2300 >
2301 > /**
2302 > * @internal
2303 > */
2304 >
2305 > export interface CommentingRanges {
2306 > readonly resource: URI;
2307 > ranges: IRange[];
2308 > fileComments: boolean;
2309 > }
2310 >
2311 > export interface CommentAuthorInformation {
2312 > name: string;
2313 > iconPath?: UriComponents;
2314 >
2315 > }
2316 >
2317 > /**
2318 > * @internal
2319 > */
2320 > export interface CommentReaction {
2321 > readonly label?: string;
2322 > readonly iconPath?: UriComponents;
2323 > readonly count?: number;
2324 > readonly hasReacted?: boolean;
2325 > readonly canEdit?: boolean;
2326 > readonly reactors?: readonly string[];
2327 > }
2328 >
2329 > /**
2330 > * @internal
2331 > */
2332 > export interface CommentOptions {
2333 > /**
2334 > * An optional string to show on the comment input box when it's collapsed.
2335 > */
2336 > prompt?: string;
2337 >
2338 > /**
2339 > * An optional string to show as placeholder in the comment input box when it's focused.
2340 > */
2341 > placeHolder?: string;
2342 > }
2343 >
2344 > /**
2345 > * @internal
2346 > */
2347 > export enum CommentMode {
2348 > Editing = 0,
2349 > Preview = 1
2350 > }
2351 >
2352 > /**
2353 > * @internal
2354 > */
2355 > export enum CommentState {
2356 > Published = 0,
2357 > Draft = 1
2358 > }
2359 >
2360 > /**
2361 > * @internal
2362 > */
2363 > export interface Comment {
2364 > readonly uniqueIdInThread: number;
2365 > readonly body: string | IMarkdownString;
2366 > readonly userName: string;
2367 > readonly userIconPath?: UriComponents;
2368 > readonly contextValue?: string;
2369 > readonly commentReactions?: CommentReaction[];
2370 > readonly label?: string;
2371 > readonly mode?: CommentMode;
2372 > readonly state?: CommentState;
2373 > readonly timestamp?: string;
2374 > }
2375 >
2376 > export interface PendingCommentThread {
2377 > range: IRange | undefined;
2378 > uri: URI;
2379 > uniqueOwner: string;
2380 > isReply: boolean;
2381 > comment: PendingComment;
2382 > }
2383 >
2384 > export interface PendingComment {
2385 > body: string;
2386 > cursor: IPosition;
2387 > }
2388 >
2389 > /**
2390 > * @internal
2391 > */
2392 > export interface CommentThreadChangedEvent<T> {
2393 > /**
2394 > * Pending comment threads.
2395 > */
2396 > readonly pending: PendingCommentThread[];
2397 >
2398 > /**
2399 > * Added comment threads.
2400 > */
2401 > readonly added: AddedCommentThread<T>[];
2402 >
2403 > /**
2404 > * Removed comment threads.
2405 > */
2406 > readonly removed: CommentThread<T>[];
2407 >
2408 > /**
2409 > * Changed comment threads.
2410 > */
2411 > readonly changed: CommentThread<T>[];
2412 > }
2413 >
2414 > export interface CodeLens {
2415 > range: IRange;
2416 > id?: string;
2417 > command?: Command;
2418 > }
2419 >
2420 > export interface CodeLensList {
2421 > readonly lenses: readonly CodeLens[];
2422 > dispose?(): void;
2423 > }
2424 >
2425 > export interface CodeLensProvider {
2426 > onDidChange?: Event<this>;
2427 > provideCodeLenses(model: model.ITextModel, token: CancellationToken): ProviderResult<CodeLensList>;
2428 > resolveCodeLens?(model: model.ITextModel, codeLens: CodeLens, token: CancellationToken): ProviderResult<CodeLens>;
2429 > }
2430 >
2431 >
2432 > export enum InlayHintKind {
2433 > Type = 1,
2434 > Parameter = 2,
2435 > }
2436 >
2437 > export interface InlayHintLabelPart {
2438 > label: string;
2439 > tooltip?: string | IMarkdownString;
2440 > // collapsible?: boolean;
2441 > command?: Command;
2442 > location?: Location;
2443 > }
2444 >
2445 > export interface InlayHint {
2446 > label: string | InlayHintLabelPart[];
2447 > tooltip?: string | IMarkdownString;
2448 > textEdits?: TextEdit[];
2449 > position: IPosition;
2450 > kind?: InlayHintKind;
2451 > paddingLeft?: boolean;
2452 > paddingRight?: boolean;
2453 > }
2454 >
2455 > export interface InlayHintList {
2456 > hints: InlayHint[];
2457 > dispose(): void;
2458 > }
2459 >
2460 > export interface InlayHintsProvider {
2461 > displayName?: string;
2462 > onDidChangeInlayHints?: Event<void>;
2463 > provideInlayHints(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult<InlayHintList>;
2464 > resolveInlayHint?(hint: InlayHint, token: CancellationToken): ProviderResult<InlayHint>;
2465 > }
2466 >
2467 > export interface SemanticTokensLegend {
2468 > readonly tokenTypes: string[];
2469 > readonly tokenModifiers: string[];
2470 > }
2471 >
2472 > export interface SemanticTokens {
2473 > readonly resultId?: string;
2474 > readonly data: Uint32Array;
2475 > }
2476 >
2477 > export interface SemanticTokensEdit {
2478 > readonly start: number;
2479 > readonly deleteCount: number;
2480 > readonly data?: Uint32Array;
2481 > }
2482 >
2483 > export interface SemanticTokensEdits {
2484 > readonly resultId?: string;
2485 > readonly edits: SemanticTokensEdit[];
2486 > }
2487 >
2488 > export interface DocumentSemanticTokensProvider {
2489 > readonly onDidChange?: Event<void>;
2490 > getLegend(): SemanticTokensLegend;
2491 > provideDocumentSemanticTokens(model: model.ITextModel, lastResultId: string | null, token: CancellationToken): ProviderResult<SemanticTokens | SemanticTokensEdits>;
2492 > releaseDocumentSemanticTokens(resultId: string | undefined): void;
2493 > }
2494 >
2495 > export interface DocumentRangeSemanticTokensProvider {
2496 > readonly onDidChange?: Event<void>;
2497 > getLegend(): SemanticTokensLegend;
2498 > provideDocumentRangeSemanticTokens(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult<SemanticTokens>;
2499 > }
2500 >
2501 > /**
2502 > * @internal
2503 > */
2504 > export interface ITokenizationSupportChangedEvent {
2505 > changedLanguages: string[];
2506 > changedColorMap: boolean;
2507 > }
2508 >
2509 > /**
2510 > * @internal
2511 > */
2512 > export interface ILazyTokenizationSupport<TSupport> {
2513 > get tokenizationSupport(): Promise<TSupport | null>;
2514 > }
2515 >
2516 > /**
2517 > * @internal
2518 > */
2519 > export class LazyTokenizationSupport<TSupport = ITokenizationSupport> implements IDisposable, ILazyTokenizationSupport<TSupport> {
2520 > private _tokenizationSupport: Promise<TSupport & IDisposable | null> | null = null;
2521 >
2522 > constructor(private readonly createSupport: () => Promise<TSupport & IDisposable | null>) {
2523 }
2524 > languages.ts
2525 > dispose(): void {
2526 if (this._tokenizationSupport) {
2527 this._tokenizationSupport.then((support) => {
2532 }
2533 }
2534 > languages.ts
2535 > get tokenizationSupport(): Promise<TSupport | null> {
2536 if (!this._tokenizationSupport) {
2537 this._tokenizationSupport = this.createSupport();
2539 return this._tokenizationSupport;
2540 }
2541 > } languages.ts
2542 >
2543 > /**
2544 > * @internal
2545 > */
2546 > export interface ITokenizationRegistry<TSupport> {
2547 >
2548 > /**
2549 > * An event triggered when:
2550 > * - a tokenization support is registered, unregistered or changed.
2551 > * - the color map is changed.
2552 > */
2553 > readonly onDidChange: Event<ITokenizationSupportChangedEvent>;
2554 >
2555 > /**
2556 > * Fire a change event for a language.
2557 > * This is useful for languages that embed other languages.
2558 > */
2559 > handleChange(languageIds: string[]): void;
2560 >
2561 > /**
2562 > * Register a tokenization support.
2563 > */
2564 > register(languageId: string, support: TSupport): IDisposable;
2565 >
2566 > /**
2567 > * Register a tokenization support factory.
2568 > */
2569 > registerFactory(languageId: string, factory: ILazyTokenizationSupport<TSupport>): IDisposable;
2570 >
2571 > /**
2572 > * Get or create the tokenization support for a language.
2573 > * Returns `null` if not found.
2574 > */
2575 > getOrCreate(languageId: string): Promise<TSupport | null>;
2576 >
2577 > /**
2578 > * Get the tokenization support for a language.
2579 > * Returns `null` if not found.
2580 > */
2581 > get(languageId: string): TSupport | null;
2582 >
2583 > /**
2584 > * Returns false if a factory is still pending.
2585 > */
2586 > isResolved(languageId: string): boolean;
2587 >
2588 > /**
2589 > * Set the new color map that all tokens will use in their ColorId binary encoded bits for foreground and background.
2590 > */
2591 > setColorMap(colorMap: Color[]): void;
2592 >
2593 > getColorMap(): Color[] | null;
2594 >
2595 > getDefaultBackground(): Color | null;
2596 > }
2597 >
2598 > /**
2599 > * @internal
2600 > */
2601 > export const TokenizationRegistry: ITokenizationRegistry<ITokenizationSupport> = new TokenizationRegistryImpl();
2602 >
2603 > /**
2604 > * @internal
2605 > */
2606 > export enum ExternalUriOpenerPriority {
2607 > None = 0,
2608 > Option = 1,
2609 > Default = 2,
2610 > Preferred = 3,
2611 > }
2612 >
2613 > /**
2614 > * @internal
2615 > */
2616 > export type DropYieldTo = { readonly kind: HierarchicalKind } | { readonly mimeType: string };
2617 >
2618 > /**
2619 > * @internal
2620 > */
2621 > export interface DocumentDropEdit {
2622 > readonly title: string;
2623 > readonly kind: HierarchicalKind | undefined;
2624 > readonly handledMimeType?: string;
2625 > readonly yieldTo?: readonly DropYieldTo[];
2626 > insertText: string | { readonly snippet: string };
2627 > additionalEdit?: WorkspaceEdit;
2628 > }
2629 >
2630 > /**
2631 > * @internal
2632 > */
2633 > export interface DocumentDropEditsSession {
2634 > edits: readonly DocumentDropEdit[];
2635 > dispose(): void;
2636 > }
2637 >
2638 > /**
2639 > * @internal
2640 > */
2641 > export interface DocumentDropEditProvider {
2642 > readonly id?: string;
2643 > readonly dropMimeTypes?: readonly string[];
2644 > readonly providedDropEditKinds?: readonly HierarchicalKind[];
2645 >
2646 > provideDocumentDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): ProviderResult<DocumentDropEditsSession>;
2647 > resolveDocumentDropEdit?(edit: DocumentDropEdit, token: CancellationToken): Promise<DocumentDropEdit>;
2648 > }
src/vs/editor/common/model.ts 1559 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- model.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 { IMarkdownString } from '../../base/common/htmlContent.js';
8 > import { IDisposable } from '../../base/common/lifecycle.js';
9 > import { equals } from '../../base/common/objects.js';
10 > import { ThemeColor } from '../../base/common/themables.js';
11 > import { URI } from '../../base/common/uri.js';
12 > import { ISingleEditOperation } from './core/editOperation.js';
13 > import { IPosition, Position } from './core/position.js';
14 > import { IRange, Range } from './core/range.js';
15 > import { Selection } from './core/selection.js';
16 > import { TextChange } from './core/textChange.js';
17 > import { WordCharacterClassifier } from './core/wordCharacterClassifier.js';
18 > import { IWordAtPosition } from './core/wordHelper.js';
19 > import { FormattingOptions } from './languages.js';
20 > import { ILanguageSelection } from './languages/language.js';
21 > import { IBracketPairsTextModelPart } from './textModelBracketPairs.js';
22 > import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent, LineInjectedText, ModelFontChangedEvent, ModelLineHeightChangedEvent } from './textModelEvents.js';
23 > import { IModelContentChange } from './model/mirrorTextModel.js';
24 > import { IGuidesTextModelPart } from './textModelGuides.js';
25 > import { ITokenizationTextModelPart } from './tokenizationTextModelPart.js';
26 > import { UndoRedoGroup } from '../../platform/undoRedo/common/undoRedo.js';
27 > import { TokenArray } from './tokens/lineTokens.js';
28 > import { IEditorModel } from './editorCommon.js';
29 > import { TextModelEditSource } from './textModelEditSource.js';
30 > import { TextEdit } from './core/edits/textEdit.js';
31 > import { IViewModel } from './viewModel.js';
32 >
33 > /**
34 > * Vertical Lane in the overview ruler of the editor.
35 > */
36 > export enum OverviewRulerLane {
37 > Left = 1,
38 > Center = 2,
39 > Right = 4,
40 > Full = 7
41 > }
42 >
43 > /**
44 > * Vertical Lane in the glyph margin of the editor.
45 > */
46 > export enum GlyphMarginLane {
47 > Left = 1,
48 > Center = 2,
49 > Right = 3,
50 > }
51 >
52 > export interface IGlyphMarginLanesModel {
53 > /**
54 > * The number of lanes that should be rendered in the editor.
55 > */
56 > readonly requiredLanes: number;
57 >
58 > /**
59 > * Gets the lanes that should be rendered starting at a given line number.
60 > */
61 > getLanesAtLine(lineNumber: number): GlyphMarginLane[];
62 >
63 > /**
64 > * Resets the model and ensures it can contain at least `maxLine` lines.
65 > */
66 > reset(maxLine: number): void;
67 >
68 > /**
69 > * Registers that a lane should be visible at the Range in the model.
70 > * @param persist - if true, notes that the lane should always be visible,
71 > * even on lines where there's no specific request for that lane.
72 > */
73 > push(lane: GlyphMarginLane, range: Range, persist?: boolean): void;
74 > }
75 >
76 > /**
77 > * Position in the minimap to render the decoration.
78 > */
79 > export const enum MinimapPosition {
80 > Inline = 1,
81 > Gutter = 2
82 > }
83 >
84 > /**
85 > * Section header style.
86 > */
87 > export const enum MinimapSectionHeaderStyle {
88 > Normal = 1,
89 > Underlined = 2
90 > }
91 >
92 > export interface IDecorationOptions {
93 > /**
94 > * CSS color to render.
95 > * e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry
96 > */
97 > color: string | ThemeColor | undefined;
98 > /**
99 > * CSS color to render.
100 > * e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry
101 > */
102 > darkColor?: string | ThemeColor;
103 > }
104 >
105 > export interface IModelDecorationGlyphMarginOptions {
106 > /**
107 > * The position in the glyph margin.
108 > */
109 > position: GlyphMarginLane;
110 >
111 > /**
112 > * Whether the glyph margin lane in {@link position} should be rendered even
113 > * outside of this decoration's range.
114 > */
115 > persistLane?: boolean;
116 > }
117 >
118 > /**
119 > * Options for rendering a model decoration in the overview ruler.
120 > */
121 > export interface IModelDecorationOverviewRulerOptions extends IDecorationOptions {
122 > /**
123 > * The position in the overview ruler.
124 > */
125 > position: OverviewRulerLane;
126 > }
127 >
128 > /**
129 > * Options for rendering a model decoration in the minimap.
130 > */
131 > export interface IModelDecorationMinimapOptions extends IDecorationOptions {
132 > /**
133 > * The position in the minimap.
134 > */
135 > position: MinimapPosition;
136 > /**
137 > * If the decoration is for a section header, which header style.
138 > */
139 > sectionHeaderStyle?: MinimapSectionHeaderStyle | null;
140 > /**
141 > * If the decoration is for a section header, the header text.
142 > */
143 > sectionHeaderText?: string | null;
144 > }
145 >
146 > /**
147 > * Options for a model decoration.
148 > */
149 > export interface IModelDecorationOptions {
150 > /**
151 > * A debug description that can be used for inspecting model decorations.
152 > * @internal
153 > */
154 > description: string;
155 > /**
156 > * Customize the growing behavior of the decoration when typing at the edges of the decoration.
157 > * Defaults to TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges
158 > */
159 > stickiness?: TrackedRangeStickiness;
160 > /**
161 > * CSS class name describing the decoration.
162 > */
163 > className?: string | null;
164 > /**
165 > * Indicates whether the decoration should span across the entire line when it continues onto the next line.
166 > */
167 > shouldFillLineOnLineBreak?: boolean | null;
168 > blockClassName?: string | null;
169 > /**
170 > * Indicates if this block should be rendered after the last line.
171 > * In this case, the range must be empty and set to the last line.
172 > */
173 > blockIsAfterEnd?: boolean | null;
174 > blockDoesNotCollapse?: boolean | null;
175 > blockPadding?: [top: number, right: number, bottom: number, left: number] | null;
176 >
177 > /**
178 > * Message to be rendered when hovering over the glyph margin decoration.
179 > */
180 > glyphMarginHoverMessage?: IMarkdownString | IMarkdownString[] | null;
181 > /**
182 > * Array of MarkdownString to render as the decoration message.
183 > */
184 > hoverMessage?: IMarkdownString | IMarkdownString[] | null;
185 > /**
186 > * Array of MarkdownString to render as the line number message.
187 > */
188 > lineNumberHoverMessage?: IMarkdownString | IMarkdownString[] | null;
189 > /**
190 > * Should the decoration expand to encompass a whole line.
191 > */
192 > isWholeLine?: boolean;
193 > /**
194 > * Always render the decoration (even when the range it encompasses is collapsed).
195 > */
196 > showIfCollapsed?: boolean;
197 > /**
198 > * Collapse the decoration if its entire range is being replaced via an edit.
199 > * @internal
200 > */
201 > collapseOnReplaceEdit?: boolean;
202 > /**
203 > * Specifies the stack order of a decoration.
204 > * A decoration with greater stack order is always in front of a decoration with
205 > * a lower stack order when the decorations are on the same line.
206 > */
207 > zIndex?: number;
208 > /**
209 > * If set, render this decoration in the overview ruler.
210 > */
211 > overviewRuler?: IModelDecorationOverviewRulerOptions | null;
212 > /**
213 > * If set, render this decoration in the minimap.
214 > */
215 > minimap?: IModelDecorationMinimapOptions | null;
216 > /**
217 > * If set, the decoration will be rendered in the glyph margin with this CSS class name.
218 > */
219 > glyphMarginClassName?: string | null;
220 > /**
221 > * If set and the decoration has {@link glyphMarginClassName} set, render this decoration
222 > * with the specified {@link IModelDecorationGlyphMarginOptions} in the glyph margin.
223 > */
224 > glyphMargin?: IModelDecorationGlyphMarginOptions | null;
225 > /**
226 > * If set, the decoration will override the line height of the lines it spans. This value is a multiplier to the default line height.
227 > */
228 > lineHeight?: number | null;
229 > /**
230 > * Font family
231 > */
232 > fontFamily?: string | null;
233 > /**
234 > * Font size
235 > */
236 > fontSize?: string | null;
237 > /**
238 > * Font weight
239 > */
240 > fontWeight?: string | null;
241 > /**
242 > * Font style
243 > */
244 > fontStyle?: string | null;
245 > /**
246 > * If set, the decoration will be rendered in the lines decorations with this CSS class name.
247 > */
248 > linesDecorationsClassName?: string | null;
249 > /**
250 > * Controls the tooltip text of the line decoration.
251 > */
252 > linesDecorationsTooltip?: string | null;
253 > /**
254 > * If set, the decoration will be rendered on the line number.
255 > */
256 > lineNumberClassName?: string | null;
257 > /**
258 > * If set, the decoration will be rendered in the lines decorations with this CSS class name, but only for the first line in case of line wrapping.
259 > */
260 > firstLineDecorationClassName?: string | null;
261 > /**
262 > * If set, the decoration will be rendered in the margin (covering its full width) with this CSS class name.
263 > */
264 > marginClassName?: string | null;
265 > /**
266 > * If set, the decoration will be rendered inline with the text with this CSS class name.
267 > * Please use this only for CSS rules that must impact the text. For example, use `className`
268 > * to have a background color decoration.
269 > */
270 > inlineClassName?: string | null;
271 > /**
272 > * If there is an `inlineClassName` which affects letter spacing.
273 > */
274 > inlineClassNameAffectsLetterSpacing?: boolean;
275 > /**
276 > * If set, the decoration will be rendered before the text with this CSS class name.
277 > */
278 > beforeContentClassName?: string | null;
279 > /**
280 > * If set, the decoration will be rendered after the text with this CSS class name.
281 > */
282 > afterContentClassName?: string | null;
283 > /**
284 > * If set, text will be injected in the view after the range.
285 > */
286 > after?: InjectedTextOptions | null;
287 >
288 > /**
289 > * If set, text will be injected in the view before the range.
290 > */
291 > before?: InjectedTextOptions | null;
292 >
293 > /**
294 > * If set, this decoration will not be rendered for comment tokens.
295 > * @internal
296 > */
297 > hideInCommentTokens?: boolean | null;
298 >
299 > /**
300 > * If set, this decoration will not be rendered for string tokens.
301 > * @internal
302 > */
303 > hideInStringTokens?: boolean | null;
304 >
305 > /**
306 > * Whether the decoration affects the font.
307 > * @internal
308 > */
309 > affectsFont?: boolean | null;
310 >
311 > /**
312 > * The text direction of the decoration.
313 > */
314 > textDirection?: TextDirection | null;
315 > }
316 >
317 > /**
318 > * Text Direction for a decoration.
319 > */
320 > export enum TextDirection {
321 > LTR = 0,
322 >
323 > RTL = 1,
324 > }
325 >
326 > /**
327 > * Configures text that is injected into the view without changing the underlying document.
328 > */
329 > export interface InjectedTextOptions {
330 > /**
331 > * Sets the text to inject. Must be a single line.
332 > */
333 > readonly content: string;
334 >
335 > /**
336 > * @internal
337 > */
338 > readonly tokens?: TokenArray | null;
339 >
340 > /**
341 > * If set, the decoration will be rendered inline with the text with this CSS class name.
342 > */
343 > readonly inlineClassName?: string | null;
344 >
345 > /**
346 > * If there is an `inlineClassName` which affects letter spacing.
347 > */
348 > readonly inlineClassNameAffectsLetterSpacing?: boolean;
349 >
350 > /**
351 > * This field allows to attach data to this injected text.
352 > * The data can be read when injected texts at a given position are queried.
353 > */
354 > readonly attachedData?: unknown;
355 >
356 > /**
357 > * Configures cursor stops around injected text.
358 > * Defaults to {@link InjectedTextCursorStops.Both}.
359 > */
360 > readonly cursorStops?: InjectedTextCursorStops | null;
361 > }
362 >
363 > export enum InjectedTextCursorStops {
364 > Both,
365 > Right,
366 > Left,
367 > None
368 > }
369 >
370 > /**
371 > * New model decorations.
372 > */
373 > export interface IModelDeltaDecoration {
374 > /**
375 > * Range that this decoration covers.
376 > */
377 > range: IRange;
378 > /**
379 > * Options associated with this decoration.
380 > */
381 > options: IModelDecorationOptions;
382 > }
383 >
384 > /**
385 > * A decoration in the model.
386 > */
387 > export interface IModelDecoration {
388 > /**
389 > * Identifier for a decoration.
390 > */
391 > readonly id: string;
392 > /**
393 > * Identifier for a decoration's owner.
394 > */
395 > readonly ownerId: number;
396 > /**
397 > * Range that this decoration covers.
398 > */
399 > readonly range: Range;
400 > /**
401 > * Options associated with this decoration.
402 > */
403 > readonly options: IModelDecorationOptions;
404 > }
405 >
406 > /**
407 > * An accessor that can add, change or remove model decorations.
408 > * @internal
409 > */
410 > export interface IModelDecorationsChangeAccessor {
411 > /**
412 > * Add a new decoration.
413 > * @param range Range that this decoration covers.
414 > * @param options Options associated with this decoration.
415 > * @return An unique identifier associated with this decoration.
416 > */
417 > addDecoration(range: IRange, options: IModelDecorationOptions): string;
418 > /**
419 > * Change the range that an existing decoration covers.
420 > * @param id The unique identifier associated with the decoration.
421 > * @param newRange The new range that this decoration covers.
422 > */
423 > changeDecoration(id: string, newRange: IRange): void;
424 > /**
425 > * Change the options associated with an existing decoration.
426 > * @param id The unique identifier associated with the decoration.
427 > * @param newOptions The new options associated with this decoration.
428 > */
429 > changeDecorationOptions(id: string, newOptions: IModelDecorationOptions): void;
430 > /**
431 > * Remove an existing decoration.
432 > * @param id The unique identifier associated with the decoration.
433 > */
434 > removeDecoration(id: string): void;
435 > /**
436 > * Perform a minimum amount of operations, in order to transform the decorations
437 > * identified by `oldDecorations` to the decorations described by `newDecorations`
438 > * and returns the new identifiers associated with the resulting decorations.
439 > *
440 > * @param oldDecorations Array containing previous decorations identifiers.
441 > * @param newDecorations Array describing what decorations should result after the call.
442 > * @return An array containing the new decorations identifiers.
443 > */
444 > deltaDecorations(oldDecorations: readonly string[], newDecorations: readonly IModelDeltaDecoration[]): string[];
445 > }
446 >
447 > /**
448 > * End of line character preference.
449 > */
450 > export const enum EndOfLinePreference {
451 > /**
452 > * Use the end of line character identified in the text buffer.
453 > */
454 > TextDefined = 0,
455 > /**
456 > * Use line feed (\n) as the end of line character.
457 > */
458 > LF = 1,
459 > /**
460 > * Use carriage return and line feed (\r\n) as the end of line character.
461 > */
462 > CRLF = 2
463 > }
464 >
465 > /**
466 > * The default end of line to use when instantiating models.
467 > */
468 > export const enum DefaultEndOfLine {
469 > /**
470 > * Use line feed (\n) as the end of line character.
471 > */
472 > LF = 1,
473 > /**
474 > * Use carriage return and line feed (\r\n) as the end of line character.
475 > */
476 > CRLF = 2
477 > }
478 >
479 > /**
480 > * End of line character preference.
481 > */
482 > export const enum EndOfLineSequence {
483 > /**
484 > * Use line feed (\n) as the end of line character.
485 > */
486 > LF = 0,
487 > /**
488 > * Use carriage return and line feed (\r\n) as the end of line character.
489 > */
490 > CRLF = 1
491 > }
492 >
493 > /**
494 > * An identifier for a single edit operation.
495 > * @internal
496 > */
497 > export interface ISingleEditOperationIdentifier {
498 > /**
499 > * Identifier major
500 > */
501 > major: number;
502 > /**
503 > * Identifier minor
504 > */
505 > minor: number;
506 > }
507 >
508 > /**
509 > * A single edit operation, that has an identifier.
510 > */
511 > export interface IIdentifiedSingleEditOperation extends ISingleEditOperation {
512 > /**
513 > * An identifier associated with this single edit operation.
514 > * @internal
515 > */
516 > identifier?: ISingleEditOperationIdentifier | null;
517 > /**
518 > * This indicates that this operation is inserting automatic whitespace
519 > * that can be removed on next model edit operation if `config.trimAutoWhitespace` is true.
520 > * @internal
521 > */
522 > isAutoWhitespaceEdit?: boolean;
523 > /**
524 > * This indicates that this operation is in a set of operations that are tracked and should not be "simplified".
525 > * @internal
526 > */
527 > _isTracked?: boolean;
528 > }
529 >
530 > export interface IValidEditOperation {
531 > /**
532 > * An identifier associated with this single edit operation.
533 > * @internal
534 > */
535 > identifier: ISingleEditOperationIdentifier | null;
536 > /**
537 > * The range to replace. This can be empty to emulate a simple insert.
538 > */
539 > range: Range;
540 > /**
541 > * The text to replace with. This can be empty to emulate a simple delete.
542 > */
543 > text: string;
544 > /**
545 > * @internal
546 > */
547 > textChange: TextChange;
548 > }
549 >
550 > /**
551 > * A callback that can compute the cursor state after applying a series of edit operations.
552 > */
553 > export interface ICursorStateComputer {
554 > /**
555 > * A callback that can compute the resulting cursors state after some edit operations have been executed.
556 > */
557 > (inverseEditOperations: IValidEditOperation[]): Selection[] | null;
558 > }
559 >
560 > export class TextModelResolvedOptions {
561 > _textModelResolvedOptionsBrand: void = undefined;
562 >
563 > readonly tabSize: number;
564 > readonly indentSize: number;
565 > private readonly _indentSizeIsTabSize: boolean;
566 > readonly insertSpaces: boolean;
567 > readonly defaultEOL: DefaultEndOfLine;
568 > readonly trimAutoWhitespace: boolean;
569 > readonly bracketPairColorizationOptions: BracketPairColorizationOptions;
570 >
571 > public get originalIndentSize(): number | 'tabSize' {
572 > return this._indentSizeIsTabSize ? 'tabSize' : this.indentSize;
573 > }
574 >
575 > /**
576 > * @internal
577 > */
578 > constructor(src: {
579 tabSize: number;
580 indentSize: number | 'tabSize';
597 this.bracketPairColorizationOptions = src.bracketPairColorizationOptions;
598 }
599 > model.ts
600 > /**
601 > * @internal
602 > */
603 > public equals(other: TextModelResolvedOptions): boolean {
604 return (
605 this.tabSize === other.tabSize
612 );
613 }
614 > model.ts
615 > /**
616 > * @internal
617 > */
618 > public createChangeEvent(newOpts: TextModelResolvedOptions): IModelOptionsChangedEvent {
619 return {
620 tabSize: this.tabSize !== newOpts.tabSize,
624 };
625 }
626 > } model.ts
627 >
628 > /**
629 > * @internal
630 > */
631 > export interface ITextModelCreationOptions {
632 > tabSize: number;
633 > indentSize: number | 'tabSize';
634 > insertSpaces: boolean;
635 > detectIndentation: boolean;
636 > trimAutoWhitespace: boolean;
637 > defaultEOL: DefaultEndOfLine;
638 > isForSimpleWidget: boolean;
639 > largeFileOptimizations: boolean;
640 > bracketPairColorizationOptions: BracketPairColorizationOptions;
641 > }
642 >
643 > export interface BracketPairColorizationOptions {
644 > enabled: boolean;
645 > independentColorPoolPerBracketType: boolean;
646 > }
647 >
648 > export interface ITextModelUpdateOptions {
649 > tabSize?: number;
650 > indentSize?: number | 'tabSize';
651 > insertSpaces?: boolean;
652 > trimAutoWhitespace?: boolean;
653 > bracketColorizationOptions?: BracketPairColorizationOptions;
654 > }
655 >
656 > export class FindMatch {
657 > _findMatchBrand: void = undefined;
658 >
659 > public readonly range: Range;
660 > public readonly matches: string[] | null;
661 >
662 > /**
663 > * @internal
664 > */
665 > constructor(range: Range, matches: string[] | null) {
666 this.range = range;
667 this.matches = matches;
668 }
669 > } model.ts
670 >
671 > /**
672 > * Describes the behavior of decorations when typing/editing near their edges.
673 > * Note: Please do not edit the values, as they very carefully match `DecorationRangeBehavior`
674 > */
675 > export const enum TrackedRangeStickiness {
676 > AlwaysGrowsWhenTypingAtEdges = 0,
677 > NeverGrowsWhenTypingAtEdges = 1,
678 > GrowsOnlyWhenTypingBefore = 2,
679 > GrowsOnlyWhenTypingAfter = 3,
680 > }
681 >
682 > /**
683 > * Text snapshot that works like an iterator.
684 > * Will try to return chunks of roughly ~64KB size.
685 > * Will return null when finished.
686 > */
687 > export interface ITextSnapshot {
688 > read(): string | null;
689 > }
690 >
691 > /**
692 > * @internal
693 > */
694 > export function isITextSnapshot(obj: unknown): obj is ITextSnapshot {
695 return (!!obj && typeof (obj as ITextSnapshot).read === 'function');
696 }
697 > model.ts
698 > /**
699 > * A model.
700 > */
701 > export interface ITextModel {
702 >
703 > /**
704 > * Gets the resource associated with this editor model.
705 > */
706 > readonly uri: URI;
707 >
708 > /**
709 > * A unique identifier associated with this model.
710 > */
711 > readonly id: string;
712 >
713 > /**
714 > * This model is constructed for a simple widget code editor.
715 > * @internal
716 > */
717 > readonly isForSimpleWidget: boolean;
718 >
719 > /**
720 > * Method to register a view model on a model
721 > * @internal
722 > */
723 > registerViewModel(viewModel: IViewModel): void;
724 >
725 > /**
726 > * Method which unregister a view model on a model
727 > * @internal
728 > */
729 > unregisterViewModel(viewModel: IViewModel): void;
730 >
731 > /**
732 > * If true, the text model might contain RTL.
733 > * If false, the text model **contains only** contain LTR.
734 > * @internal
735 > */
736 > mightContainRTL(): boolean;
737 >
738 > /**
739 > * If true, the text model might contain LINE SEPARATOR (LS), PARAGRAPH SEPARATOR (PS).
740 > * If false, the text model definitely does not contain these.
741 > * @internal
742 > */
743 > mightContainUnusualLineTerminators(): boolean;
744 >
745 > /**
746 > * @internal
747 > */
748 > removeUnusualLineTerminators(selections?: Selection[]): void;
749 >
750 > /**
751 > * If true, the text model might contain non basic ASCII.
752 > * If false, the text model **contains only** basic ASCII.
753 > * @internal
754 > */
755 > mightContainNonBasicASCII(): boolean;
756 >
757 > /**
758 > * Get the resolved options for this model.
759 > */
760 > getOptions(): TextModelResolvedOptions;
761 >
762 > /**
763 > * Get the formatting options for this model.
764 > * @internal
765 > */
766 > getFormattingOptions(): FormattingOptions;
767 >
768 > /**
769 > * Get the current version id of the model.
770 > * Anytime a change happens to the model (even undo/redo),
771 > * the version id is incremented.
772 > */
773 > getVersionId(): number;
774 >
775 > /**
776 > * Get the alternative version id of the model.
777 > * This alternative version id is not always incremented,
778 > * it will return the same values in the case of undo-redo.
779 > */
780 > getAlternativeVersionId(): number;
781 >
782 > /**
783 > * Replace the entire text buffer value contained in this model.
784 > */
785 > setValue(newValue: string | ITextSnapshot): void;
786 >
787 > /**
788 > * Get the text stored in this model.
789 > * @param eol The end of line character preference. Defaults to `EndOfLinePreference.TextDefined`.
790 > * @param preserverBOM Preserve a BOM character if it was detected when the model was constructed.
791 > * @return The text.
792 > */
793 > getValue(eol?: EndOfLinePreference, preserveBOM?: boolean): string;
794 >
795 > /**
796 > * Get the text stored in this model.
797 > * @param preserverBOM Preserve a BOM character if it was detected when the model was constructed.
798 > * @return The text snapshot (it is safe to consume it asynchronously).
799 > */
800 > createSnapshot(preserveBOM?: boolean): ITextSnapshot;
801 >
802 > /**
803 > * Get the length of the text stored in this model.
804 > */
805 > getValueLength(eol?: EndOfLinePreference, preserveBOM?: boolean): number;
806 >
807 > /**
808 > * Check if the raw text stored in this model equals another raw text.
809 > * @internal
810 > */
811 > equalsTextBuffer(other: ITextBuffer): boolean;
812 >
813 > /**
814 > * Get the underling text buffer.
815 > * @internal
816 > */
817 > getTextBuffer(): ITextBuffer;
818 >
819 > /**
820 > * Get the text in a certain range.
821 > * @param range The range describing what text to get.
822 > * @param eol The end of line character preference. This will only be used for multiline ranges. Defaults to `EndOfLinePreference.TextDefined`.
823 > * @return The text.
824 > */
825 > getValueInRange(range: IRange, eol?: EndOfLinePreference): string;
826 >
827 > /**
828 > * Get the length of text in a certain range.
829 > * @param range The range describing what text length to get.
830 > * @return The text length.
831 > */
832 > getValueLengthInRange(range: IRange, eol?: EndOfLinePreference): number;
833 >
834 > /**
835 > * Get the character count of text in a certain range.
836 > * @param range The range describing what text length to get.
837 > */
838 > getCharacterCountInRange(range: IRange, eol?: EndOfLinePreference): number;
839 >
840 > /**
841 > * Splits characters in two buckets. First bucket (A) is of characters that
842 > * sit in lines with length < `LONG_LINE_BOUNDARY`. Second bucket (B) is of
843 > * characters that sit in lines with length >= `LONG_LINE_BOUNDARY`.
844 > * If count(B) > count(A) return true. Returns false otherwise.
845 > * @internal
846 > */
847 > isDominatedByLongLines(): boolean;
848 >
849 > /**
850 > * Get the number of lines in the model.
851 > */
852 > getLineCount(): number;
853 >
854 > /**
855 > * Get the text for a certain line.
856 > */
857 > getLineContent(lineNumber: number): string;
858 >
859 > /**
860 > * Get the line injected text for a certain line.
861 > * @internal
862 > */
863 > getLineInjectedText(lineNumber: number, ownerId?: number): LineInjectedText[];
864 >
865 > /**
866 > * Get the text length for a certain line.
867 > */
868 > getLineLength(lineNumber: number): number;
869 >
870 > /**
871 > * Get the text for all lines.
872 > */
873 > getLinesContent(): string[];
874 >
875 > /**
876 > * Get the end of line sequence predominantly used in the text buffer.
877 > * @return EOL char sequence (e.g.: '\n' or '\r\n').
878 > */
879 > getEOL(): string;
880 >
881 > /**
882 > * Get the end of line sequence predominantly used in the text buffer.
883 > */
884 > getEndOfLineSequence(): EndOfLineSequence;
885 >
886 > /**
887 > * Get the minimum legal column for line at `lineNumber`
888 > */
889 > getLineMinColumn(lineNumber: number): number;
890 >
891 > /**
892 > * Get the maximum legal column for line at `lineNumber`
893 > */
894 > getLineMaxColumn(lineNumber: number): number;
895 >
896 > /**
897 > * Returns the column before the first non whitespace character for line at `lineNumber`.
898 > * Returns 0 if line is empty or contains only whitespace.
899 > */
900 > getLineFirstNonWhitespaceColumn(lineNumber: number): number;
901 >
902 > /**
903 > * Returns the column after the last non whitespace character for line at `lineNumber`.
904 > * Returns 0 if line is empty or contains only whitespace.
905 > */
906 > getLineLastNonWhitespaceColumn(lineNumber: number): number;
907 >
908 > /**
909 > * Create a valid position.
910 > */
911 > validatePosition(position: IPosition): Position;
912 >
913 > /**
914 > * Advances the given position by the given offset (negative offsets are also accepted)
915 > * and returns it as a new valid position.
916 > *
917 > * If the offset and position are such that their combination goes beyond the beginning or
918 > * end of the model, throws an exception.
919 > *
920 > * If the offset is such that the new position would be in the middle of a multi-byte
921 > * line terminator, throws an exception.
922 > */
923 > modifyPosition(position: IPosition, offset: number): Position;
924 >
925 > /**
926 > * Create a valid range.
927 > */
928 > validateRange(range: IRange): Range;
929 >
930 > /**
931 > * Verifies the range is valid.
932 > */
933 > isValidRange(range: IRange): boolean;
934 >
935 > /**
936 > * Converts the position to a zero-based offset.
937 > *
938 > * The position will be [adjusted](#TextDocument.validatePosition).
939 > *
940 > * @param position A position.
941 > * @return A valid zero-based offset.
942 > */
943 > getOffsetAt(position: IPosition): number;
944 >
945 > /**
946 > * Converts a zero-based offset to a position.
947 > *
948 > * @param offset A zero-based offset.
949 > * @return A valid [position](#Position).
950 > */
951 > getPositionAt(offset: number): Position;
952 >
953 > /**
954 > * Get a range covering the entire model.
955 > */
956 > getFullModelRange(): Range;
957 >
958 > /**
959 > * Returns if the model was disposed or not.
960 > */
961 > isDisposed(): boolean;
962 >
963 > /**
964 > * This model is so large that it would not be a good idea to sync it over
965 > * to web workers or other places.
966 > * @internal
967 > */
968 > isTooLargeForSyncing(): boolean;
969 >
970 > /**
971 > * The file is so large, that even tokenization is disabled.
972 > * @internal
973 > */
974 > isTooLargeForTokenization(): boolean;
975 >
976 > /**
977 > * The file is so large, that operations on it might be too large for heap
978 > * and can lead to OOM crashes so they should be disabled.
979 > * @internal
980 > */
981 > isTooLargeForHeapOperation(): boolean;
982 >
983 > /**
984 > * Search the model.
985 > * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.
986 > * @param searchOnlyEditableRange Limit the searching to only search inside the editable range of the model.
987 > * @param isRegex Used to indicate that `searchString` is a regular expression.
988 > * @param matchCase Force the matching to match lower/upper case exactly.
989 > * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.
990 > * @param captureMatches The result will contain the captured groups.
991 > * @param limitResultCount Limit the number of results
992 > * @return The ranges where the matches are. It is empty if not matches have been found.
993 > */
994 > findMatches(searchString: string, searchOnlyEditableRange: boolean, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean, limitResultCount?: number): FindMatch[];
995 > /**
996 > * Search the model.
997 > * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.
998 > * @param searchScope Limit the searching to only search inside these ranges.
999 > * @param isRegex Used to indicate that `searchString` is a regular expression.
1000 > * @param matchCase Force the matching to match lower/upper case exactly.
1001 > * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.
1002 > * @param captureMatches The result will contain the captured groups.
1003 > * @param limitResultCount Limit the number of results
1004 > * @return The ranges where the matches are. It is empty if no matches have been found.
1005 > */
1006 > findMatches(searchString: string, searchScope: IRange | IRange[], isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean, limitResultCount?: number): FindMatch[];
1007 > /**
1008 > * Search the model for the next match. Loops to the beginning of the model if needed.
1009 > * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.
1010 > * @param searchStart Start the searching at the specified position.
1011 > * @param isRegex Used to indicate that `searchString` is a regular expression.
1012 > * @param matchCase Force the matching to match lower/upper case exactly.
1013 > * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.
1014 > * @param captureMatches The result will contain the captured groups.
1015 > * @return The range where the next match is. It is null if no next match has been found.
1016 > */
1017 > findNextMatch(searchString: string, searchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean): FindMatch | null;
1018 > /**
1019 > * Search the model for the previous match. Loops to the end of the model if needed.
1020 > * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.
1021 > * @param searchStart Start the searching at the specified position.
1022 > * @param isRegex Used to indicate that `searchString` is a regular expression.
1023 > * @param matchCase Force the matching to match lower/upper case exactly.
1024 > * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.
1025 > * @param captureMatches The result will contain the captured groups.
1026 > * @return The range where the previous match is. It is null if no previous match has been found.
1027 > */
1028 > findPreviousMatch(searchString: string, searchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean): FindMatch | null;
1029 >
1030 >
1031 > /**
1032 > * Get the language associated with this model.
1033 > */
1034 > getLanguageId(): string;
1035 >
1036 > /**
1037 > * Set the current language mode associated with the model.
1038 > * @param languageId The new language.
1039 > * @param source The source of the call that set the language.
1040 > * @internal
1041 > */
1042 > setLanguage(languageId: string, source?: string): void;
1043 >
1044 > /**
1045 > * Set the current language mode associated with the model.
1046 > * @param languageSelection The new language selection.
1047 > * @param source The source of the call that set the language.
1048 > * @internal
1049 > */
1050 > setLanguage(languageSelection: ILanguageSelection, source?: string): void;
1051 >
1052 > /**
1053 > * Returns the real (inner-most) language mode at a given position.
1054 > * The result might be inaccurate. Use `forceTokenization` to ensure accurate tokens.
1055 > * @internal
1056 > */
1057 > getLanguageIdAtPosition(lineNumber: number, column: number): string;
1058 >
1059 > /**
1060 > * Get the word under or besides `position`.
1061 > * @param position The position to look for a word.
1062 > * @return The word under or besides `position`. Might be null.
1063 > */
1064 > getWordAtPosition(position: IPosition): IWordAtPosition | null;
1065 >
1066 > /**
1067 > * Get the word under or besides `position` trimmed to `position`.column
1068 > * @param position The position to look for a word.
1069 > * @return The word under or besides `position`. Will never be null.
1070 > */
1071 > getWordUntilPosition(position: IPosition): IWordAtPosition;
1072 >
1073 > /**
1074 > * Change the decorations. The callback will be called with a change accessor
1075 > * that becomes invalid as soon as the callback finishes executing.
1076 > * This allows for all events to be queued up until the change
1077 > * is completed. Returns whatever the callback returns.
1078 > * @param ownerId Identifies the editor id in which these decorations should appear. If no `ownerId` is provided, the decorations will appear in all editors that attach this model.
1079 > * @internal
1080 > */
1081 > changeDecorations<T>(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T, ownerId?: number): T | null;
1082 >
1083 > /**
1084 > * Perform a minimum amount of operations, in order to transform the decorations
1085 > * identified by `oldDecorations` to the decorations described by `newDecorations`
1086 > * and returns the new identifiers associated with the resulting decorations.
1087 > *
1088 > * @param oldDecorations Array containing previous decorations identifiers.
1089 > * @param newDecorations Array describing what decorations should result after the call.
1090 > * @param ownerId Identifies the editor id in which these decorations should appear. If no `ownerId` is provided, the decorations will appear in all editors that attach this model.
1091 > * @return An array containing the new decorations identifiers.
1092 > */
1093 > deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[], ownerId?: number): string[];
1094 >
1095 > /**
1096 > * Remove all decorations that have been added with this specific ownerId.
1097 > * @param ownerId The owner id to search for.
1098 > * @internal
1099 > */
1100 > removeAllDecorationsWithOwnerId(ownerId: number): void;
1101 >
1102 > /**
1103 > * Get the options associated with a decoration.
1104 > * @param id The decoration id.
1105 > * @return The decoration options or null if the decoration was not found.
1106 > */
1107 > getDecorationOptions(id: string): IModelDecorationOptions | null;
1108 >
1109 > /**
1110 > * Get the range associated with a decoration.
1111 > * @param id The decoration id.
1112 > * @return The decoration range or null if the decoration was not found.
1113 > */
1114 > getDecorationRange(id: string): Range | null;
1115 >
1116 > /**
1117 > * Gets all the decorations for the line `lineNumber` as an array.
1118 > * @param lineNumber The line number
1119 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1120 > * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
1121 > * @param filterFontDecorations If set, it will ignore font decorations.
1122 > * @return An array with the decorations
1123 > */
1124 > getLineDecorations(lineNumber: number, ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean): IModelDecoration[];
1125 >
1126 > /**
1127 > * Gets all the font decorations for the line `lineNumber` as an array.
1128 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1129 > * @internal
1130 > */
1131 > getFontDecorationsInRange(range: IRange, ownerId?: number): IModelDecoration[];
1132 >
1133 > /**
1134 > * Gets all the decorations for the lines between `startLineNumber` and `endLineNumber` as an array.
1135 > * @param startLineNumber The start line number
1136 > * @param endLineNumber The end line number
1137 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1138 > * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
1139 > * @param filterFontDecorations If set, it will ignore font decorations.
1140 > * @return An array with the decorations
1141 > */
1142 > getLinesDecorations(startLineNumber: number, endLineNumber: number, ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean): IModelDecoration[];
1143 >
1144 > /**
1145 > * Gets all the decorations in a range as an array. Only `startLineNumber` and `endLineNumber` from `range` are used for filtering.
1146 > * So for now it returns all the decorations on the same line as `range`.
1147 > * @param range The range to search in
1148 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1149 > * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
1150 > * @param filterFontDecorations If set, it will ignore font decorations.
1151 > * @param onlyMinimapDecorations If set, it will return only decorations that render in the minimap.
1152 > * @param onlyMarginDecorations If set, it will return only decorations that render in the glyph margin.
1153 > * @return An array with the decorations
1154 > */
1155 > getDecorationsInRange(range: IRange, ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean, onlyMinimapDecorations?: boolean, onlyMarginDecorations?: boolean): IModelDecoration[];
1156 >
1157 > /**
1158 > * Gets all the decorations as an array.
1159 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1160 > * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
1161 > * @param filterFontDecorations If set, it will ignore font decorations.
1162 > */
1163 > getAllDecorations(ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean): IModelDecoration[];
1164 >
1165 > /**
1166 > * Gets all decorations that render in the glyph margin as an array.
1167 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1168 > */
1169 > getAllMarginDecorations(ownerId?: number): IModelDecoration[];
1170 >
1171 > /**
1172 > * Gets all the decorations that should be rendered in the overview ruler as an array.
1173 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1174 > * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
1175 > * @param filterFontDecorations If set, it will ignore font decorations.
1176 > */
1177 > getOverviewRulerDecorations(ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean): IModelDecoration[];
1178 >
1179 > /**
1180 > * Gets all the decorations that contain injected text.
1181 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1182 > */
1183 > getInjectedTextDecorations(ownerId?: number): IModelDecoration[];
1184 >
1185 > /**
1186 > * Gets all the decorations that contain custom line heights.
1187 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1188 > */
1189 > getCustomLineHeightsDecorations(ownerId?: number): IModelDecoration[];
1190 >
1191 > /**
1192 > * Gets all the decorations that contain custom line heights.
1193 > * @param range The range to search in
1194 > * @param ownerId If set, it will ignore decorations belonging to other owners.
1195 > */
1196 > getCustomLineHeightsDecorationsInRange(range: Range, ownerId?: number): IModelDecoration[];
1197 >
1198 > /**
1199 > * @internal
1200 > */
1201 > _getTrackedRange(id: string): Range | null;
1202 >
1203 > /**
1204 > * @internal
1205 > */
1206 > _setTrackedRange(id: string | null, newRange: null, newStickiness: TrackedRangeStickiness): null;
1207 > /**
1208 > * @internal
1209 > */
1210 > _setTrackedRange(id: string | null, newRange: Range, newStickiness: TrackedRangeStickiness): string;
1211 >
1212 > /**
1213 > * Normalize a string containing whitespace according to indentation rules (converts to spaces or to tabs).
1214 > */
1215 > normalizeIndentation(str: string): string;
1216 >
1217 > /**
1218 > * Change the options of this model.
1219 > */
1220 > updateOptions(newOpts: ITextModelUpdateOptions): void;
1221 >
1222 > /**
1223 > * Detect the indentation options for this model from its content.
1224 > */
1225 > detectIndentation(defaultInsertSpaces: boolean, defaultTabSize: number): void;
1226 >
1227 > /**
1228 > * Close the current undo-redo element.
1229 > * This offers a way to create an undo/redo stop point.
1230 > */
1231 > pushStackElement(): void;
1232 >
1233 > /**
1234 > * Open the current undo-redo element.
1235 > * This offers a way to remove the current undo/redo stop point.
1236 > */
1237 > popStackElement(): void;
1238 >
1239 > /**
1240 > * @internal
1241 > */
1242 > edit(edit: TextEdit, options?: { reason?: TextModelEditSource }): void;
1243 >
1244 > /**
1245 > * Push edit operations, basically editing the model. This is the preferred way
1246 > * of editing the model. The edit operations will land on the undo stack.
1247 > * @param beforeCursorState The cursor state before the edit operations. This cursor state will be returned when `undo` or `redo` are invoked.
1248 > * @param editOperations The edit operations.
1249 > * @param cursorStateComputer A callback that can compute the resulting cursors state after the edit operations have been executed.
1250 > * @return The cursor state returned by the `cursorStateComputer`.
1251 > */
1252 > pushEditOperations(beforeCursorState: Selection[] | null, editOperations: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer): Selection[] | null;
1253 > /**
1254 > * @internal
1255 > */
1256 > pushEditOperations(beforeCursorState: Selection[] | null, editOperations: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer, group?: UndoRedoGroup, reason?: TextModelEditSource): Selection[] | null;
1257 >
1258 > /**
1259 > * Change the end of line sequence. This is the preferred way of
1260 > * changing the eol sequence. This will land on the undo stack.
1261 > */
1262 > pushEOL(eol: EndOfLineSequence): void;
1263 >
1264 > /**
1265 > * Edit the model without adding the edits to the undo stack.
1266 > * This can have dire consequences on the undo stack! See @pushEditOperations for the preferred way.
1267 > * @param operations The edit operations.
1268 > * @return If desired, the inverse edit operations, that, when applied, will bring the model back to the previous state.
1269 > */
1270 > applyEdits(operations: readonly IIdentifiedSingleEditOperation[]): void;
1271 > /** @internal */
1272 > applyEdits(operations: readonly IIdentifiedSingleEditOperation[], reason: TextModelEditSource): void;
1273 > applyEdits(operations: readonly IIdentifiedSingleEditOperation[], computeUndoEdits: false): void;
1274 > applyEdits(operations: readonly IIdentifiedSingleEditOperation[], computeUndoEdits: true): IValidEditOperation[];
1275 >
1276 > /**
1277 > * Change the end of line sequence without recording in the undo stack.
1278 > * This can have dire consequences on the undo stack! See @pushEOL for the preferred way.
1279 > */
1280 > setEOL(eol: EndOfLineSequence): void;
1281 >
1282 > /**
1283 > * @internal
1284 > */
1285 > _applyUndo(changes: TextChange[], eol: EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void;
1286 >
1287 > /**
1288 > * @internal
1289 > */
1290 > _applyRedo(changes: TextChange[], eol: EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void;
1291 >
1292 > /**
1293 > * Undo edit operations until the previous undo/redo point.
1294 > * The inverse edit operations will be pushed on the redo stack.
1295 > */
1296 > undo(): void | Promise<void>;
1297 >
1298 > /**
1299 > * Is there anything in the undo stack?
1300 > */
1301 > canUndo(): boolean;
1302 >
1303 > /**
1304 > * Redo edit operations until the next undo/redo point.
1305 > * The inverse edit operations will be pushed on the undo stack.
1306 > */
1307 > redo(): void | Promise<void>;
1308 >
1309 > /**
1310 > * Is there anything in the redo stack?
1311 > */
1312 > canRedo(): boolean;
1313 >
1314 > /**
1315 > * An event emitted when the contents of the model have changed.
1316 > * @event
1317 > */
1318 > onDidChangeContent(listener: (e: IModelContentChangedEvent) => void): IDisposable;
1319 > /**
1320 > * An event emitted when decorations of the model have changed.
1321 > * @event
1322 > */
1323 > readonly onDidChangeDecorations: Event<IModelDecorationsChangedEvent>;
1324 > /**
1325 > * An event emitted when line heights from decorations changes.
1326 > * This event is emitted only when adding, removing or changing a decoration
1327 > * and not when doing edits in the model (i.e. when decoration ranges change)
1328 > * @internal
1329 > * @event
1330 > */
1331 > readonly onDidChangeLineHeight: Event<ModelLineHeightChangedEvent>;
1332 > /**
1333 > * An event emitted when the font from decorations changes.
1334 > * This event is emitted only when adding, removing or changing a decoration
1335 > * and not when doing edits in the model (i.e. when decoration ranges change)
1336 > * @internal
1337 > * @event
1338 > */
1339 > readonly onDidChangeFont: Event<ModelFontChangedEvent>;
1340 > /**
1341 > * An event emitted when the model options have changed.
1342 > * @event
1343 > */
1344 > readonly onDidChangeOptions: Event<IModelOptionsChangedEvent>;
1345 > /**
1346 > * An event emitted when the language associated with the model has changed.
1347 > * @event
1348 > */
1349 > readonly onDidChangeLanguage: Event<IModelLanguageChangedEvent>;
1350 > /**
1351 > * An event emitted when the language configuration associated with the model has changed.
1352 > * @event
1353 > */
1354 > readonly onDidChangeLanguageConfiguration: Event<IModelLanguageConfigurationChangedEvent>;
1355 > /**
1356 > * An event emitted when the tokens associated with the model have changed.
1357 > * @event
1358 > * @internal
1359 > */
1360 > readonly onDidChangeTokens: Event<IModelTokensChangedEvent>;
1361 > /**
1362 > * An event emitted when the model has been attached to the first editor or detached from the last editor.
1363 > * @event
1364 > */
1365 > readonly onDidChangeAttached: Event<void>;
1366 > /**
1367 > * An event emitted right before disposing the model.
1368 > * @event
1369 > */
1370 > readonly onWillDispose: Event<void>;
1371 >
1372 > /**
1373 > * Destroy this model.
1374 > */
1375 > dispose(): void;
1376 >
1377 > /**
1378 > * @internal
1379 > */
1380 > onBeforeAttached(): IAttachedView;
1381 >
1382 > /**
1383 > * @internal
1384 > */
1385 > onBeforeDetached(view: IAttachedView): void;
1386 >
1387 > /**
1388 > * Returns if this model is attached to an editor or not.
1389 > */
1390 > isAttachedToEditor(): boolean;
1391 >
1392 > /**
1393 > * Returns the count of editors this model is attached to.
1394 > * @internal
1395 > */
1396 > getAttachedEditorCount(): number;
1397 >
1398 > /**
1399 > * Among all positions that are projected to the same position in the underlying text model as
1400 > * the given position, select a unique position as indicated by the affinity.
1401 > *
1402 > * PositionAffinity.Left:
1403 > * The normalized position must be equal or left to the requested position.
1404 > *
1405 > * PositionAffinity.Right:
1406 > * The normalized position must be equal or right to the requested position.
1407 > *
1408 > * @internal
1409 > */
1410 > normalizePosition(position: Position, affinity: PositionAffinity): Position;
1411 >
1412 > /**
1413 > * Gets the column at which indentation stops at a given line.
1414 > * @internal
1415 > */
1416 > getLineIndentColumn(lineNumber: number): number;
1417 >
1418 > /**
1419 > * Returns an object that can be used to query brackets.
1420 > * @internal
1421 > */
1422 > readonly bracketPairs: IBracketPairsTextModelPart;
1423 >
1424 > /**
1425 > * Returns an object that can be used to query indent guides.
1426 > * @internal
1427 > */
1428 > readonly guides: IGuidesTextModelPart;
1429 >
1430 > /**
1431 > * @internal
1432 > */
1433 > readonly tokenization: ITokenizationTextModelPart;
1434 > }
1435 >
1436 > /**
1437 > * @internal
1438 > */
1439 > export function isITextModel(obj: IEditorModel): obj is ITextModel {
1440 return Boolean(obj && (obj as ITextModel).uri);
1441 }
1442 > model.ts
1443 > /**
1444 > * @internal
1445 > */
1446 > export interface IAttachedView {
1447 > /**
1448 > * @param stabilized Indicates if the visible lines are probably going to change soon or can be considered stable.
1449 > * Is true on reveal range and false on scroll.
1450 > * Tokenizers should tokenize synchronously if stabilized is true.
1451 > */
1452 > setVisibleLines(visibleLines: { startLineNumber: number; endLineNumber: number }[], stabilized: boolean): void;
1453 > }
1454 >
1455 > export const enum PositionAffinity {
1456 > /**
1457 > * Prefers the left most position.
1458 > */
1459 > Left = 0,
1460 >
1461 > /**
1462 > * Prefers the right most position.
1463 > */
1464 > Right = 1,
1465 >
1466 > /**
1467 > * No preference.
1468 > */
1469 > None = 2,
1470 >
1471 > /**
1472 > * If the given position is on injected text, prefers the position left of it.
1473 > */
1474 > LeftOfInjectedText = 3,
1475 >
1476 > /**
1477 > * If the given position is on injected text, prefers the position right of it.
1478 > */
1479 > RightOfInjectedText = 4,
1480 > }
1481 >
1482 > /**
1483 > * @internal
1484 > */
1485 > export interface ITextBufferBuilder {
1486 > acceptChunk(chunk: string): void;
1487 > finish(): ITextBufferFactory;
1488 > }
1489 >
1490 > /**
1491 > * @internal
1492 > */
1493 > export interface ITextBufferFactory {
1494 > create(defaultEOL: DefaultEndOfLine): { textBuffer: ITextBuffer; disposable: IDisposable };
1495 > getFirstLineText(lengthLimit: number): string;
1496 > }
1497 >
1498 > /**
1499 > * @internal
1500 > */
1501 > export const enum ModelConstants {
1502 > FIRST_LINE_DETECTION_LENGTH_LIMIT = 1000
1503 > }
1504 >
1505 > /**
1506 > * @internal
1507 > */
1508 > export class ValidAnnotatedEditOperation implements IIdentifiedSingleEditOperation {
1509 > constructor(
1510 public readonly identifier: ISingleEditOperationIdentifier | null,
1511 public readonly range: Range,
1515 public readonly _isTracked: boolean,
1516 ) { }
1517 > } model.ts
1518 >
1519 > /**
1520 > * @internal
1521 > *
1522 > * `lineNumber` is 1 based.
1523 > */
1524 > export interface IReadonlyTextBuffer {
1525 > readonly onDidChangeContent: Event<void>;
1526 > equals(other: ITextBuffer): boolean;
1527 > mightContainRTL(): boolean;
1528 > mightContainUnusualLineTerminators(): boolean;
1529 > resetMightContainUnusualLineTerminators(): void;
1530 > mightContainNonBasicASCII(): boolean;
1531 > getBOM(): string;
1532 > getEOL(): string;
1533 >
1534 > getOffsetAt(lineNumber: number, column: number): number;
1535 > getPositionAt(offset: number): Position;
1536 > getRangeAt(offset: number, length: number): Range;
1537 >
1538 > getValueInRange(range: Range, eol: EndOfLinePreference): string;
1539 > createSnapshot(preserveBOM: boolean): ITextSnapshot;
1540 > getValueLengthInRange(range: Range, eol: EndOfLinePreference): number;
1541 > getCharacterCountInRange(range: Range, eol: EndOfLinePreference): number;
1542 > getLength(): number;
1543 > getLineCount(): number;
1544 > getLinesContent(): string[];
1545 > getLineContent(lineNumber: number): string;
1546 > getLineCharCode(lineNumber: number, index: number): number;
1547 > getCharCode(offset: number): number;
1548 > getLineLength(lineNumber: number): number;
1549 > getLineMinColumn(lineNumber: number): number;
1550 > getLineMaxColumn(lineNumber: number): number;
1551 > getLineFirstNonWhitespaceColumn(lineNumber: number): number;
1552 > getLineLastNonWhitespaceColumn(lineNumber: number): number;
1553 > findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[];
1554 >
1555 > /**
1556 > * Get nearest chunk of text after `offset` in the text buffer.
1557 > */
1558 > getNearestChunk(offset: number): string;
1559 > }
1560 >
1561 > /**
1562 > * @internal
1563 > */
1564 > export class SearchData {
1565 >
1566 > /**
1567 > * The regex to search for. Always defined.
1568 > */
1569 > public readonly regex: RegExp;
1570 > /**
1571 > * The word separator classifier.
1572 > */
1573 > public readonly wordSeparators: WordCharacterClassifier | null;
1574 > /**
1575 > * The simple string to search for (if possible).
1576 > */
1577 > public readonly simpleSearch: string | null;
1578 >
1579 > constructor(regex: RegExp, wordSeparators: WordCharacterClassifier | null, simpleSearch: string | null) {
1580 this.regex = regex;
1581 this.wordSeparators = wordSeparators;
1582 this.simpleSearch = simpleSearch;
1583 }
1584 > } model.ts
1585 >
1586 > /**
1587 > * @internal
1588 > */
1589 > export interface ITextBuffer extends IReadonlyTextBuffer, IDisposable {
1590 > setEOL(newEOL: '\r\n' | '\n'): void;
1591 > applyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult;
1592 > }
1593 >
1594 > /**
1595 > * @internal
1596 > */
1597 > export class ApplyEditsResult {
1598 >
1599 > constructor(
1600 public readonly reverseEdits: IValidEditOperation[] | null,
1601 public readonly changes: IInternalModelContentChange[],
1602 public readonly trimAutoWhitespaceLineNumbers: number[] | null
1603 ) { }
1604 > model.ts
1605 > }
1606 >
1607 > /**
1608 > * @internal
1609 > */
1610 > export interface IInternalModelContentChange extends IModelContentChange {
1611 > range: Range;
1612 > forceMoveMarkers: boolean;
1613 > }
1614 >
1615 > /**
1616 > * @internal
1617 > */
1618 > export function shouldSynchronizeModel(model: ITextModel): boolean {
1619 return (
1620 !model.isTooLargeForSyncing() && !model.isForSimpleWidget
src/vs/base/common/async.ts 1238 covered LOC · 202 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- async.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 { BugIndicatingError, CancellationError, isCancellationError } from './errors.js';
8 > import { Emitter, Event } from './event.js';
9 > import { Disposable, DisposableMap, DisposableStore, IDisposable, isDisposable, MutableDisposable, toDisposable } from './lifecycle.js';
10 > import { extUri as defaultExtUri, IExtUri } from './resources.js';
11 > import { URI } from './uri.js';
12 > import { setTimeout0 } from './platform.js';
13 > import { MicrotaskDelay } from './symbols.js';
14 > import { Lazy } from './lazy.js';
15 >
16 > export function isThenable<T>(obj: unknown): obj is Promise<T> {
17 return !!obj && typeof (obj as unknown as Promise<T>).then === 'function';
18 }
19 > async.ts
20 > export interface CancelablePromise<T> extends Promise<T> {
21 > cancel(): void;
22 > }
23 >
24 > /**
25 > * Returns a promise that can be cancelled using the provided cancellation token.
26 > *
27 > * @remarks When cancellation is requested, the promise will be rejected with a {@link CancellationError}.
28 > * If the promise resolves to a disposable object, it will be automatically disposed when cancellation
29 > * is requested.
30 > *
31 > * @param callback A function that accepts a cancellation token and returns a promise
32 > * @returns A promise that can be cancelled
33 > */
34 > export function createCancelablePromise<T>(callback: (token: CancellationToken) => Promise<T>): CancelablePromise<T> {
35 const source = new CancellationTokenSource();
36
80 };
81 }
82 > async.ts
83 > /**
84 > * Returns a promise that resolves with `undefined` as soon as the passed token is cancelled.
85 > * @see {@link raceCancellationError}
86 > */
87 > export function raceCancellation<T>(promise: Promise<T>, token: CancellationToken): Promise<T | undefined>;
88 >
89 > /**
90 > * Returns a promise that resolves with `defaultValue` as soon as the passed token is cancelled.
91 > * @see {@link raceCancellationError}
92 > */
93 > export function raceCancellation<T>(promise: Promise<T>, token: CancellationToken, defaultValue: T): Promise<T>;
94 >
95 > export function raceCancellation<T>(promise: Promise<T>, token: CancellationToken, defaultValue?: T): Promise<T | undefined> {
96 return new Promise((resolve, reject) => {
97 const ref = token.onCancellationRequested(() => {
102 });
103 }
104 > async.ts
105 > /**
106 > * Returns a promise that rejects with an {@CancellationError} as soon as the passed token is cancelled.
107 > * @see {@link raceCancellation}
108 > */
109 > export function raceCancellationError<T>(promise: Promise<T>, token: CancellationToken): Promise<T> {
110 return new Promise((resolve, reject) => {
111 const ref = token.onCancellationRequested(() => {
116 });
117 }
118 > async.ts
119 > export function rejectIfNotCanceled(err: unknown): undefined {
120 if (isCancellationError(err)) {
121 return undefined;
123 return Promise.reject(err) as never;
124 }
125 > async.ts
126 > /**
127 > * Wraps a cancellable promise such that it is no cancellable. Can be used to
128 > * avoid issues with shared promises that would normally be returned as
129 > * cancellable to consumers.
130 > */
131 > export function notCancellablePromise<T>(promise: CancelablePromise<T>): Promise<T> {
132 return new Promise<T>((resolve, reject) => {
133 promise.then(resolve, reject);
134 });
135 }
136 > async.ts
137 > /**
138 > * Returns as soon as one of the promises resolves or rejects and cancels remaining promises
139 > */
140 > export function raceCancellablePromises<T>(cancellablePromises: (CancelablePromise<T> | Promise<T>)[]): CancelablePromise<T> {
141 let resolvedPromiseIndex = -1;
142 const promises = cancellablePromises.map((promise, index) => promise.then(result => { resolvedPromiseIndex = index; return result; }));
154 return promise;
155 }
156 > async.ts
157 > export function raceTimeout<T>(promise: Promise<T>, timeout: number, onTimeout?: () => void): Promise<T | undefined> {
158 let promiseResolve: ((value: T | undefined) => void) | undefined = undefined;
159
168 ]);
169 }
170 > async.ts
171 > export function asPromise<T>(callback: () => T | Thenable<T>): Promise<T> {
172 return new Promise<T>((resolve, reject) => {
173 const item = callback();
179 });
180 }
181 > async.ts
182 > /**
183 > * Creates and returns a new promise, plus its `resolve` and `reject` callbacks.
184 > *
185 > * Replace with standardized [`Promise.withResolvers`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers) once it is supported
186 > */
187 > export function promiseWithResolvers<T>(): { promise: Promise<T>; resolve: (value: T | PromiseLike<T>) => void; reject: (err?: any) => void } {
188 let resolve: (value: T | PromiseLike<T>) => void;
189 let reject: (reason?: any) => void;
194 return { promise, resolve: resolve!, reject: reject! };
195 }
196 > async.ts
197 > export interface ITask<T> {
198 > (): T;
199 > }
200 >
201 > export interface ICancellableTask<T> {
202 > (token: CancellationToken): T;
203 > }
204 >
205 > /**
206 > * A helper to prevent accumulation of sequential async tasks.
207 > *
208 > * Imagine a mail man with the sole task of delivering letters. As soon as
209 > * a letter submitted for delivery, he drives to the destination, delivers it
210 > * and returns to his base. Imagine that during the trip, N more letters were submitted.
211 > * When the mail man returns, he picks those N letters and delivers them all in a
212 > * single trip. Even though N+1 submissions occurred, only 2 deliveries were made.
213 > *
214 > * The throttler implements this via the queue() method, by providing it a task
215 > * factory. Following the example:
216 > *
217 > * const throttler = new Throttler();
218 > * const letters = [];
219 > *
220 > * function deliver() {
221 > * const lettersToDeliver = letters;
222 > * letters = [];
223 > * return makeTheTrip(lettersToDeliver);
224 > * }
225 > *
226 > * function onLetterReceived(l) {
227 > * letters.push(l);
228 > * throttler.queue(deliver);
229 > * }
230 > */
231 > export class Throttler implements IDisposable {
232 >
233 > private activePromise: Promise<any> | null;
234 > private queuedPromise: Promise<any> | null;
235 > private queuedPromiseFactory: ICancellableTask<Promise<any>> | null;
236 > private cancellationTokenSource: CancellationTokenSource;
237 >
238 > constructor() {
239 this.activePromise = null;
240 this.queuedPromise = null;
243 this.cancellationTokenSource = new CancellationTokenSource();
244 }
245 > async.ts
246 > queue<T>(promiseFactory: ICancellableTask<Promise<T>>): Promise<T> {
247 if (this.cancellationTokenSource.token.isCancellationRequested) {
248 return Promise.reject(new Error('Throttler is disposed'));
288 });
289 }
290 > async.ts
291 > dispose(): void {
292 this.cancellationTokenSource.cancel();
293 }
294 > } async.ts
295 >
296 > export class Sequencer {
297
298 private current: Promise<unknown> = Promise.resolve(null);
299 > async.ts
300 > queue<T>(promiseTask: ITask<Promise<T>>): Promise<T> {
301 return this.current = this.current.then(() => promiseTask(), () => promiseTask());
302 }
303 > } async.ts
304 >
305 > /**
306 > * A {@link Throttler} per key. Calls for the same key coalesce (only the most
307 > * recently queued task runs after the active one settles); calls for different
308 > * keys are independent. Idle keys are cleaned up automatically.
309 > */
310 > export class ThrottlerByKey<TKey> implements IDisposable {
311
312 private readonly throttlers = new Map<TKey, { throttler: Throttler; count: number }>();
313 > async.ts
314 > queue<T>(key: TKey, task: ITask<Promise<T>>): Promise<T> {
315 let entry = this.throttlers.get(key);
316 if (!entry) {
327 });
328 }
329 > async.ts
330 > dispose(): void {
331 for (const { throttler } of this.throttlers.values()) {
332 throttler.dispose();
334 this.throttlers.clear();
335 }
336 > } async.ts
337 >
338 > export class SequencerByKey<TKey> {
339
340 private promiseMap = new Map<TKey, Promise<unknown>>();
341 > async.ts
342 > queue<T>(key: TKey, promiseTask: ITask<Promise<T>>): Promise<T> {
343 const runningPromise = this.promiseMap.get(key) ?? Promise.resolve();
344 const newPromise = runningPromise
353 return newPromise;
354 }
355 > async.ts
356 > peek(key: TKey): Promise<unknown> | undefined {
357 return this.promiseMap.get(key) || undefined;
358 }
359 > async.ts
360 > keys(): IterableIterator<TKey> {
361 return this.promiseMap.keys();
362 }
363 > } async.ts
364 >
365 > interface IScheduledLater extends IDisposable {
366 > isTriggered(): boolean;
367 > }
368 >
369 > const timeoutDeferred = (timeout: number, fn: () => void): IScheduledLater => {
370 let scheduled = true;
371 const handle = setTimeout(() => {
381 };
382 };
383 > async.ts
384 > const microtaskDeferred = (fn: () => void): IScheduledLater => {
385 let scheduled = true;
386 queueMicrotask(() => {
396 };
397 };
398 > async.ts
399 > /**
400 > * A helper to delay (debounce) execution of a task that is being requested often.
401 > *
402 > * Following the throttler, now imagine the mail man wants to optimize the number of
403 > * trips proactively. The trip itself can be long, so he decides not to make the trip
404 > * as soon as a letter is submitted. Instead he waits a while, in case more
405 > * letters are submitted. After said waiting period, if no letters were submitted, he
406 > * decides to make the trip. Imagine that N more letters were submitted after the first
407 > * one, all within a short period of time between each other. Even though N+1
408 > * submissions occurred, only 1 delivery was made.
409 > *
410 > * The delayer offers this behavior via the trigger() method, into which both the task
411 > * to be executed and the waiting period (delay) must be passed in as arguments. Following
412 > * the example:
413 > *
414 > * const delayer = new Delayer(WAITING_PERIOD);
415 > * const letters = [];
416 > *
417 > * function letterReceived(l) {
418 > * letters.push(l);
419 > * delayer.trigger(() => { return makeTheTrip(); });
420 > * }
421 > */
422 > export class Delayer<T> implements IDisposable {
423 >
424 > private deferred: IScheduledLater | null;
425 > private completionPromise: Promise<any> | null;
426 > private doResolve: ((value?: any | Promise<any>) => void) | null;
427 > private doReject: ((err: unknown) => void) | null;
428 > private task: ITask<T | Promise<T>> | null;
429 >
430 > constructor(public defaultDelay: number | typeof MicrotaskDelay) {
431 this.deferred = null;
432 this.completionPromise = null;
435 this.task = null;
436 }
437 > async.ts
438 > trigger(task: ITask<T | Promise<T>>, delay = this.defaultDelay): Promise<T> {
439 this.task = task;
440 this.cancelTimeout();
465 return this.completionPromise;
466 }
467 > async.ts
468 > isTriggered(): boolean {
469 return !!this.deferred?.isTriggered();
470 }
471 > async.ts
472 > cancel(): void {
473 this.cancelTimeout();
474
478 }
479 }
480 > async.ts
481 > private cancelTimeout(): void {
482 this.deferred?.dispose();
483 this.deferred = null;
484 }
485 > async.ts
486 > dispose(): void {
487 this.cancel();
488 }
489 > } async.ts
490 >
491 > /**
492 > * A helper to delay execution of a task that is being requested often, while
493 > * preventing accumulation of consecutive executions, while the task runs.
494 > *
495 > * The mail man is clever and waits for a certain amount of time, before going
496 > * out to deliver letters. While the mail man is going out, more letters arrive
497 > * and can only be delivered once he is back. Once he is back the mail man will
498 > * do one more trip to deliver the letters that have accumulated while he was out.
499 > */
500 > export class ThrottledDelayer<T> {
501 >
502 > private delayer: Delayer<Promise<T>>;
503 > private throttler: Throttler;
504 >
505 > constructor(defaultDelay: number) {
506 this.delayer = new Delayer(defaultDelay);
507 this.throttler = new Throttler();
508 }
509 > async.ts
510 > trigger(promiseFactory: ICancellableTask<Promise<T>>, delay?: number): Promise<T> {
511 return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay) as unknown as Promise<T>;
512 }
513 > async.ts
514 > isTriggered(): boolean {
515 return this.delayer.isTriggered();
516 }
517 > async.ts
518 > cancel(): void {
519 this.delayer.cancel();
520 }
521 > async.ts
522 > dispose(): void {
523 this.delayer.dispose();
524 this.throttler.dispose();
525 }
526 > } async.ts
527 >
528 > /**
529 > * A barrier that is initially closed and then becomes opened permanently.
530 > */
531 > export class Barrier {
532 > private _isOpen: boolean;
533 > private _promise: Promise<boolean>;
534 > private _completePromise!: (v: boolean) => void;
535 >
536 > constructor() {
537 this._isOpen = false;
538 this._promise = new Promise<boolean>((c, e) => {
540 });
541 }
542 > async.ts
543 > isOpen(): boolean {
544 return this._isOpen;
545 }
546 > async.ts
547 > open(): void {
548 this._isOpen = true;
549 this._completePromise(true);
550 }
551 > async.ts
552 > wait(): Promise<boolean> {
553 return this._promise;
554 }
555 > } async.ts
556 >
557 > /**
558 > * A barrier that is initially closed and then becomes opened permanently after a certain period of
559 > * time or when open is called explicitly
560 > */
561 > export class AutoOpenBarrier extends Barrier {
562 >
563 > private readonly _timeout: Timeout;
564 >
565 > constructor(autoOpenTimeMs: number) {
566 super();
567 this._timeout = setTimeout(() => this.open(), autoOpenTimeMs);
568 }
569 > async.ts
570 > override open(): void {
571 clearTimeout(this._timeout);
572 super.open();
573 }
574 > } async.ts
575 >
576 > export function timeout(millis: number): CancelablePromise<void>;
577 > export function timeout(millis: number, token: CancellationToken): Promise<void>;
578 > export function timeout(millis: number, token?: CancellationToken): CancelablePromise<void> | Promise<void> {
579 if (!token) {
580 return createCancelablePromise(token => timeout(millis, token));
593 });
594 }
595 > async.ts
596 > /**
597 > * Creates a timeout that can be disposed using its returned value.
598 > * @param handler The timeout handler.
599 > * @param timeout An optional timeout in milliseconds.
600 > * @param store An optional {@link DisposableStore} that will have the timeout disposable managed automatically.
601 > *
602 > * @example
603 > * const store = new DisposableStore;
604 > * // Call the timeout after 1000ms at which point it will be automatically
605 > * // evicted from the store.
606 > * const timeoutDisposable = disposableTimeout(() => {}, 1000, store);
607 > *
608 > * if (foo) {
609 > * // Cancel the timeout and evict it from store.
610 > * timeoutDisposable.dispose();
611 > * }
612 > */
613 > export function disposableTimeout(handler: () => void, timeout = 0, store?: DisposableStore): IDisposable {
614 const timer = setTimeout(() => {
615 handler();
625 return disposable;
626 }
627 > async.ts
628 > /**
629 > * The largest delay (in milliseconds) a single `setTimeout` can represent.
630 > * Larger values overflow its internal 32-bit signed integer and fire (almost)
631 > * immediately instead of waiting.
632 > */
633 > export const MAX_TIMEOUT_DELAY = 2 ** 31 - 1; // ~24.8 days
634 >
635 > /**
636 > * Like {@link disposableTimeout}, but supports delays larger than
637 > * {@link MAX_TIMEOUT_DELAY} (~24.8 days), which a single `setTimeout` cannot
638 > * represent. The wait is split into chunks and re-armed until the target time is
639 > * reached, so the handler fires at approximately `Date.now() + timeout`.
640 > *
641 > * Note: like `setTimeout`, firing is best-effort and may drift across system
642 > * sleep or wall-clock changes; do not rely on it for precise scheduling.
643 > *
644 > * @param handler The timeout handler.
645 > * @param timeout The timeout in milliseconds. May exceed {@link MAX_TIMEOUT_DELAY}.
646 > * @param store An optional {@link DisposableStore} that will have the timeout disposable managed automatically.
647 > */
648 > export function disposableLongTimeout(handler: () => void, timeout: number, store?: DisposableStore): IDisposable {
649 const target = Date.now() + timeout;
650 let timer: Timeout;
671 return disposable;
672 }
673 > async.ts
674 > /**
675 > * Runs the provided list of promise factories in sequential order. The returned
676 > * promise will complete to an array of results from each promise.
677 > */
678 >
679 > export function sequence<T>(promiseFactories: ITask<Promise<T>>[]): Promise<T[]> {
680 const results: T[] = [];
681 let index = 0;
701 return Promise.resolve(null).then(thenHandler);
702 }
703 > async.ts
704 > export function first<T>(promiseFactories: ITask<Promise<T>>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T | null = null): Promise<T | null> {
705 let index = 0;
706 const len = promiseFactories.length;
725 return loop();
726 }
727 > async.ts
728 > /**
729 > * Returns the result of the first promise that matches the "shouldStop",
730 > * running all promises in parallel. Supports cancelable promises.
731 > */
732 > export function firstParallel<T>(promiseList: Promise<T>[], shouldStop?: (t: T) => boolean, defaultValue?: T | null): Promise<T | null>;
733 > export function firstParallel<T, R extends T>(promiseList: Promise<T>[], shouldStop: (t: T) => t is R, defaultValue?: R | null): Promise<R | null>;
734 > export function firstParallel<T>(promiseList: Promise<T>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T | null = null) {
735 if (promiseList.length === 0) {
736 return Promise.resolve(defaultValue);
764 });
765 }
766 > async.ts
767 > interface ILimitedTaskFactory<T> {
768 > factory: ITask<Promise<T>>;
769 > c: (value: T | Promise<T>) => void;
770 > e: (error?: unknown) => void;
771 > }
772 >
773 > export interface ILimiter<T> {
774 >
775 > readonly size: number;
776 >
777 > queue(factory: ITask<Promise<T>>): Promise<T>;
778 >
779 > clear(): void;
780 > }
781 >
782 > /**
783 > * A helper to queue N promises and run them all with a max degree of parallelism. The helper
784 > * ensures that at any time no more than M promises are running at the same time.
785 > */
786 > export class Limiter<T> implements ILimiter<T> {
787 >
788 > private _size = 0;
789 > private _isDisposed = false;
790 > private runningPromises: number;
791 > private readonly maxDegreeOfParalellism: number;
792 > private readonly outstandingPromises: ILimitedTaskFactory<T>[];
793 > private readonly _onDrained: Emitter<void>;
794 >
795 > constructor(maxDegreeOfParalellism: number) {
796 this.maxDegreeOfParalellism = maxDegreeOfParalellism;
797 this.outstandingPromises = [];
799 this._onDrained = new Emitter<void>();
800 }
801 > async.ts
802 > /**
803 > *
804 > * @returns A promise that resolved when all work is done (onDrained) or when
805 > * there is nothing to do
806 > */
807 > whenIdle(): Promise<void> {
808 return this.size > 0
809 ? Event.toPromise(this.onDrained)
810 : Promise.resolve();
811 }
812 > async.ts
813 > get onDrained(): Event<void> {
814 return this._onDrained.event;
815 }
816 > async.ts
817 > get size(): number {
818 return this._size;
819 }
820 > async.ts
821 > queue(factory: ITask<Promise<T>>): Promise<T> {
822 if (this._isDisposed) {
823 throw new Error('Object has been disposed');
830 });
831 }
832 > async.ts
833 > private consume(): void {
834 while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) {
835 const iLimitedTask = this.outstandingPromises.shift()!;
841 }
842 }
843 > async.ts
844 > private consumed(): void {
845 if (this._isDisposed) {
846 return;
855 }
856 }
857 > async.ts
858 > clear(): void {
859 if (this._isDisposed) {
860 throw new Error('Object has been disposed');
863 this._size = this.runningPromises;
864 }
865 > async.ts
866 > dispose(): void {
867 this._isDisposed = true;
868 this.outstandingPromises.length = 0; // stop further processing
870 this._onDrained.dispose();
871 }
872 > } async.ts
873 >
874 > /**
875 > * A queue is handles one promise at a time and guarantees that at any time only one promise is executing.
876 > */
877 > export class Queue<T> extends Limiter<T> {
878 >
879 > constructor() {
880 super(1);
881 }
882 > } async.ts
883 >
884 > /**
885 > * Same as `Queue`, ensures that only 1 task is executed at the same time. The difference to `Queue` is that
886 > * there is only 1 task about to be scheduled next. As such, calling `queue` while a task is executing will
887 > * replace the currently queued task until it executes.
888 > *
889 > * As such, the returned promise may not be from the factory that is passed in but from the next factory that
890 > * is running after having called `queue`.
891 > */
892 > export class LimitedQueue {
893
894 private readonly sequentializer = new TaskSequentializer();
895
896 private tasks = 0;
897 > async.ts
898 > queue(factory: ITask<Promise<void>>): Promise<void> {
899 if (!this.sequentializer.isRunning()) {
900 return this.sequentializer.run(this.tasks++, factory());
905 });
906 }
907 > } async.ts
908 >
909 > /**
910 > * A helper to organize queues per resource. The ResourceQueue makes sure to manage queues per resource
911 > * by disposing them once the queue is empty.
912 > */
913 > export class ResourceQueue implements IDisposable {
914
915 private readonly queues = new Map<string, Queue<void>>();
919 private drainListeners: DisposableMap<number> | undefined = undefined;
920 private drainListenerCount = 0;
921 > async.ts
922 > async whenDrained(): Promise<void> {
923 if (this.isDrained()) {
924 return;
930 return promise.p;
931 }
932 > async.ts
933 > private isDrained(): boolean {
934 for (const [, queue] of this.queues) {
935 if (queue.size > 0) {
940 return true;
941 }
942 > async.ts
943 > queueSize(resource: URI, extUri: IExtUri = defaultExtUri): number {
944 const key = extUri.getComparisonKey(resource);
945
946 return this.queues.get(key)?.size ?? 0;
947 }
948 > async.ts
949 > queueFor(resource: URI, factory: ITask<Promise<void>>, extUri: IExtUri = defaultExtUri): Promise<void> {
950 const key = extUri.getComparisonKey(resource);
951
977 return queue.queue(factory);
978 }
979 > async.ts
980 > private onDidQueueDrain(): void {
981 if (!this.isDrained()) {
982 return; // not done yet
985 this.releaseDrainers();
986 }
987 > async.ts
988 > private releaseDrainers(): void {
989 for (const drainer of this.drainers) {
990 drainer.complete();
993 this.drainers.clear();
994 }
995 > async.ts
996 > dispose(): void {
997 for (const [, queue] of this.queues) {
998 queue.dispose();
1011 this.drainListeners?.dispose();
1012 }
1013 > } async.ts
1014 >
1015 > export type Task<T = void> = () => (Promise<T> | T);
1016 >
1017 > /**
1018 > * Wrap a type in an optional promise. This can be useful to avoid the runtime
1019 > * overhead of creating a promise.
1020 > */
1021 > export type MaybePromise<T> = Promise<T> | T;
1022 >
1023 > /**
1024 > * Processes tasks in the order they were scheduled.
1025 > */
1026 > export class TaskQueue {
1027 private _runningTask: Task<any> | undefined = undefined;
1028 private _pendingTasks: { task: Task<any>; deferred: DeferredPromise<any>; setUndefinedWhenCleared: boolean }[] = [];
1029 > async.ts
1030 > /**
1031 > * Waits for the current and pending tasks to finish, then runs and awaits the given task.
1032 > * If the task is skipped because of clearPending, the promise is rejected with a CancellationError.
1033 > */
1034 > public schedule<T>(task: Task<T>): Promise<T> {
1035 const deferred = new DeferredPromise<T>();
1036 this._pendingTasks.push({ task, deferred, setUndefinedWhenCleared: false });
1038 return deferred.p;
1039 }
1040 > async.ts
1041 > /**
1042 > * Waits for the current and pending tasks to finish, then runs and awaits the given task.
1043 > * If the task is skipped because of clearPending, the promise is resolved with undefined.
1044 > */
1045 > public scheduleSkipIfCleared<T>(task: Task<T>): Promise<T | undefined> {
1046 const deferred = new DeferredPromise<T>();
1047 this._pendingTasks.push({ task, deferred, setUndefinedWhenCleared: true });
1049 return deferred.p;
1050 }
1051 > async.ts
1052 > private _runIfNotRunning(): void {
1053 if (this._runningTask === undefined) {
1054 this._processQueue();
1055 }
1056 }
1057 > async.ts
1058 > private async _processQueue(): Promise<void> {
1059 if (this._pendingTasks.length === 0) {
1060 return;
1082 }
1083 }
1084 > async.ts
1085 > /**
1086 > * Clears all pending tasks. Does not cancel the currently running task.
1087 > */
1088 > public clearPending(): void {
1089 const tasks = this._pendingTasks;
1090 this._pendingTasks = [];
1097 }
1098 }
1099 > } async.ts
1100 >
1101 > export class TimeoutTimer implements IDisposable {
1102 > private _token: Timeout | undefined;
1103 > private _isDisposed = false;
1104 >
1105 > constructor();
1106 > constructor(runner: () => void, timeout: number);
1107 > constructor(runner?: () => void, timeout?: number) {
1108 this._token = undefined;
1109
1112 }
1113 }
1114 > async.ts
1115 > dispose(): void {
1116 this.cancel();
1117 this._isDisposed = true;
1118 }
1119 > async.ts
1120 > cancel(): void {
1121 if (this._token !== undefined) {
1122 clearTimeout(this._token);
1124 }
1125 }
1126 > async.ts
1127 > cancelAndSet(runner: () => void, timeout: number): void {
1128 if (this._isDisposed) {
1129 throw new BugIndicatingError(`Calling 'cancelAndSet' on a disposed TimeoutTimer`);
1136 }, timeout);
1137 }
1138 > async.ts
1139 > setIfNotSet(runner: () => void, timeout: number): void {
1140 if (this._isDisposed) {
1141 throw new BugIndicatingError(`Calling 'setIfNotSet' on a disposed TimeoutTimer`);
1151 }, timeout);
1152 }
1153 > } async.ts
1154 >
1155 > export class IntervalTimer implements IDisposable {
1156
1157 private disposable: IDisposable | undefined = undefined;
1158 private isDisposed = false;
1159 > async.ts
1160 > cancel(): void {
1161 this.disposable?.dispose();
1162 this.disposable = undefined;
1163 }
1164 > async.ts
1165 > cancelAndSet(runner: () => void, interval: number, context = globalThis): void {
1166 if (this.isDisposed) {
1167 throw new BugIndicatingError(`Calling 'cancelAndSet' on a disposed IntervalTimer`);
1178 });
1179 }
1180 > async.ts
1181 > dispose(): void {
1182 this.cancel();
1183 this.isDisposed = true;
1184 }
1185 > } async.ts
1186 >
1187 > export class RunOnceScheduler<Runner extends (...args: any[]) => any = () => any> implements IDisposable {
1188 >
1189 > protected runner: Runner | null;
1190 >
1191 > private timeoutToken: Timeout | undefined;
1192 > private timeout: number;
1193 > private timeoutHandler: () => void;
1194 >
1195 > constructor(runner: Runner, delay: number) {
1196 this.timeoutToken = undefined;
1197 this.runner = runner;
1199 this.timeoutHandler = this.onTimeout.bind(this);
1200 }
1201 > async.ts
1202 > /**
1203 > * Dispose RunOnceScheduler
1204 > */
1205 > dispose(): void {
1206 this.cancel();
1207 this.runner = null;
1208 }
1209 > async.ts
1210 > /**
1211 > * Cancel current scheduled runner (if any).
1212 > */
1213 > cancel(): void {
1214 if (this.isScheduled()) {
1215 clearTimeout(this.timeoutToken);
1217 }
1218 }
1219 > async.ts
1220 > /**
1221 > * Cancel previous runner (if any) & schedule a new runner.
1222 > */
1223 > schedule(delay = this.timeout): void {
1224 this.cancel();
1225 this.timeoutToken = setTimeout(this.timeoutHandler, delay);
1226 }
1227 > async.ts
1228 > get delay(): number {
1229 return this.timeout;
1230 }
1231 > async.ts
1232 > set delay(value: number) {
1233 this.timeout = value;
1234 }
1235 > async.ts
1236 > /**
1237 > * Returns true if scheduled.
1238 > */
1239 > isScheduled(): boolean {
1240 return this.timeoutToken !== undefined;
1241 }
1242 > async.ts
1243 > flush(): void {
1244 if (this.isScheduled()) {
1245 this.cancel();
1247 }
1248 }
1249 > async.ts
1250 > private onTimeout() {
1251 this.timeoutToken = undefined;
1252 if (this.runner) {
1254 }
1255 }
1256 > async.ts
1257 > protected doRun(): void {
1258 this.runner?.();
1259 }
1260 > } async.ts
1261 >
1262 > /**
1263 > * Same as `RunOnceScheduler`, but doesn't count the time spent in sleep mode.
1264 > * > **NOTE**: Only offers 1s resolution.
1265 > *
1266 > * When calling `setTimeout` with 3hrs, and putting the computer immediately to sleep
1267 > * for 8hrs, `setTimeout` will fire **as soon as the computer wakes from sleep**. But
1268 > * this scheduler will execute 3hrs **after waking the computer from sleep**.
1269 > */
1270 > export class ProcessTimeRunOnceScheduler {
1271 >
1272 > private runner: (() => void) | null;
1273 > private timeout: number;
1274 >
1275 > private counter: number;
1276 > private intervalToken: Timeout | undefined;
1277 > private intervalHandler: () => void;
1278 >
1279 > constructor(runner: () => void, delay: number) {
1280 if (delay % 1000 !== 0) {
1281 console.warn(`ProcessTimeRunOnceScheduler resolution is 1s, ${delay}ms is not a multiple of 1000ms.`);
1287 this.intervalHandler = this.onInterval.bind(this);
1288 }
1289 > async.ts
1290 > dispose(): void {
1291 this.cancel();
1292 this.runner = null;
1293 }
1294 > async.ts
1295 > cancel(): void {
1296 if (this.isScheduled()) {
1297 clearInterval(this.intervalToken);
1299 }
1300 }
1301 > async.ts
1302 > /**
1303 > * Cancel previous runner (if any) & schedule a new runner.
1304 > */
1305 > schedule(delay = this.timeout): void {
1306 if (delay % 1000 !== 0) {
1307 console.warn(`ProcessTimeRunOnceScheduler resolution is 1s, ${delay}ms is not a multiple of 1000ms.`);
1311 this.intervalToken = setInterval(this.intervalHandler, 1000);
1312 }
1313 > async.ts
1314 > /**
1315 > * Returns true if scheduled.
1316 > */
1317 > isScheduled(): boolean {
1318 return this.intervalToken !== undefined;
1319 }
1320 > async.ts
1321 > private onInterval() {
1322 this.counter--;
1323 if (this.counter > 0) {
1331 this.runner?.();
1332 }
1333 > } async.ts
1334 >
1335 > export class RunOnceWorker<T> extends RunOnceScheduler<(units: T[]) => void> {
1336 >
1337 > private units: T[] = [];
1338 >
1339 > constructor(runner: (units: T[]) => void, timeout: number) {
1340 super(runner, timeout);
1341 }
1342 > async.ts
1343 > work(unit: T): void {
1344 this.units.push(unit);
1345
1348 }
1349 }
1350 > async.ts
1351 > protected override doRun(): void {
1352 const units = this.units;
1353 this.units = [];
1355 this.runner?.(units);
1356 }
1357 > async.ts
1358 > override dispose(): void {
1359 this.units = [];
1360
1361 super.dispose();
1362 }
1363 > } async.ts
1364 >
1365 > export interface IThrottledWorkerOptions {
1366 >
1367 > /**
1368 > * maximum of units the worker will pass onto handler at once
1369 > */
1370 > maxWorkChunkSize: number;
1371 >
1372 > /**
1373 > * maximum of units the worker will keep in memory for processing
1374 > */
1375 > maxBufferedWork: number | undefined;
1376 >
1377 > /**
1378 > * delay before processing the next round of chunks when chunk size exceeds limits
1379 > */
1380 > throttleDelay: number;
1381 >
1382 > /**
1383 > * When enabled will guarantee that two distinct calls to `work()` are not executed
1384 > * without throttle delay between them.
1385 > * Otherwise if the worker isn't currently throttling it will execute work immediately.
1386 > */
1387 > waitThrottleDelayBetweenWorkUnits?: boolean;
1388 > }
1389 >
1390 > /**
1391 > * The `ThrottledWorker` will accept units of work `T`
1392 > * to handle. The contract is:
1393 > * * there is a maximum of units the worker can handle at once (via `maxWorkChunkSize`)
1394 > * * there is a maximum of units the worker will keep in memory for processing (via `maxBufferedWork`)
1395 > * * after having handled `maxWorkChunkSize` units, the worker needs to rest (via `throttleDelay`)
1396 > */
1397 > export class ThrottledWorker<T> extends Disposable {
1398 >
1399 > private readonly pendingWork: T[] = [];
1400 >
1401 > private readonly throttler = this._register(new MutableDisposable<RunOnceScheduler>());
1402 > private disposed = false;
1403 > private lastExecutionTime = 0;
1404 >
1405 > constructor(
1406 private options: IThrottledWorkerOptions,
1407 private readonly handler: (units: T[]) => void
1409 super();
1410 }
1411 > async.ts
1412 > /**
1413 > * The number of work units that are pending to be processed.
1414 > */
1415 > get pending(): number { return this.pendingWork.length; }
1416 >
1417 > /**
1418 > * Add units to be worked on. Use `pending` to figure out
1419 > * how many units are not yet processed after this method
1420 > * was called.
1421 > *
1422 > * @returns whether the work was accepted or not. If the
1423 > * worker is disposed, it will not accept any more work.
1424 > * If the number of pending units would become larger
1425 > * than `maxPendingWork`, more work will also not be accepted.
1426 > */
1427 > work(units: readonly T[]): boolean {
1428 if (this.disposed) {
1429 return false; // work not accepted: disposed
1469 return true; // work accepted
1470 }
1471 > async.ts
1472 > private doWork(): void {
1473 this.lastExecutionTime = Date.now();
1474
1481 }
1482 }
1483 > async.ts
1484 > private scheduleThrottler(delay = this.options.throttleDelay): void {
1485 this.throttler.value = new RunOnceScheduler(() => {
1486 this.throttler.clear();
1490 this.throttler.value.schedule();
1491 }
1492 > async.ts
1493 > override dispose(): void {
1494 super.dispose();
1495
1497 this.disposed = true;
1498 }
1499 > } async.ts
1500 >
1501 > //#region -- run on idle tricks ------------
1502 >
1503 > export interface IdleDeadline {
1504 > readonly didTimeout: boolean;
1505 > timeRemaining(): number;
1506 > }
1507 >
1508 > type IdleApi = Pick<typeof globalThis, 'requestIdleCallback' | 'cancelIdleCallback'>;
1509 >
1510 >
1511 > /**
1512 > * Execute the callback the next time the browser is idle, returning an
1513 > * {@link IDisposable} that will cancel the callback when disposed. This wraps
1514 > * [requestIdleCallback] so it will fallback to [setTimeout] if the environment
1515 > * doesn't support it.
1516 > *
1517 > * @param callback The callback to run when idle, this includes an
1518 > * [IdleDeadline] that provides the time alloted for the idle callback by the
1519 > * browser. Not respecting this deadline will result in a degraded user
1520 > * experience.
1521 > * @param timeout A timeout at which point to queue no longer wait for an idle
1522 > * callback but queue it on the regular event loop (like setTimeout). Typically
1523 > * this should not be used.
1524 > *
1525 > * [IdleDeadline]: https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline
1526 > * [requestIdleCallback]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
1527 > * [setTimeout]: https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout
1528 > *
1529 > * **Note** that there is `dom.ts#runWhenWindowIdle` which is better suited when running inside a browser
1530 > * context
1531 > */
1532 > export let runWhenGlobalIdle: (callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable;
1533 >
1534 > export let _runWhenIdle: (targetWindow: IdleApi, callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable;
1535 >
1536 > (function () {
1537 > const safeGlobal: any = globalThis;
1538 > if (typeof safeGlobal.requestIdleCallback !== 'function' || typeof safeGlobal.cancelIdleCallback !== 'function') {
1539 > _runWhenIdle = (_targetWindow, runner, timeout?) => {
1540 setTimeout0(() => {
1541 if (disposed) {
1561 };
1562 };
1563 > } else { async.ts
1564 _runWhenIdle = (targetWindow: typeof safeGlobal, runner, timeout?) => {
1565 const handle: number = targetWindow.requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined);
1576 };
1577 }
1578 > runWhenGlobalIdle = (runner, timeout) => _runWhenIdle(globalThis, runner, timeout); async.ts
1579 > })();
1580 >
1581 > export function installFakeRunWhenIdle(fakeImpl: typeof _runWhenIdle): IDisposable {
1582 const origRunWhenIdle = _runWhenIdle;
1583 const origRunWhenGlobalIdle = runWhenGlobalIdle;
1589 });
1590 }
1591 > async.ts
1592 > export abstract class AbstractIdleValue<T> {
1593 >
1594 > private readonly _executor: () => void;
1595 > private readonly _handle: IDisposable;
1596 >
1597 > private _didRun: boolean = false;
1598 > private _value?: T;
1599 > private _error: unknown;
1600 >
1601 > constructor(targetWindow: IdleApi, executor: () => T) {
1602 this._executor = () => {
1603 try {
1611 this._handle = _runWhenIdle(targetWindow, () => this._executor());
1612 }
1613 > async.ts
1614 > dispose(): void {
1615 this._handle.dispose();
1616 }
1617 > async.ts
1618 > get value(): T {
1619 if (!this._didRun) {
1620 this._handle.dispose();
1626 return this._value!;
1627 }
1628 > async.ts
1629 > get isInitialized(): boolean {
1630 return this._didRun;
1631 }
1632 > } async.ts
1633 >
1634 > /**
1635 > * An `IdleValue` that always uses the current window (which might be throttled or inactive)
1636 > *
1637 > * **Note** that there is `dom.ts#WindowIdleValue` which is better suited when running inside a browser
1638 > * context
1639 > */
1640 > export class GlobalIdleValue<T> extends AbstractIdleValue<T> {
1641 >
1642 > constructor(executor: () => T) {
1643 super(globalThis, executor);
1644 }
1645 > } async.ts
1646 >
1647 > //#endregion
1648 >
1649 export async function retry<T>(task: ITask<Promise<T>>, delay: number, retries: number): Promise<T> {
1650 let lastError: Error | undefined;
1662 throw lastError;
1663 }
1664 > async.ts
1665 > //#region Task Sequentializer
1666 >
1667 > interface IRunningTask {
1668 > readonly taskId: number;
1669 > readonly cancel: () => void;
1670 > readonly promise: Promise<void>;
1671 > }
1672 >
1673 > interface IQueuedTask {
1674 > readonly promise: Promise<void>;
1675 > readonly promiseResolve: () => void;
1676 > readonly promiseReject: (error: Error) => void;
1677 > run: ITask<Promise<void>>;
1678 > }
1679 >
1680 > export interface ITaskSequentializerWithRunningTask {
1681 > readonly running: Promise<void>;
1682 > }
1683 >
1684 > export interface ITaskSequentializerWithQueuedTask {
1685 > readonly queued: IQueuedTask;
1686 > }
1687 >
1688 > /**
1689 > * @deprecated use `LimitedQueue` instead for an easier to use API
1690 > */
1691 > export class TaskSequentializer {
1692 >
1693 > private _running?: IRunningTask;
1694 > private _queued?: IQueuedTask;
1695 >
1696 > isRunning(taskId?: number): this is ITaskSequentializerWithRunningTask {
1697 if (typeof taskId === 'number') {
1698 return this._running?.taskId === taskId;
1701 return !!this._running;
1702 }
1703 > async.ts
1704 > get running(): Promise<void> | undefined {
1705 return this._running?.promise;
1706 }
1707 > async.ts
1708 > cancelRunning(): void {
1709 this._running?.cancel();
1710 }
1711 > async.ts
1712 > run(taskId: number, promise: Promise<void>, onCancel?: () => void,): Promise<void> {
1713 this._running = { taskId, cancel: () => onCancel?.(), promise };
1714
1717 return promise;
1718 }
1719 > async.ts
1720 > private doneRunning(taskId: number): void {
1721 if (this._running && taskId === this._running.taskId) {
1722
1728 }
1729 }
1730 > async.ts
1731 > private runQueued(): void {
1732 if (this._queued) {
1733 const queued = this._queued;
1738 }
1739 }
1740 > async.ts
1741 > /**
1742 > * Note: the promise to schedule as next run MUST itself call `run`.
1743 > * Otherwise, this sequentializer will report `false` for `isRunning`
1744 > * even when this task is running. Missing this detail means that
1745 > * suddenly multiple tasks will run in parallel.
1746 > */
1747 > queue(run: ITask<Promise<void>>): Promise<void> {
1748
1749 // this is our first queued task, so we create associated promise with it
1767 return this._queued.promise;
1768 }
1769 > async.ts
1770 > hasQueued(): this is ITaskSequentializerWithQueuedTask {
1771 return !!this._queued;
1772 }
1773 > async.ts
1774 > async join(): Promise<void> {
1775 return this._queued?.promise ?? this._running?.promise;
1776 }
1777 > } async.ts
1778 >
1779 > //#endregion
1780 >
1781 > //#region
1782 >
1783 > /**
1784 > * The `IntervalCounter` allows to count the number
1785 > * of calls to `increment()` over a duration of
1786 > * `interval`. This utility can be used to conditionally
1787 > * throttle a frequent task when a certain threshold
1788 > * is reached.
1789 > */
1790 > export class IntervalCounter {
1791 >
1792 > private lastIncrementTime = 0;
1793 >
1794 > private value = 0;
1795 >
1796 > constructor(private readonly interval: number, private readonly nowFn = () => Date.now()) { }
1797 >
1798 > increment(): number {
1799 const now = this.nowFn();
1800
1810 return this.value;
1811 }
1812 > } async.ts
1813 >
1814 > //#endregion
1815 >
1816 > //#region
1817 >
1818 > export type ValueCallback<T = unknown> = (value: T | Promise<T>) => void;
1819 >
1820 > const enum DeferredOutcome {
1821 > Resolved,
1822 > Rejected
1823 > }
1824 >
1825 > /**
1826 > * Creates a promise whose resolution or rejection can be controlled imperatively.
1827 > */
1828 > export class DeferredPromise<T> {
1829 >
1830 > public static fromPromise<T>(promise: Promise<T>): DeferredPromise<T> {
1831 const deferred = new DeferredPromise<T>();
1832 deferred.settleWith(promise);
1833 return deferred;
1834 }
1835 > async.ts
1836 > private completeCallback!: ValueCallback<T>;
1837 > private errorCallback!: (err: unknown) => void;
1838 > private outcome?: { outcome: DeferredOutcome.Rejected; value: unknown } | { outcome: DeferredOutcome.Resolved; value: T };
1839 >
1840 > public get isRejected() {
1841 return this.outcome?.outcome === DeferredOutcome.Rejected;
1842 }
1843 > async.ts
1844 > public get isResolved() {
1845 return this.outcome?.outcome === DeferredOutcome.Resolved;
1846 }
1847 > async.ts
1848 > public get isSettled() {
1849 return !!this.outcome;
1850 }
1851 > async.ts
1852 > public get value() {
1853 return this.outcome?.outcome === DeferredOutcome.Resolved ? this.outcome?.value : undefined;
1854 }
1855 > async.ts
1856 > public readonly p: Promise<T>;
1857 >
1858 > constructor() {
1859 this.p = new Promise<T>((c, e) => {
1860 this.completeCallback = c;
1862 });
1863 }
1864 > async.ts
1865 > public complete(value: T) {
1866 if (this.isSettled) {
1867 return Promise.resolve();
1874 });
1875 }
1876 > async.ts
1877 > public error(err: unknown) {
1878 if (this.isSettled) {
1879 return Promise.resolve();
1886 });
1887 }
1888 > async.ts
1889 > public settleWith(promise: Promise<T>): Promise<void> {
1890 return promise.then(
1891 value => this.complete(value),
1893 );
1894 }
1895 > async.ts
1896 > public cancel() {
1897 return this.error(new CancellationError());
1898 }
1899 > } async.ts
1900 >
1901 > //#endregion
1902 >
1903 > //#region Promises
1904 >
1905 > export namespace Promises {
1906 >
1907 > /**
1908 > * A drop-in replacement for `Promise.all` with the only difference
1909 > * that the method awaits every promise to either fulfill or reject.
1910 > *
1911 > * Similar to `Promise.all`, only the first error will be returned
1912 > * if any.
1913 > */
1914 > export async function settled<T>(promises: Promise<T>[]): Promise<T[]> {
1915 let firstError: Error | undefined = undefined;
1916
1929 return result as unknown as T[]; // cast is needed and protected by the `throw` above
1930 }
1931 > async.ts
1932 > /**
1933 > * A helper to create a new `Promise<T>` with a body that is a promise
1934 > * itself. By default, an error that raises from the async body will
1935 > * end up as a unhandled rejection, so this utility properly awaits the
1936 > * body and rejects the promise as a normal promise does without async
1937 > * body.
1938 > *
1939 > * This method should only be used in rare cases where otherwise `async`
1940 > * cannot be used (e.g. when callbacks are involved that require this).
1941 > */
1942 > export function withAsyncBody<T, E = Error>(bodyFn: (resolve: (value: T) => unknown, reject: (error: E) => unknown) => Promise<unknown>): Promise<T> {
1943 // eslint-disable-next-line no-async-promise-executor
1944 return new Promise<T>(async (resolve, reject) => {
1950 });
1951 }
1952 > } async.ts
1953 >
1954 > export class StatefulPromise<T> {
1955 > private _value: T | undefined = undefined;
1956 > get value(): T | undefined { return this._value; }
1957 >
1958 > private _error: unknown = undefined;
1959 > get error(): unknown { return this._error; }
1960 >
1961 > private _isResolved = false;
1962 > get isResolved() { return this._isResolved; }
1963 >
1964 > public readonly promise: Promise<T>;
1965 >
1966 > constructor(promise: Promise<T>) {
1967 this.promise = promise.then(
1968 value => {
1978 );
1979 }
1980 > async.ts
1981 > /**
1982 > * Returns the resolved value.
1983 > * Throws if the promise is not resolved yet.
1984 > */
1985 > public requireValue(): T {
1986 if (!this._isResolved) {
1987 throw new BugIndicatingError('Promise is not resolved yet');
1992 return this._value!;
1993 }
1994 > } async.ts
1995 >
1996 > export class LazyStatefulPromise<T> {
1997 > private readonly _promise = new Lazy(() => new StatefulPromise(this._compute()));
1998 >
1999 > constructor(
2000 private readonly _compute: () => Promise<T>,
2001 ) { }
2002 > async.ts
2003 > /**
2004 > * Returns the resolved value.
2005 > * Throws if the promise is not resolved yet.
2006 > */
2007 > public requireValue(): T {
2008 return this._promise.value.requireValue();
2009 }
2010 > async.ts
2011 > /**
2012 > * Returns the promise (and triggers a computation of the promise if not yet done so).
2013 > */
2014 > public getPromise(): Promise<T> {
2015 return this._promise.value.promise;
2016 }
2017 > async.ts
2018 > /**
2019 > * Reads the current value without triggering a computation of the promise.
2020 > */
2021 > public get currentValue(): T | undefined {
2022 return this._promise.rawValue?.value;
2023 }
2024 > } async.ts
2025 >
2026 > //#endregion
2027 >
2028 > //#region
2029 >
2030 > const enum AsyncIterableSourceState {
2031 > Initial,
2032 > DoneOK,
2033 > DoneError,
2034 > }
2035 >
2036 > /**
2037 > * An object that allows to emit async values asynchronously or bring the iterable to an error state using `reject()`.
2038 > * This emitter is valid only for the duration of the executor (until the promise returned by the executor settles).
2039 > */
2040 > export interface AsyncIterableEmitter<T> {
2041 > /**
2042 > * The value will be appended at the end.
2043 > *
2044 > * **NOTE** If `reject()` has already been called, this method has no effect.
2045 > */
2046 > emitOne(value: T): void;
2047 > /**
2048 > * The values will be appended at the end.
2049 > *
2050 > * **NOTE** If `reject()` has already been called, this method has no effect.
2051 > */
2052 > emitMany(values: T[]): void;
2053 > /**
2054 > * Writing an error will permanently invalidate this iterable.
2055 > * The current users will receive an error thrown, as will all future users.
2056 > *
2057 > * **NOTE** If `reject()` have already been called, this method has no effect.
2058 > */
2059 > reject(error: Error): void;
2060 > }
2061 >
2062 > /**
2063 > * An executor for the `AsyncIterableObject` that has access to an emitter.
2064 > */
2065 > export interface AsyncIterableExecutor<T> {
2066 > /**
2067 > * @param emitter An object that allows to emit async values valid only for the duration of the executor.
2068 > */
2069 > (emitter: AsyncIterableEmitter<T>): unknown | Promise<unknown>;
2070 > }
2071 >
2072 > /**
2073 > * A rich implementation for an `AsyncIterable<T>`.
2074 > */
2075 > export class AsyncIterableObject<T> implements AsyncIterable<T> {
2076 >
2077 > public static fromArray<T>(items: T[]): AsyncIterableObject<T> {
2078 > return new AsyncIterableObject<T>((writer) => {
2079 > writer.emitMany(items);
2080 > });
2081 > }
2082 >
2083 > public static fromPromise<T>(promise: Promise<T[]>): AsyncIterableObject<T> {
2084 return new AsyncIterableObject<T>(async (emitter) => {
2085 emitter.emitMany(await promise);
2086 });
2087 }
2088 > async.ts
2089 > public static fromPromisesResolveOrder<T>(promises: Promise<T>[]): AsyncIterableObject<T> {
2090 return new AsyncIterableObject<T>(async (emitter) => {
2091 await Promise.all(promises.map(async (p) => emitter.emitOne(await p)));
2092 });
2093 }
2094 > async.ts
2095 > public static merge<T>(iterables: AsyncIterable<T>[]): AsyncIterableObject<T> {
2096 return new AsyncIterableObject(async (emitter) => {
2097 await Promise.all(iterables.map(async (iterable) => {
2102 });
2103 }
2104 > async.ts
2105 > public static EMPTY = AsyncIterableObject.fromArray<any>([]);
2106 >
2107 > private _state: AsyncIterableSourceState;
2108 > private _results: T[];
2109 > private _error: Error | null;
2110 > private readonly _onReturn?: () => void | Promise<void>;
2111 > private readonly _onStateChanged: Emitter<void>;
2112 >
2113 > constructor(executor: AsyncIterableExecutor<T>, onReturn?: () => void | Promise<void>) {
2114 > this._state = AsyncIterableSourceState.Initial;
2115 > this._results = [];
2116 > this._error = null;
2117 > this._onReturn = onReturn;
2118 > this._onStateChanged = new Emitter<void>();
2119 >
2120 > queueMicrotask(async () => {
2121 > const writer: AsyncIterableEmitter<T> = {
2122 > emitOne: (item) => this.emitOne(item),
2123 > emitMany: (items) => this.emitMany(items),
2124 > reject: (error) => this.reject(error)
2125 > };
2126 > try {
2127 > await Promise.resolve(executor(writer));
2128 > this.resolve();
2129 > } catch (err) {
2130 this.reject(err);
2131 > } finally { async.ts
2132 > // The executor has settled; emitting afterwards must be a no-op per the
2133 > // documented "no effect after resolve()/reject()" contract (see emitOne).
2134 > writer.emitOne = () => { };
2135 > writer.emitMany = () => { };
2136 > writer.reject = () => { };
2137 > }
2138 > });
2139 > }
2140 >
2141 > [Symbol.asyncIterator](): AsyncIterator<T, undefined, undefined> {
2142 let i = 0;
2143 return {
2162 };
2163 }
2164 > async.ts
2165 > public static map<T, R>(iterable: AsyncIterable<T>, mapFn: (item: T) => R): AsyncIterableObject<R> {
2166 return new AsyncIterableObject<R>(async (emitter) => {
2167 for await (const item of iterable) {
2170 });
2171 }
2172 > async.ts
2173 > public map<R>(mapFn: (item: T) => R): AsyncIterableObject<R> {
2174 return AsyncIterableObject.map(this, mapFn);
2175 }
2176 > async.ts
2177 > public static filter<T>(iterable: AsyncIterable<T>, filterFn: (item: T) => boolean): AsyncIterableObject<T> {
2178 return new AsyncIterableObject<T>(async (emitter) => {
2179 for await (const item of iterable) {
2184 });
2185 }
2186 > async.ts
2187 > public filter<T2 extends T>(filterFn: (item: T) => item is T2): AsyncIterableObject<T2>;
2188 > public filter(filterFn: (item: T) => boolean): AsyncIterableObject<T>;
2189 > public filter(filterFn: (item: T) => boolean): AsyncIterableObject<T> {
2190 return AsyncIterableObject.filter(this, filterFn);
2191 }
2192 > async.ts
2193 > public static coalesce<T>(iterable: AsyncIterable<T | undefined | null>): AsyncIterableObject<T> {
2194 return <AsyncIterableObject<T>>AsyncIterableObject.filter(iterable, item => !!item);
2195 }
2196 > async.ts
2197 > public coalesce(): AsyncIterableObject<NonNullable<T>> {
2198 return AsyncIterableObject.coalesce(this) as AsyncIterableObject<NonNullable<T>>;
2199 }
2200 > async.ts
2201 > public static async toPromise<T>(iterable: AsyncIterable<T>): Promise<T[]> {
2202 const result: T[] = [];
2203 for await (const item of iterable) {
2206 return result;
2207 }
2208 > async.ts
2209 > public toPromise(): Promise<T[]> {
2210 return AsyncIterableObject.toPromise(this);
2211 }
2212 > async.ts
2213 > /**
2214 > * The value will be appended at the end.
2215 > *
2216 > * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
2217 > */
2218 > private emitOne(value: T): void {
2219 if (this._state !== AsyncIterableSourceState.Initial) {
2220 return;
2225 this._onStateChanged.fire();
2226 }
2227 > async.ts
2228 > /**
2229 > * The values will be appended at the end.
2230 > *
2231 > * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
2232 > */
2233 > private emitMany(values: T[]): void {
2234 > if (this._state !== AsyncIterableSourceState.Initial) {
2235 return;
2236 }
2237 > // it is important to add new values at the end, async.ts
2238 > // as we may have iterators already running on the array
2239 > this._results = this._results.concat(values);
2240 > this._onStateChanged.fire();
2241 > }
2242 >
2243 > /**
2244 > * Calling `resolve()` will mark the result array as complete.
2245 > *
2246 > * **NOTE** `resolve()` must be called, otherwise all consumers of this iterable will hang indefinitely, similar to a non-resolved promise.
2247 > * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
2248 > */
2249 > private resolve(): void {
2250 > if (this._state !== AsyncIterableSourceState.Initial) {
2251 return;
2252 }
2253 > this._state = AsyncIterableSourceState.DoneOK; async.ts
2254 > this._onStateChanged.fire();
2255 > }
2256 >
2257 > /**
2258 > * Writing an error will permanently invalidate this iterable.
2259 > * The current users will receive an error thrown, as will all future users.
2260 > *
2261 > * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
2262 > */
2263 > private reject(error: Error) {
2264 if (this._state !== AsyncIterableSourceState.Initial) {
2265 return;
2269 this._onStateChanged.fire();
2270 }
2271 > } async.ts
2272 >
2273 >
2274 > export function createCancelableAsyncIterableProducer<T>(callback: (token: CancellationToken) => AsyncIterable<T>): CancelableAsyncIterableProducer<T> {
2275 const source = new CancellationTokenSource();
2276 const innerIterable = callback(source.token);
2299 });
2300 }
2301 > async.ts
2302 > export class AsyncIterableSource<T> {
2303 >
2304 > private readonly _deferred = new DeferredPromise<void>();
2305 > private readonly _asyncIterable: AsyncIterableObject<T>;
2306 >
2307 > private _errorFn: (error: Error) => void;
2308 > private _emitOneFn: (item: T) => void;
2309 > private _emitManyFn: (item: T[]) => void;
2310 >
2311 > /**
2312 > *
2313 > * @param onReturn A function that will be called when consuming the async iterable
2314 > * has finished by the consumer, e.g the for-await-loop has be existed (break, return) early.
2315 > * This is NOT called when resolving this source by its owner.
2316 > */
2317 > constructor(onReturn?: () => Promise<void> | void) {
2318 this._asyncIterable = new AsyncIterableObject(emitter => {
2319
2354 };
2355 }
2356 > async.ts
2357 > get asyncIterable(): AsyncIterableObject<T> {
2358 return this._asyncIterable;
2359 }
2360 > async.ts
2361 > resolve(): void {
2362 this._deferred.complete();
2363 }
2364 > async.ts
2365 > reject(error: Error): void {
2366 this._errorFn(error);
2367 this._deferred.complete();
2368 }
2369 > async.ts
2370 > emitOne(item: T): void {
2371 this._emitOneFn(item);
2372 }
2373 > async.ts
2374 > emitMany(items: T[]) {
2375 this._emitManyFn(items);
2376 }
2377 > } async.ts
2378 >
2379 > export function cancellableIterable<T>(iterableOrIterator: AsyncIterator<T> | AsyncIterable<T>, token: CancellationToken): AsyncIterableIterator<T> {
2380 const iterator = Symbol.asyncIterator in iterableOrIterator ? iterableOrIterator[Symbol.asyncIterator]() : iterableOrIterator;
2381
2395 };
2396 }
2397 > async.ts
2398 > type ProducerConsumerValue<T> = {
2399 > ok: true;
2400 > value: T;
2401 > } | {
2402 > ok: false;
2403 > error: Error;
2404 > };
2405 >
2406 > class ProducerConsumer<T> {
2407 > private readonly _unsatisfiedConsumers: DeferredPromise<T>[] = [];
2408 > private readonly _unconsumedValues: ProducerConsumerValue<T>[] = [];
2409 > private _finalValue: ProducerConsumerValue<T> | undefined;
2410 >
2411 > public get hasFinalValue(): boolean {
2412 > return !!this._finalValue;
2413 > }
2414 >
2415 > produce(value: ProducerConsumerValue<T>): void {
2416 this._ensureNoFinalValue();
2417 if (this._unsatisfiedConsumers.length > 0) {
2422 }
2423 }
2424 > async.ts
2425 > produceFinal(value: ProducerConsumerValue<T>): void {
2426 > this._ensureNoFinalValue();
2427 > this._finalValue = value;
2428 > for (const deferred of this._unsatisfiedConsumers) {
2429 this._resolveOrRejectDeferred(deferred, value);
2430 }
2431 > this._unsatisfiedConsumers.length = 0; async.ts
2432 > }
2433 >
2434 > private _ensureNoFinalValue(): void {
2435 > if (this._finalValue) {
2436 throw new BugIndicatingError('ProducerConsumer: cannot produce after final value has been set');
2437 }
2438 > } async.ts
2439 >
2440 > private _resolveOrRejectDeferred(deferred: DeferredPromise<T>, value: ProducerConsumerValue<T>): void {
2441 if (value.ok) {
2442 deferred.complete(value.value);
2445 }
2446 }
2447 > async.ts
2448 > consume(): Promise<T> {
2449 if (this._unconsumedValues.length > 0 || this._finalValue) {
2450 const value = this._unconsumedValues.length > 0 ? this._unconsumedValues.shift()! : this._finalValue!;
2460 }
2461 }
2462 > } async.ts
2463 >
2464 > /**
2465 > * Important difference to AsyncIterableObject:
2466 > * If it is iterated two times, the second iterator will not see the values emitted by the first iterator.
2467 > */
2468 > export class AsyncIterableProducer<T> implements AsyncIterable<T> {
2469 > private readonly _producerConsumer = new ProducerConsumer<IteratorResult<T>>();
2470 >
2471 > constructor(executor: AsyncIterableExecutor<T>, private readonly _onReturn?: () => void) {
2472 > queueMicrotask(async () => {
2473 > const p = executor({
2474 > emitOne: value => this._producerConsumer.produce({ ok: true, value: { done: false, value: value } }),
2475 > emitMany: values => {
2476 > for (const value of values) {
2477 this._producerConsumer.produce({ ok: true, value: { done: false, value: value } });
2478 }
2479 > }, async.ts
2480 > reject: error => this._finishError(error),
2481 > });
2482 >
2483 > if (!this._producerConsumer.hasFinalValue) {
2484 > try {
2485 > await p;
2486 > this._finishOk();
2487 > } catch (error) {
2488 this._finishError(error);
2489 }
2490 > } async.ts
2491 > });
2492 > }
2493 >
2494 > public static fromArray<T>(items: T[]): AsyncIterableProducer<T> {
2495 > return new AsyncIterableProducer<T>((writer) => {
2496 > writer.emitMany(items);
2497 > });
2498 > }
2499 >
2500 > public static fromPromise<T>(promise: Promise<T[]>): AsyncIterableProducer<T> {
2501 return new AsyncIterableProducer<T>(async (emitter) => {
2502 emitter.emitMany(await promise);
2503 });
2504 }
2505 > async.ts
2506 > public static fromPromisesResolveOrder<T>(promises: Promise<T>[]): AsyncIterableProducer<T> {
2507 return new AsyncIterableProducer<T>(async (emitter) => {
2508 await Promise.all(promises.map(async (p) => emitter.emitOne(await p)));
2509 });
2510 }
2511 > async.ts
2512 > public static merge<T>(iterables: AsyncIterable<T>[]): AsyncIterableProducer<T> {
2513 return new AsyncIterableProducer(async (emitter) => {
2514 await Promise.all(iterables.map(async (iterable) => {
2519 });
2520 }
2521 > async.ts
2522 > public static EMPTY = AsyncIterableProducer.fromArray<any>([]);
2523 >
2524 > public static map<T, R>(iterable: AsyncIterable<T>, mapFn: (item: T) => R): AsyncIterableProducer<R> {
2525 return new AsyncIterableProducer<R>(async (emitter) => {
2526 for await (const item of iterable) {
2529 });
2530 }
2531 > async.ts
2532 > public static tee<T>(iterable: AsyncIterable<T>): [AsyncIterableProducer<T>, AsyncIterableProducer<T>] {
2533 let emitter1: AsyncIterableEmitter<T> | undefined;
2534 let emitter2: AsyncIterableEmitter<T> | undefined;
2565 return [p1, p2];
2566 }
2567 > async.ts
2568 > public map<R>(mapFn: (item: T) => R): AsyncIterableProducer<R> {
2569 return AsyncIterableProducer.map(this, mapFn);
2570 }
2571 > async.ts
2572 > public static coalesce<T>(iterable: AsyncIterable<T | undefined | null>): AsyncIterableProducer<T> {
2573 return <AsyncIterableProducer<T>>AsyncIterableProducer.filter(iterable, item => !!item);
2574 }
2575 > async.ts
2576 > public coalesce(): AsyncIterableProducer<NonNullable<T>> {
2577 return AsyncIterableProducer.coalesce(this) as AsyncIterableProducer<NonNullable<T>>;
2578 }
2579 > async.ts
2580 > public static filter<T>(iterable: AsyncIterable<T>, filterFn: (item: T) => boolean): AsyncIterableProducer<T> {
2581 return new AsyncIterableProducer<T>(async (emitter) => {
2582 for await (const item of iterable) {
2587 });
2588 }
2589 > async.ts
2590 > public filter<T2 extends T>(filterFn: (item: T) => item is T2): AsyncIterableProducer<T2>;
2591 > public filter(filterFn: (item: T) => boolean): AsyncIterableProducer<T>;
2592 > public filter(filterFn: (item: T) => boolean): AsyncIterableProducer<T> {
2593 return AsyncIterableProducer.filter(this, filterFn);
2594 }
2595 > async.ts
2596 > private _finishOk(): void {
2597 > if (!this._producerConsumer.hasFinalValue) {
2598 > this._producerConsumer.produceFinal({ ok: true, value: { done: true, value: undefined } });
2599 > }
2600 > }
2601 >
2602 > private _finishError(error: Error): void {
2603 if (!this._producerConsumer.hasFinalValue) {
2604 this._producerConsumer.produceFinal({ ok: false, error: error });
2606 // Warning: this can cause to dropped errors.
2607 }
2608 > async.ts
2609 > private readonly _iterator: AsyncIterator<T, void, void> = {
2610 > next: () => this._producerConsumer.consume(),
2611 > return: () => {
2612 this._onReturn?.();
2613 return Promise.resolve({ done: true, value: undefined });
2614 },
2615 > throw: async (e) => { async.ts
2616 this._finishError(e);
2617 return { done: true, value: undefined };
2618 },
2619 > }; async.ts
2620 >
2621 > [Symbol.asyncIterator](): AsyncIterator<T, void, void> {
2622 return this._iterator;
2623 }
2624 > } async.ts
2625 >
2626 > export class CancelableAsyncIterableProducer<T> extends AsyncIterableProducer<T> {
2627 > constructor(
2628 private readonly _source: CancellationTokenSource,
2629 executor: AsyncIterableExecutor<T>
2631 super(executor);
2632 }
2633 > async.ts
2634 > cancel(): void {
2635 this._source.cancel();
2636 }
2637 > } async.ts
2638 >
2639 > //#endregion
2640 >
2641 > export const AsyncReaderEndOfStream = Symbol('AsyncReaderEndOfStream');
2642 >
2643 > export class AsyncReader<T> {
2644 > private _buffer: T[] = [];
2645 > private _atEnd = false;
2646 >
2647 > public get endOfStream(): boolean { return this._buffer.length === 0 && this._atEnd; }
2648 > private _extendBufferPromise: Promise<void> | undefined;
2649 >
2650 > constructor(
2651 private readonly _source: AsyncIterator<T>
2652 ) {
2653 }
2654 > async.ts
2655 > public async read(): Promise<T | typeof AsyncReaderEndOfStream> {
2656 if (this._buffer.length === 0 && !this._atEnd) {
2657 await this._extendBuffer();
2662 return this._buffer.shift()!;
2663 }
2664 > async.ts
2665 > public async readWhile(predicate: (value: T) => boolean, callback: (element: T) => unknown): Promise<void> {
2666 do {
2667 const piece = await this.peek();
2676 } while (true);
2677 }
2678 > async.ts
2679 > public readBufferedOrThrow(): T | typeof AsyncReaderEndOfStream {
2680 const value = this.peekBufferedOrThrow();
2681 this._buffer.shift();
2682 return value;
2683 }
2684 > async.ts
2685 > public async consumeToEnd(): Promise<void> {
2686 while (!this.endOfStream) {
2687 await this.read();
2688 }
2689 }
2690 > async.ts
2691 > public async peek(): Promise<T | typeof AsyncReaderEndOfStream> {
2692 if (this._buffer.length === 0 && !this._atEnd) {
2693 await this._extendBuffer();
2698 return this._buffer[0];
2699 }
2700 > async.ts
2701 > public peekBufferedOrThrow(): T | typeof AsyncReaderEndOfStream {
2702 if (this._buffer.length === 0) {
2703 if (this._atEnd) {
2709 return this._buffer[0];
2710 }
2711 > async.ts
2712 > public async peekTimeout(timeoutMs: number): Promise<T | typeof AsyncReaderEndOfStream | undefined> {
2713 if (this._buffer.length === 0 && !this._atEnd) {
2714 await raceTimeout(this._extendBuffer(), timeoutMs);
2722 return this._buffer[0];
2723 }
2724 > async.ts
2725 > private _extendBuffer(): Promise<void> {
2726 if (this._atEnd) {
2727 return Promise.resolve();
2742 return this._extendBufferPromise;
2743 }
2744 > } async.ts
2745 >
2746 > export function createTimeout(ms: number, cb: () => void): IDisposable {
2747 const t = setTimeout(cb, ms);
2748 return toDisposable(() => clearTimeout(t));
src/vs/editor/common/standalone/standaloneEnums.ts 1017 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- standaloneEnums.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 GENERATED FILE. DO NOT EDIT DIRECTLY.
7 >
8 >
9 > export enum AccessibilitySupport {
10 > /**
11 > * This should be the browser case where it is not known if a screen reader is attached or no.
12 > */
13 > Unknown = 0,
14 > Disabled = 1,
15 > Enabled = 2
16 > }
17 >
18 > export enum CodeActionTriggerType {
19 > Invoke = 1,
20 > Auto = 2
21 > }
22 >
23 > export enum CompletionItemInsertTextRule {
24 > None = 0,
25 > /**
26 > * Adjust whitespace/indentation of multiline insert texts to
27 > * match the current line indentation.
28 > */
29 > KeepWhitespace = 1,
30 > /**
31 > * `insertText` is a snippet.
32 > */
33 > InsertAsSnippet = 4
34 > }
35 >
36 > export enum CompletionItemKind {
37 > Method = 0,
38 > Function = 1,
39 > Constructor = 2,
40 > Field = 3,
41 > Variable = 4,
42 > Class = 5,
43 > Struct = 6,
44 > Interface = 7,
45 > Module = 8,
46 > Property = 9,
47 > Event = 10,
48 > Operator = 11,
49 > Unit = 12,
50 > Value = 13,
51 > Constant = 14,
52 > Enum = 15,
53 > EnumMember = 16,
54 > Keyword = 17,
55 > Text = 18,
56 > Color = 19,
57 > File = 20,
58 > Reference = 21,
59 > Customcolor = 22,
60 > Folder = 23,
61 > TypeParameter = 24,
62 > User = 25,
63 > Issue = 26,
64 > Tool = 27,
65 > Snippet = 28
66 > }
67 >
68 > export enum CompletionItemTag {
69 > Deprecated = 1
70 > }
71 >
72 > /**
73 > * How a suggest provider was triggered.
74 > */
75 > export enum CompletionTriggerKind {
76 > Invoke = 0,
77 > TriggerCharacter = 1,
78 > TriggerForIncompleteCompletions = 2
79 > }
80 >
81 > /**
82 > * A positioning preference for rendering content widgets.
83 > */
84 > export enum ContentWidgetPositionPreference {
85 > /**
86 > * Place the content widget exactly at a position
87 > */
88 > EXACT = 0,
89 > /**
90 > * Place the content widget above a position
91 > */
92 > ABOVE = 1,
93 > /**
94 > * Place the content widget below a position
95 > */
96 > BELOW = 2
97 > }
98 >
99 > /**
100 > * Describes the reason the cursor has changed its position.
101 > */
102 > export enum CursorChangeReason {
103 > /**
104 > * Unknown or not set.
105 > */
106 > NotSet = 0,
107 > /**
108 > * A `model.setValue()` was called.
109 > */
110 > ContentFlush = 1,
111 > /**
112 > * The `model` has been changed outside of this cursor and the cursor recovers its position from associated markers.
113 > */
114 > RecoverFromMarkers = 2,
115 > /**
116 > * There was an explicit user gesture.
117 > */
118 > Explicit = 3,
119 > /**
120 > * There was a Paste.
121 > */
122 > Paste = 4,
123 > /**
124 > * There was an Undo.
125 > */
126 > Undo = 5,
127 > /**
128 > * There was a Redo.
129 > */
130 > Redo = 6
131 > }
132 >
133 > /**
134 > * The default end of line to use when instantiating models.
135 > */
136 > export enum DefaultEndOfLine {
137 > /**
138 > * Use line feed (\n) as the end of line character.
139 > */
140 > LF = 1,
141 > /**
142 > * Use carriage return and line feed (\r\n) as the end of line character.
143 > */
144 > CRLF = 2
145 > }
146 >
147 > /**
148 > * A document highlight kind.
149 > */
150 > export enum DocumentHighlightKind {
151 > /**
152 > * A textual occurrence.
153 > */
154 > Text = 0,
155 > /**
156 > * Read-access of a symbol, like reading a variable.
157 > */
158 > Read = 1,
159 > /**
160 > * Write-access of a symbol, like writing to a variable.
161 > */
162 > Write = 2
163 > }
164 >
165 > /**
166 > * Configuration options for auto indentation in the editor
167 > */
168 > export enum EditorAutoIndentStrategy {
169 > None = 0,
170 > Keep = 1,
171 > Brackets = 2,
172 > Advanced = 3,
173 > Full = 4
174 > }
175 >
176 > export enum EditorOption {
177 > acceptSuggestionOnCommitCharacter = 0,
178 > acceptSuggestionOnEnter = 1,
179 > accessibilitySupport = 2,
180 > accessibilityPageSize = 3,
181 > allowOverflow = 4,
182 > allowVariableLineHeights = 5,
183 > allowVariableFonts = 6,
184 > allowVariableFontsInAccessibilityMode = 7,
185 > ariaLabel = 8,
186 > ariaRequired = 9,
187 > autoClosingBrackets = 10,
188 > autoClosingComments = 11,
189 > screenReaderAnnounceInlineSuggestion = 12,
190 > autoClosingDelete = 13,
191 > autoClosingOvertype = 14,
192 > autoClosingQuotes = 15,
193 > autoIndent = 16,
194 > autoIndentOnPaste = 17,
195 > autoIndentOnPasteWithinString = 18,
196 > automaticLayout = 19,
197 > autoSurround = 20,
198 > bracketPairColorization = 21,
199 > guides = 22,
200 > codeLens = 23,
201 > codeLensFontFamily = 24,
202 > codeLensFontSize = 25,
203 > colorDecorators = 26,
204 > colorDecoratorsLimit = 27,
205 > columnSelection = 28,
206 > comments = 29,
207 > contextmenu = 30,
208 > copyWithSyntaxHighlighting = 31,
209 > cursorBlinking = 32,
210 > cursorSmoothCaretAnimation = 33,
211 > cursorStyle = 34,
212 > cursorSurroundingLines = 35,
213 > cursorSurroundingLinesStyle = 36,
214 > cursorWidth = 37,
215 > cursorHeight = 38,
216 > disableLayerHinting = 39,
217 > disableMonospaceOptimizations = 40,
218 > domReadOnly = 41,
219 > dragAndDrop = 42,
220 > dropIntoEditor = 43,
221 > editContext = 44,
222 > emptySelectionClipboard = 45,
223 > experimentalGpuAcceleration = 46,
224 > experimentalWhitespaceRendering = 47,
225 > extraEditorClassName = 48,
226 > fastScrollSensitivity = 49,
227 > find = 50,
228 > fixedOverflowWidgets = 51,
229 > folding = 52,
230 > foldingStrategy = 53,
231 > foldingHighlight = 54,
232 > foldingImportsByDefault = 55,
233 > foldingMaximumRegions = 56,
234 > unfoldOnClickAfterEndOfLine = 57,
235 > fontFamily = 58,
236 > fontInfo = 59,
237 > fontLigatures = 60,
238 > fontSize = 61,
239 > fontWeight = 62,
240 > fontVariations = 63,
241 > formatOnPaste = 64,
242 > formatOnType = 65,
243 > glyphMargin = 66,
244 > gotoLocation = 67,
245 > hideCursorInOverviewRuler = 68,
246 > hover = 69,
247 > inDiffEditor = 70,
248 > inlineSuggest = 71,
249 > letterSpacing = 72,
250 > lightbulb = 73,
251 > lineDecorationsWidth = 74,
252 > lineHeight = 75,
253 > lineNumbers = 76,
254 > lineNumbersMinChars = 77,
255 > linkedEditing = 78,
256 > links = 79,
257 > matchBrackets = 80,
258 > minimap = 81,
259 > mouseStyle = 82,
260 > mouseWheelScrollSensitivity = 83,
261 > mouseWheelZoom = 84,
262 > multiCursorMergeOverlapping = 85,
263 > multiCursorModifier = 86,
264 > mouseMiddleClickAction = 87,
265 > multiCursorPaste = 88,
266 > multiCursorLimit = 89,
267 > occurrencesHighlight = 90,
268 > occurrencesHighlightDelay = 91,
269 > overtypeCursorStyle = 92,
270 > overtypeOnPaste = 93,
271 > overviewRulerBorder = 94,
272 > overviewRulerLanes = 95,
273 > padding = 96,
274 > pasteAs = 97,
275 > parameterHints = 98,
276 > peekWidgetDefaultFocus = 99,
277 > placeholder = 100,
278 > definitionLinkOpensInPeek = 101,
279 > quickSuggestions = 102,
280 > quickSuggestionsDelay = 103,
281 > readOnly = 104,
282 > readOnlyMessage = 105,
283 > renameOnType = 106,
284 > renderRichScreenReaderContent = 107,
285 > renderControlCharacters = 108,
286 > renderFinalNewline = 109,
287 > renderLineHighlight = 110,
288 > renderLineHighlightOnlyWhenFocus = 111,
289 > renderValidationDecorations = 112,
290 > renderWhitespace = 113,
291 > revealHorizontalRightPadding = 114,
292 > roundedSelection = 115,
293 > rulers = 116,
294 > scrollbar = 117,
295 > scrollBeyondLastColumn = 118,
296 > scrollBeyondLastLine = 119,
297 > scrollPredominantAxis = 120,
298 > selectionClipboard = 121,
299 > selectionHighlight = 122,
300 > selectionHighlightMaxLength = 123,
301 > selectionHighlightMultiline = 124,
302 > selectOnLineNumbers = 125,
303 > showFoldingControls = 126,
304 > showUnused = 127,
305 > snippetSuggestions = 128,
306 > smartSelect = 129,
307 > smoothScrolling = 130,
308 > stickyScroll = 131,
309 > stickyTabStops = 132,
310 > stopRenderingLineAfter = 133,
311 > suggest = 134,
312 > suggestFontSize = 135,
313 > suggestLineHeight = 136,
314 > suggestOnTriggerCharacters = 137,
315 > suggestSelection = 138,
316 > tabCompletion = 139,
317 > tabIndex = 140,
318 > trimWhitespaceOnDelete = 141,
319 > unicodeHighlighting = 142,
320 > unusualLineTerminators = 143,
321 > useShadowDOM = 144,
322 > useTabStops = 145,
323 > wordBreak = 146,
324 > wordSegmenterLocales = 147,
325 > wordSeparators = 148,
326 > wordWrap = 149,
327 > wordWrapBreakAfterCharacters = 150,
328 > wordWrapBreakBeforeCharacters = 151,
329 > wordWrapColumn = 152,
330 > wordWrapOverride1 = 153,
331 > wordWrapOverride2 = 154,
332 > wrappingIndent = 155,
333 > wrappingStrategy = 156,
334 > showDeprecated = 157,
335 > inertialScroll = 158,
336 > inlayHints = 159,
337 > wrapOnEscapedLineFeeds = 160,
338 > effectiveCursorStyle = 161,
339 > editorClassName = 162,
340 > pixelRatio = 163,
341 > tabFocusMode = 164,
342 > layoutInfo = 165,
343 > wrappingInfo = 166,
344 > defaultColorDecorators = 167,
345 > colorDecoratorsActivatedOn = 168,
346 > inlineCompletionsAccessibilityVerbose = 169,
347 > effectiveEditContext = 170,
348 > scrollOnMiddleClick = 171,
349 > effectiveAllowVariableFonts = 172,
350 > doubleClickSelectsBlock = 173
351 > }
352 >
353 > /**
354 > * End of line character preference.
355 > */
356 > export enum EndOfLinePreference {
357 > /**
358 > * Use the end of line character identified in the text buffer.
359 > */
360 > TextDefined = 0,
361 > /**
362 > * Use line feed (\n) as the end of line character.
363 > */
364 > LF = 1,
365 > /**
366 > * Use carriage return and line feed (\r\n) as the end of line character.
367 > */
368 > CRLF = 2
369 > }
370 >
371 > /**
372 > * End of line character preference.
373 > */
374 > export enum EndOfLineSequence {
375 > /**
376 > * Use line feed (\n) as the end of line character.
377 > */
378 > LF = 0,
379 > /**
380 > * Use carriage return and line feed (\r\n) as the end of line character.
381 > */
382 > CRLF = 1
383 > }
384 >
385 > /**
386 > * Vertical Lane in the glyph margin of the editor.
387 > */
388 > export enum GlyphMarginLane {
389 > Left = 1,
390 > Center = 2,
391 > Right = 3
392 > }
393 >
394 > export enum HoverVerbosityAction {
395 > /**
396 > * Increase the verbosity of the hover
397 > */
398 > Increase = 0,
399 > /**
400 > * Decrease the verbosity of the hover
401 > */
402 > Decrease = 1
403 > }
404 >
405 > /**
406 > * Describes what to do with the indentation when pressing Enter.
407 > */
408 > export enum IndentAction {
409 > /**
410 > * Insert new line and copy the previous line's indentation.
411 > */
412 > None = 0,
413 > /**
414 > * Insert new line and indent once (relative to the previous line's indentation).
415 > */
416 > Indent = 1,
417 > /**
418 > * Insert two new lines:
419 > * - the first one indented which will hold the cursor
420 > * - the second one at the same indentation level
421 > */
422 > IndentOutdent = 2,
423 > /**
424 > * Insert new line and outdent once (relative to the previous line's indentation).
425 > */
426 > Outdent = 3
427 > }
428 >
429 > export enum InjectedTextCursorStops {
430 > Both = 0,
431 > Right = 1,
432 > Left = 2,
433 > None = 3
434 > }
435 >
436 > export enum InlayHintKind {
437 > Type = 1,
438 > Parameter = 2
439 > }
440 >
441 > export enum InlineCompletionEndOfLifeReasonKind {
442 > Accepted = 0,
443 > Rejected = 1,
444 > Ignored = 2
445 > }
446 >
447 > export enum InlineCompletionHintStyle {
448 > Code = 1,
449 > Label = 2
450 > }
451 >
452 > /**
453 > * How an {@link InlineCompletionsProvider inline completion provider} was triggered.
454 > */
455 > export enum InlineCompletionTriggerKind {
456 > /**
457 > * Completion was triggered automatically while editing.
458 > * It is sufficient to return a single completion item in this case.
459 > */
460 > Automatic = 0,
461 > /**
462 > * Completion was triggered explicitly by a user gesture.
463 > * Return multiple completion items to enable cycling through them.
464 > */
465 > Explicit = 1
466 > }
467 > /**
468 > * Virtual Key Codes, the value does not hold any inherent meaning.
469 > * Inspired somewhat from https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
470 > * But these are "more general", as they should work across browsers & OS`s.
471 > */
472 > export enum KeyCode {
473 > DependsOnKbLayout = -1,
474 > /**
475 > * Placed first to cover the 0 value of the enum.
476 > */
477 > Unknown = 0,
478 > Backspace = 1,
479 > Tab = 2,
480 > Enter = 3,
481 > Shift = 4,
482 > Ctrl = 5,
483 > Alt = 6,
484 > PauseBreak = 7,
485 > CapsLock = 8,
486 > Escape = 9,
487 > Space = 10,
488 > PageUp = 11,
489 > PageDown = 12,
490 > End = 13,
491 > Home = 14,
492 > LeftArrow = 15,
493 > UpArrow = 16,
494 > RightArrow = 17,
495 > DownArrow = 18,
496 > Insert = 19,
497 > Delete = 20,
498 > Digit0 = 21,
499 > Digit1 = 22,
500 > Digit2 = 23,
501 > Digit3 = 24,
502 > Digit4 = 25,
503 > Digit5 = 26,
504 > Digit6 = 27,
505 > Digit7 = 28,
506 > Digit8 = 29,
507 > Digit9 = 30,
508 > KeyA = 31,
509 > KeyB = 32,
510 > KeyC = 33,
511 > KeyD = 34,
512 > KeyE = 35,
513 > KeyF = 36,
514 > KeyG = 37,
515 > KeyH = 38,
516 > KeyI = 39,
517 > KeyJ = 40,
518 > KeyK = 41,
519 > KeyL = 42,
520 > KeyM = 43,
521 > KeyN = 44,
522 > KeyO = 45,
523 > KeyP = 46,
524 > KeyQ = 47,
525 > KeyR = 48,
526 > KeyS = 49,
527 > KeyT = 50,
528 > KeyU = 51,
529 > KeyV = 52,
530 > KeyW = 53,
531 > KeyX = 54,
532 > KeyY = 55,
533 > KeyZ = 56,
534 > Meta = 57,
535 > ContextMenu = 58,
536 > F1 = 59,
537 > F2 = 60,
538 > F3 = 61,
539 > F4 = 62,
540 > F5 = 63,
541 > F6 = 64,
542 > F7 = 65,
543 > F8 = 66,
544 > F9 = 67,
545 > F10 = 68,
546 > F11 = 69,
547 > F12 = 70,
548 > F13 = 71,
549 > F14 = 72,
550 > F15 = 73,
551 > F16 = 74,
552 > F17 = 75,
553 > F18 = 76,
554 > F19 = 77,
555 > F20 = 78,
556 > F21 = 79,
557 > F22 = 80,
558 > F23 = 81,
559 > F24 = 82,
560 > NumLock = 83,
561 > ScrollLock = 84,
562 > /**
563 > * Used for miscellaneous characters; it can vary by keyboard.
564 > * For the US standard keyboard, the ';:' key
565 > */
566 > Semicolon = 85,
567 > /**
568 > * For any country/region, the '+' key
569 > * For the US standard keyboard, the '=+' key
570 > */
571 > Equal = 86,
572 > /**
573 > * For any country/region, the ',' key
574 > * For the US standard keyboard, the ',<' key
575 > */
576 > Comma = 87,
577 > /**
578 > * For any country/region, the '-' key
579 > * For the US standard keyboard, the '-_' key
580 > */
581 > Minus = 88,
582 > /**
583 > * For any country/region, the '.' key
584 > * For the US standard keyboard, the '.>' key
585 > */
586 > Period = 89,
587 > /**
588 > * Used for miscellaneous characters; it can vary by keyboard.
589 > * For the US standard keyboard, the '/?' key
590 > */
591 > Slash = 90,
592 > /**
593 > * Used for miscellaneous characters; it can vary by keyboard.
594 > * For the US standard keyboard, the '`~' key
595 > */
596 > Backquote = 91,
597 > /**
598 > * Used for miscellaneous characters; it can vary by keyboard.
599 > * For the US standard keyboard, the '[{' key
600 > */
601 > BracketLeft = 92,
602 > /**
603 > * Used for miscellaneous characters; it can vary by keyboard.
604 > * For the US standard keyboard, the '\|' key
605 > */
606 > Backslash = 93,
607 > /**
608 > * Used for miscellaneous characters; it can vary by keyboard.
609 > * For the US standard keyboard, the ']}' key
610 > */
611 > BracketRight = 94,
612 > /**
613 > * Used for miscellaneous characters; it can vary by keyboard.
614 > * For the US standard keyboard, the ''"' key
615 > */
616 > Quote = 95,
617 > /**
618 > * Used for miscellaneous characters; it can vary by keyboard.
619 > */
620 > OEM_8 = 96,
621 > /**
622 > * Either the angle bracket key or the backslash key on the RT 102-key keyboard.
623 > */
624 > IntlBackslash = 97,
625 > Numpad0 = 98,// VK_NUMPAD0, 0x60, Numeric keypad 0 key
626 > Numpad1 = 99,// VK_NUMPAD1, 0x61, Numeric keypad 1 key
627 > Numpad2 = 100,// VK_NUMPAD2, 0x62, Numeric keypad 2 key
628 > Numpad3 = 101,// VK_NUMPAD3, 0x63, Numeric keypad 3 key
629 > Numpad4 = 102,// VK_NUMPAD4, 0x64, Numeric keypad 4 key
630 > Numpad5 = 103,// VK_NUMPAD5, 0x65, Numeric keypad 5 key
631 > Numpad6 = 104,// VK_NUMPAD6, 0x66, Numeric keypad 6 key
632 > Numpad7 = 105,// VK_NUMPAD7, 0x67, Numeric keypad 7 key
633 > Numpad8 = 106,// VK_NUMPAD8, 0x68, Numeric keypad 8 key
634 > Numpad9 = 107,// VK_NUMPAD9, 0x69, Numeric keypad 9 key
635 > NumpadMultiply = 108,// VK_MULTIPLY, 0x6A, Multiply key
636 > NumpadAdd = 109,// VK_ADD, 0x6B, Add key
637 > NUMPAD_SEPARATOR = 110,// VK_SEPARATOR, 0x6C, Separator key
638 > NumpadSubtract = 111,// VK_SUBTRACT, 0x6D, Subtract key
639 > NumpadDecimal = 112,// VK_DECIMAL, 0x6E, Decimal key
640 > NumpadDivide = 113,// VK_DIVIDE, 0x6F,
641 > /**
642 > * Cover all key codes when IME is processing input.
643 > */
644 > KEY_IN_COMPOSITION = 114,
645 > ABNT_C1 = 115,// Brazilian (ABNT) Keyboard
646 > ABNT_C2 = 116,// Brazilian (ABNT) Keyboard
647 > AudioVolumeMute = 117,
648 > AudioVolumeUp = 118,
649 > AudioVolumeDown = 119,
650 > BrowserSearch = 120,
651 > BrowserHome = 121,
652 > BrowserBack = 122,
653 > BrowserForward = 123,
654 > MediaTrackNext = 124,
655 > MediaTrackPrevious = 125,
656 > MediaStop = 126,
657 > MediaPlayPause = 127,
658 > LaunchMediaPlayer = 128,
659 > LaunchMail = 129,
660 > LaunchApp2 = 130,
661 > /**
662 > * VK_CLEAR, 0x0C, CLEAR key
663 > */
664 > Clear = 131,
665 > /**
666 > * Placed last to cover the length of the enum.
667 > * Please do not depend on this value!
668 > */
669 > MAX_VALUE = 132
670 > }
671 >
672 > export enum MarkerSeverity {
673 > Hint = 1,
674 > Info = 2,
675 > Warning = 4,
676 > Error = 8
677 > }
678 >
679 > export enum MarkerTag {
680 > Unnecessary = 1,
681 > Deprecated = 2
682 > }
683 >
684 > /**
685 > * Position in the minimap to render the decoration.
686 > */
687 > export enum MinimapPosition {
688 > Inline = 1,
689 > Gutter = 2
690 > }
691 >
692 > /**
693 > * Section header style.
694 > */
695 > export enum MinimapSectionHeaderStyle {
696 > Normal = 1,
697 > Underlined = 2
698 > }
699 >
700 > /**
701 > * Type of hit element with the mouse in the editor.
702 > */
703 > export enum MouseTargetType {
704 > /**
705 > * Mouse is on top of an unknown element.
706 > */
707 > UNKNOWN = 0,
708 > /**
709 > * Mouse is on top of the textarea used for input.
710 > */
711 > TEXTAREA = 1,
712 > /**
713 > * Mouse is on top of the glyph margin
714 > */
715 > GUTTER_GLYPH_MARGIN = 2,
716 > /**
717 > * Mouse is on top of the line numbers
718 > */
719 > GUTTER_LINE_NUMBERS = 3,
720 > /**
721 > * Mouse is on top of the line decorations
722 > */
723 > GUTTER_LINE_DECORATIONS = 4,
724 > /**
725 > * Mouse is on top of the whitespace left in the gutter by a view zone.
726 > */
727 > GUTTER_VIEW_ZONE = 5,
728 > /**
729 > * Mouse is on top of text in the content.
730 > */
731 > CONTENT_TEXT = 6,
732 > /**
733 > * Mouse is on top of empty space in the content (e.g. after line text or below last line)
734 > */
735 > CONTENT_EMPTY = 7,
736 > /**
737 > * Mouse is on top of a view zone in the content.
738 > */
739 > CONTENT_VIEW_ZONE = 8,
740 > /**
741 > * Mouse is on top of a content widget.
742 > */
743 > CONTENT_WIDGET = 9,
744 > /**
745 > * Mouse is on top of the decorations overview ruler.
746 > */
747 > OVERVIEW_RULER = 10,
748 > /**
749 > * Mouse is on top of a scrollbar.
750 > */
751 > SCROLLBAR = 11,
752 > /**
753 > * Mouse is on top of an overlay widget.
754 > */
755 > OVERLAY_WIDGET = 12,
756 > /**
757 > * Mouse is outside of the editor.
758 > */
759 > OUTSIDE_EDITOR = 13
760 > }
761 >
762 > export enum NewSymbolNameTag {
763 > AIGenerated = 1
764 > }
765 >
766 > export enum NewSymbolNameTriggerKind {
767 > Invoke = 0,
768 > Automatic = 1
769 > }
770 >
771 > /**
772 > * A positioning preference for rendering overlay widgets.
773 > */
774 > export enum OverlayWidgetPositionPreference {
775 > /**
776 > * Position the overlay widget in the top right corner
777 > */
778 > TOP_RIGHT_CORNER = 0,
779 > /**
780 > * Position the overlay widget in the bottom right corner
781 > */
782 > BOTTOM_RIGHT_CORNER = 1,
783 > /**
784 > * Position the overlay widget in the top center
785 > */
786 > TOP_CENTER = 2
787 > }
788 >
789 > /**
790 > * Vertical Lane in the overview ruler of the editor.
791 > */
792 > export enum OverviewRulerLane {
793 > Left = 1,
794 > Center = 2,
795 > Right = 4,
796 > Full = 7
797 > }
798 >
799 > /**
800 > * How a partial acceptance was triggered.
801 > */
802 > export enum PartialAcceptTriggerKind {
803 > Word = 0,
804 > Line = 1,
805 > Suggest = 2
806 > }
807 >
808 > export enum PositionAffinity {
809 > /**
810 > * Prefers the left most position.
811 > */
812 > Left = 0,
813 > /**
814 > * Prefers the right most position.
815 > */
816 > Right = 1,
817 > /**
818 > * No preference.
819 > */
820 > None = 2,
821 > /**
822 > * If the given position is on injected text, prefers the position left of it.
823 > */
824 > LeftOfInjectedText = 3,
825 > /**
826 > * If the given position is on injected text, prefers the position right of it.
827 > */
828 > RightOfInjectedText = 4
829 > }
830 >
831 > export enum RenderLineNumbersType {
832 > Off = 0,
833 > On = 1,
834 > Relative = 2,
835 > Interval = 3,
836 > Custom = 4
837 > }
838 >
839 > export enum RenderMinimap {
840 > None = 0,
841 > Text = 1,
842 > Blocks = 2
843 > }
844 >
845 > export enum ScrollType {
846 > Smooth = 0,
847 > Immediate = 1
848 > }
849 >
850 > export enum ScrollbarVisibility {
851 > Auto = 1,
852 > Hidden = 2,
853 > Visible = 3
854 > }
855 >
856 > /**
857 > * The direction of a selection.
858 > */
859 > export enum SelectionDirection {
860 > /**
861 > * The selection starts above where it ends.
862 > */
863 > LTR = 0,
864 > /**
865 > * The selection starts below where it ends.
866 > */
867 > RTL = 1
868 > }
869 >
870 > export enum ShowLightbulbIconMode {
871 > Off = 'off',
872 > OnCode = 'onCode',
873 > On = 'on'
874 > }
875 >
876 > export enum SignatureHelpTriggerKind {
877 > Invoke = 1,
878 > TriggerCharacter = 2,
879 > ContentChange = 3
880 > }
881 >
882 > /**
883 > * A symbol kind.
884 > */
885 > export enum SymbolKind {
886 > File = 0,
887 > Module = 1,
888 > Namespace = 2,
889 > Package = 3,
890 > Class = 4,
891 > Method = 5,
892 > Property = 6,
893 > Field = 7,
894 > Constructor = 8,
895 > Enum = 9,
896 > Interface = 10,
897 > Function = 11,
898 > Variable = 12,
899 > Constant = 13,
900 > String = 14,
901 > Number = 15,
902 > Boolean = 16,
903 > Array = 17,
904 > Object = 18,
905 > Key = 19,
906 > Null = 20,
907 > EnumMember = 21,
908 > Struct = 22,
909 > Event = 23,
910 > Operator = 24,
911 > TypeParameter = 25
912 > }
913 >
914 > export enum SymbolTag {
915 > Deprecated = 1
916 > }
917 >
918 > /**
919 > * Text Direction for a decoration.
920 > */
921 > export enum TextDirection {
922 > LTR = 0,
923 > RTL = 1
924 > }
925 >
926 > /**
927 > * The kind of animation in which the editor's cursor should be rendered.
928 > */
929 > export enum TextEditorCursorBlinkingStyle {
930 > /**
931 > * Hidden
932 > */
933 > Hidden = 0,
934 > /**
935 > * Blinking
936 > */
937 > Blink = 1,
938 > /**
939 > * Blinking with smooth fading
940 > */
941 > Smooth = 2,
942 > /**
943 > * Blinking with prolonged filled state and smooth fading
944 > */
945 > Phase = 3,
946 > /**
947 > * Expand collapse animation on the y axis
948 > */
949 > Expand = 4,
950 > /**
951 > * No-Blinking
952 > */
953 > Solid = 5
954 > }
955 >
956 > /**
957 > * The style in which the editor's cursor should be rendered.
958 > */
959 > export enum TextEditorCursorStyle {
960 > /**
961 > * As a vertical line (sitting between two characters).
962 > */
963 > Line = 1,
964 > /**
965 > * As a block (sitting on top of a character).
966 > */
967 > Block = 2,
968 > /**
969 > * As a horizontal line (sitting under a character).
970 > */
971 > Underline = 3,
972 > /**
973 > * As a thin vertical line (sitting between two characters).
974 > */
975 > LineThin = 4,
976 > /**
977 > * As an outlined block (sitting on top of a character).
978 > */
979 > BlockOutline = 5,
980 > /**
981 > * As a thin horizontal line (sitting under a character).
982 > */
983 > UnderlineThin = 6
984 > }
985 >
986 > /**
987 > * Describes the behavior of decorations when typing/editing near their edges.
988 > * Note: Please do not edit the values, as they very carefully match `DecorationRangeBehavior`
989 > */
990 > export enum TrackedRangeStickiness {
991 > AlwaysGrowsWhenTypingAtEdges = 0,
992 > NeverGrowsWhenTypingAtEdges = 1,
993 > GrowsOnlyWhenTypingBefore = 2,
994 > GrowsOnlyWhenTypingAfter = 3
995 > }
996 >
997 > /**
998 > * Describes how to indent wrapped lines.
999 > */
1000 > export enum WrappingIndent {
1001 > /**
1002 > * No indentation => wrapped lines begin at column 1.
1003 > */
1004 > None = 0,
1005 > /**
1006 > * Same => wrapped lines get the same indentation as the parent.
1007 > */
1008 > Same = 1,
1009 > /**
1010 > * Indent => wrapped lines get +1 indentation toward the parent.
1011 > */
1012 > Indent = 2,
1013 > /**
1014 > * DeepIndent => wrapped lines get +2 indentation toward the parent.
1015 > */
1016 > DeepIndent = 3
1017 > }
src/vs/base/common/event.ts 859 covered LOC · 102 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; event.ts
1198 > this._leakageMon = (_globalLeakWarningThreshold > 0 || this._options?.leakWarningThreshold)
1199 ? new LeakageMonitor(options?.onListenerError ?? onUnexpectedError, this._options?.leakWarningThreshold ?? _globalLeakWarningThreshold, this._options?.leakWarningName) :
1200 > undefined; event.ts
1201 > this._perfMon = this._options?._profName ? new EventProfiling(this._options._profName) : undefined;
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) => { event.ts
1244 if (this._leakageMon && this._size > this._leakageMon.threshold ** 2) {
1245 const message = `[${this._leakageMon.name}] REFUSES to accept new listeners because it exceeded its threshold by far (${this._size} vs ${this._leakageMon.threshold})`;
1301 return result;
1302 };
1303 > event.ts
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) { event.ts
1386 this._deliverQueue(this._deliveryQueue);
1387 this._perfMon?.stop(); // last fire() will have starting perfmon, stop it before starting the next dispatch
1388 }
1389 > event.ts
1390 > this._perfMon?.start(this._size);
1391 >
1392 > if (!this._listeners) {
1393 > // no-op event.ts
1394 > } else if (this._listeners instanceof UniqueContainer) { event.ts
1395 this._deliver(this._listeners, event);
1396 } else {
1399 this._deliverQueue(dq);
1400 }
1401 > event.ts
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/keyCodes.ts 792 covered LOC · 11 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- keyCodes.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 > * Virtual Key Codes, the value does not hold any inherent meaning.
8 > * Inspired somewhat from https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
9 > * But these are "more general", as they should work across browsers & OS`s.
10 > */
11 > export const enum KeyCode {
12 > DependsOnKbLayout = -1,
13 >
14 > /**
15 > * Placed first to cover the 0 value of the enum.
16 > */
17 > Unknown = 0,
18 >
19 > Backspace,
20 > Tab,
21 > Enter,
22 > Shift,
23 > Ctrl,
24 > Alt,
25 > PauseBreak,
26 > CapsLock,
27 > Escape,
28 > Space,
29 > PageUp,
30 > PageDown,
31 > End,
32 > Home,
33 > LeftArrow,
34 > UpArrow,
35 > RightArrow,
36 > DownArrow,
37 > Insert,
38 > Delete,
39 >
40 > Digit0,
41 > Digit1,
42 > Digit2,
43 > Digit3,
44 > Digit4,
45 > Digit5,
46 > Digit6,
47 > Digit7,
48 > Digit8,
49 > Digit9,
50 >
51 > KeyA,
52 > KeyB,
53 > KeyC,
54 > KeyD,
55 > KeyE,
56 > KeyF,
57 > KeyG,
58 > KeyH,
59 > KeyI,
60 > KeyJ,
61 > KeyK,
62 > KeyL,
63 > KeyM,
64 > KeyN,
65 > KeyO,
66 > KeyP,
67 > KeyQ,
68 > KeyR,
69 > KeyS,
70 > KeyT,
71 > KeyU,
72 > KeyV,
73 > KeyW,
74 > KeyX,
75 > KeyY,
76 > KeyZ,
77 >
78 > Meta,
79 > ContextMenu,
80 >
81 > F1,
82 > F2,
83 > F3,
84 > F4,
85 > F5,
86 > F6,
87 > F7,
88 > F8,
89 > F9,
90 > F10,
91 > F11,
92 > F12,
93 > F13,
94 > F14,
95 > F15,
96 > F16,
97 > F17,
98 > F18,
99 > F19,
100 > F20,
101 > F21,
102 > F22,
103 > F23,
104 > F24,
105 >
106 > NumLock,
107 > ScrollLock,
108 >
109 > /**
110 > * Used for miscellaneous characters; it can vary by keyboard.
111 > * For the US standard keyboard, the ';:' key
112 > */
113 > Semicolon,
114 > /**
115 > * For any country/region, the '+' key
116 > * For the US standard keyboard, the '=+' key
117 > */
118 > Equal,
119 > /**
120 > * For any country/region, the ',' key
121 > * For the US standard keyboard, the ',<' key
122 > */
123 > Comma,
124 > /**
125 > * For any country/region, the '-' key
126 > * For the US standard keyboard, the '-_' key
127 > */
128 > Minus,
129 > /**
130 > * For any country/region, the '.' key
131 > * For the US standard keyboard, the '.>' key
132 > */
133 > Period,
134 > /**
135 > * Used for miscellaneous characters; it can vary by keyboard.
136 > * For the US standard keyboard, the '/?' key
137 > */
138 > Slash,
139 > /**
140 > * Used for miscellaneous characters; it can vary by keyboard.
141 > * For the US standard keyboard, the '`~' key
142 > */
143 > Backquote,
144 > /**
145 > * Used for miscellaneous characters; it can vary by keyboard.
146 > * For the US standard keyboard, the '[{' key
147 > */
148 > BracketLeft,
149 > /**
150 > * Used for miscellaneous characters; it can vary by keyboard.
151 > * For the US standard keyboard, the '\|' key
152 > */
153 > Backslash,
154 > /**
155 > * Used for miscellaneous characters; it can vary by keyboard.
156 > * For the US standard keyboard, the ']}' key
157 > */
158 > BracketRight,
159 > /**
160 > * Used for miscellaneous characters; it can vary by keyboard.
161 > * For the US standard keyboard, the ''"' key
162 > */
163 > Quote,
164 > /**
165 > * Used for miscellaneous characters; it can vary by keyboard.
166 > */
167 > OEM_8,
168 > /**
169 > * Either the angle bracket key or the backslash key on the RT 102-key keyboard.
170 > */
171 > IntlBackslash,
172 >
173 > Numpad0, // VK_NUMPAD0, 0x60, Numeric keypad 0 key
174 > Numpad1, // VK_NUMPAD1, 0x61, Numeric keypad 1 key
175 > Numpad2, // VK_NUMPAD2, 0x62, Numeric keypad 2 key
176 > Numpad3, // VK_NUMPAD3, 0x63, Numeric keypad 3 key
177 > Numpad4, // VK_NUMPAD4, 0x64, Numeric keypad 4 key
178 > Numpad5, // VK_NUMPAD5, 0x65, Numeric keypad 5 key
179 > Numpad6, // VK_NUMPAD6, 0x66, Numeric keypad 6 key
180 > Numpad7, // VK_NUMPAD7, 0x67, Numeric keypad 7 key
181 > Numpad8, // VK_NUMPAD8, 0x68, Numeric keypad 8 key
182 > Numpad9, // VK_NUMPAD9, 0x69, Numeric keypad 9 key
183 >
184 > NumpadMultiply, // VK_MULTIPLY, 0x6A, Multiply key
185 > NumpadAdd, // VK_ADD, 0x6B, Add key
186 > NUMPAD_SEPARATOR, // VK_SEPARATOR, 0x6C, Separator key
187 > NumpadSubtract, // VK_SUBTRACT, 0x6D, Subtract key
188 > NumpadDecimal, // VK_DECIMAL, 0x6E, Decimal key
189 > NumpadDivide, // VK_DIVIDE, 0x6F,
190 >
191 > /**
192 > * Cover all key codes when IME is processing input.
193 > */
194 > KEY_IN_COMPOSITION,
195 >
196 > ABNT_C1, // Brazilian (ABNT) Keyboard
197 > ABNT_C2, // Brazilian (ABNT) Keyboard
198 >
199 > AudioVolumeMute,
200 > AudioVolumeUp,
201 > AudioVolumeDown,
202 >
203 > BrowserSearch,
204 > BrowserHome,
205 > BrowserBack,
206 > BrowserForward,
207 >
208 > MediaTrackNext,
209 > MediaTrackPrevious,
210 > MediaStop,
211 > MediaPlayPause,
212 > LaunchMediaPlayer,
213 > LaunchMail,
214 > LaunchApp2,
215 >
216 > /**
217 > * VK_CLEAR, 0x0C, CLEAR key
218 > */
219 > Clear,
220 >
221 > /**
222 > * Placed last to cover the length of the enum.
223 > * Please do not depend on this value!
224 > */
225 > MAX_VALUE
226 > }
227 >
228 > /**
229 > * keyboardEvent.code
230 > */
231 > export const enum ScanCode {
232 > DependsOnKbLayout = -1,
233 > None,
234 > Hyper,
235 > Super,
236 > Fn,
237 > FnLock,
238 > Suspend,
239 > Resume,
240 > Turbo,
241 > Sleep,
242 > WakeUp,
243 > KeyA,
244 > KeyB,
245 > KeyC,
246 > KeyD,
247 > KeyE,
248 > KeyF,
249 > KeyG,
250 > KeyH,
251 > KeyI,
252 > KeyJ,
253 > KeyK,
254 > KeyL,
255 > KeyM,
256 > KeyN,
257 > KeyO,
258 > KeyP,
259 > KeyQ,
260 > KeyR,
261 > KeyS,
262 > KeyT,
263 > KeyU,
264 > KeyV,
265 > KeyW,
266 > KeyX,
267 > KeyY,
268 > KeyZ,
269 > Digit1,
270 > Digit2,
271 > Digit3,
272 > Digit4,
273 > Digit5,
274 > Digit6,
275 > Digit7,
276 > Digit8,
277 > Digit9,
278 > Digit0,
279 > Enter,
280 > Escape,
281 > Backspace,
282 > Tab,
283 > Space,
284 > Minus,
285 > Equal,
286 > BracketLeft,
287 > BracketRight,
288 > Backslash,
289 > IntlHash,
290 > Semicolon,
291 > Quote,
292 > Backquote,
293 > Comma,
294 > Period,
295 > Slash,
296 > CapsLock,
297 > F1,
298 > F2,
299 > F3,
300 > F4,
301 > F5,
302 > F6,
303 > F7,
304 > F8,
305 > F9,
306 > F10,
307 > F11,
308 > F12,
309 > PrintScreen,
310 > ScrollLock,
311 > Pause,
312 > Insert,
313 > Home,
314 > PageUp,
315 > Delete,
316 > End,
317 > PageDown,
318 > ArrowRight,
319 > ArrowLeft,
320 > ArrowDown,
321 > ArrowUp,
322 > NumLock,
323 > NumpadDivide,
324 > NumpadMultiply,
325 > NumpadSubtract,
326 > NumpadAdd,
327 > NumpadEnter,
328 > Numpad1,
329 > Numpad2,
330 > Numpad3,
331 > Numpad4,
332 > Numpad5,
333 > Numpad6,
334 > Numpad7,
335 > Numpad8,
336 > Numpad9,
337 > Numpad0,
338 > NumpadDecimal,
339 > IntlBackslash,
340 > ContextMenu,
341 > Power,
342 > NumpadEqual,
343 > F13,
344 > F14,
345 > F15,
346 > F16,
347 > F17,
348 > F18,
349 > F19,
350 > F20,
351 > F21,
352 > F22,
353 > F23,
354 > F24,
355 > Open,
356 > Help,
357 > Select,
358 > Again,
359 > Undo,
360 > Cut,
361 > Copy,
362 > Paste,
363 > Find,
364 > AudioVolumeMute,
365 > AudioVolumeUp,
366 > AudioVolumeDown,
367 > NumpadComma,
368 > IntlRo,
369 > KanaMode,
370 > IntlYen,
371 > Convert,
372 > NonConvert,
373 > Lang1,
374 > Lang2,
375 > Lang3,
376 > Lang4,
377 > Lang5,
378 > Abort,
379 > Props,
380 > NumpadParenLeft,
381 > NumpadParenRight,
382 > NumpadBackspace,
383 > NumpadMemoryStore,
384 > NumpadMemoryRecall,
385 > NumpadMemoryClear,
386 > NumpadMemoryAdd,
387 > NumpadMemorySubtract,
388 > NumpadClear,
389 > NumpadClearEntry,
390 > ControlLeft,
391 > ShiftLeft,
392 > AltLeft,
393 > MetaLeft,
394 > ControlRight,
395 > ShiftRight,
396 > AltRight,
397 > MetaRight,
398 > BrightnessUp,
399 > BrightnessDown,
400 > MediaPlay,
401 > MediaRecord,
402 > MediaFastForward,
403 > MediaRewind,
404 > MediaTrackNext,
405 > MediaTrackPrevious,
406 > MediaStop,
407 > Eject,
408 > MediaPlayPause,
409 > MediaSelect,
410 > LaunchMail,
411 > LaunchApp2,
412 > LaunchApp1,
413 > SelectTask,
414 > LaunchScreenSaver,
415 > BrowserSearch,
416 > BrowserHome,
417 > BrowserBack,
418 > BrowserForward,
419 > BrowserStop,
420 > BrowserRefresh,
421 > BrowserFavorites,
422 > ZoomToggle,
423 > MailReply,
424 > MailForward,
425 > MailSend,
426 >
427 > MAX_VALUE
428 > }
429 >
430 > class KeyCodeStrMap {
431 >
432 > public _keyCodeToStr: string[];
433 > public _strToKeyCode: { [str: string]: KeyCode };
434 >
435 > constructor() {
436 > this._keyCodeToStr = [];
437 > this._strToKeyCode = Object.create(null);
438 > }
439 >
440 > define(keyCode: KeyCode, str: string): void {
441 > this._keyCodeToStr[keyCode] = str;
442 > this._strToKeyCode[str.toLowerCase()] = keyCode;
443 > }
444 >
445 > keyCodeToStr(keyCode: KeyCode): string {
446 return this._keyCodeToStr[keyCode];
447 }
448 > keyCodes.ts
449 > strToKeyCode(str: string): KeyCode {
450 return this._strToKeyCode[str.toLowerCase()] || KeyCode.Unknown;
451 }
452 > } keyCodes.ts
453 >
454 > const uiMap = new KeyCodeStrMap();
455 > const userSettingsUSMap = new KeyCodeStrMap();
456 > const userSettingsGeneralMap = new KeyCodeStrMap();
457 > export const EVENT_KEY_CODE_MAP: { [keyCode: number]: KeyCode } = new Array(230);
458 > export const NATIVE_WINDOWS_KEY_CODE_TO_KEY_CODE: { [nativeKeyCode: string]: KeyCode } = {};
459 > export const SCAN_CODE_STR_TO_EVENT_KEY_CODE: { [scanCodeStr: string]: number } = {};
460 > const scanCodeIntToStr: string[] = [];
461 > const scanCodeStrToInt: { [code: string]: number } = Object.create(null);
462 > const scanCodeLowerCaseStrToInt: { [code: string]: number } = Object.create(null);
463 >
464 > export const ScanCodeUtils = {
465 > lowerCaseToEnum: (scanCode: string) => scanCodeLowerCaseStrToInt[scanCode] || ScanCode.None,
466 > toEnum: (scanCode: string) => scanCodeStrToInt[scanCode] || ScanCode.None,
467 > toString: (scanCode: ScanCode) => scanCodeIntToStr[scanCode] || 'None'
468 > };
469 >
470 > /**
471 > * -1 if a ScanCode => KeyCode mapping depends on kb layout.
472 > */
473 > export const IMMUTABLE_CODE_TO_KEY_CODE: KeyCode[] = [];
474 >
475 > /**
476 > * -1 if a KeyCode => ScanCode mapping depends on kb layout.
477 > */
478 > export const IMMUTABLE_KEY_CODE_TO_CODE: ScanCode[] = [];
479 >
480 > for (let i = 0; i <= ScanCode.MAX_VALUE; i++) {
481 > IMMUTABLE_CODE_TO_KEY_CODE[i] = KeyCode.DependsOnKbLayout;
482 > }
483 >
484 > for (let i = 0; i <= KeyCode.MAX_VALUE; i++) {
485 > IMMUTABLE_KEY_CODE_TO_CODE[i] = ScanCode.DependsOnKbLayout;
486 > }
487 >
488 > (function () {
489 >
490 > // See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
491 > // See https://github.com/microsoft/node-native-keymap/blob/88c0b0e5/deps/chromium/keyboard_codes_win.h
492 >
493 > const empty = '';
494 > type IMappingEntry = [0 | 1, ScanCode, string, KeyCode, string, number, string, string, string];
495 > const mappings: IMappingEntry[] = [
496 > // immutable, scanCode, scanCodeStr, keyCode, keyCodeStr, eventKeyCode, vkey, usUserSettingsLabel, generalUserSettingsLabel
497 > [1, ScanCode.None, 'None', KeyCode.Unknown, 'unknown', 0, 'VK_UNKNOWN', empty, empty],
498 > [1, ScanCode.Hyper, 'Hyper', KeyCode.Unknown, empty, 0, empty, empty, empty],
499 > [1, ScanCode.Super, 'Super', KeyCode.Unknown, empty, 0, empty, empty, empty],
500 > [1, ScanCode.Fn, 'Fn', KeyCode.Unknown, empty, 0, empty, empty, empty],
501 > [1, ScanCode.FnLock, 'FnLock', KeyCode.Unknown, empty, 0, empty, empty, empty],
502 > [1, ScanCode.Suspend, 'Suspend', KeyCode.Unknown, empty, 0, empty, empty, empty],
503 > [1, ScanCode.Resume, 'Resume', KeyCode.Unknown, empty, 0, empty, empty, empty],
504 > [1, ScanCode.Turbo, 'Turbo', KeyCode.Unknown, empty, 0, empty, empty, empty],
505 > [1, ScanCode.Sleep, 'Sleep', KeyCode.Unknown, empty, 0, 'VK_SLEEP', empty, empty],
506 > [1, ScanCode.WakeUp, 'WakeUp', KeyCode.Unknown, empty, 0, empty, empty, empty],
507 > [0, ScanCode.KeyA, 'KeyA', KeyCode.KeyA, 'A', 65, 'VK_A', empty, empty],
508 > [0, ScanCode.KeyB, 'KeyB', KeyCode.KeyB, 'B', 66, 'VK_B', empty, empty],
509 > [0, ScanCode.KeyC, 'KeyC', KeyCode.KeyC, 'C', 67, 'VK_C', empty, empty],
510 > [0, ScanCode.KeyD, 'KeyD', KeyCode.KeyD, 'D', 68, 'VK_D', empty, empty],
511 > [0, ScanCode.KeyE, 'KeyE', KeyCode.KeyE, 'E', 69, 'VK_E', empty, empty],
512 > [0, ScanCode.KeyF, 'KeyF', KeyCode.KeyF, 'F', 70, 'VK_F', empty, empty],
513 > [0, ScanCode.KeyG, 'KeyG', KeyCode.KeyG, 'G', 71, 'VK_G', empty, empty],
514 > [0, ScanCode.KeyH, 'KeyH', KeyCode.KeyH, 'H', 72, 'VK_H', empty, empty],
515 > [0, ScanCode.KeyI, 'KeyI', KeyCode.KeyI, 'I', 73, 'VK_I', empty, empty],
516 > [0, ScanCode.KeyJ, 'KeyJ', KeyCode.KeyJ, 'J', 74, 'VK_J', empty, empty],
517 > [0, ScanCode.KeyK, 'KeyK', KeyCode.KeyK, 'K', 75, 'VK_K', empty, empty],
518 > [0, ScanCode.KeyL, 'KeyL', KeyCode.KeyL, 'L', 76, 'VK_L', empty, empty],
519 > [0, ScanCode.KeyM, 'KeyM', KeyCode.KeyM, 'M', 77, 'VK_M', empty, empty],
520 > [0, ScanCode.KeyN, 'KeyN', KeyCode.KeyN, 'N', 78, 'VK_N', empty, empty],
521 > [0, ScanCode.KeyO, 'KeyO', KeyCode.KeyO, 'O', 79, 'VK_O', empty, empty],
522 > [0, ScanCode.KeyP, 'KeyP', KeyCode.KeyP, 'P', 80, 'VK_P', empty, empty],
523 > [0, ScanCode.KeyQ, 'KeyQ', KeyCode.KeyQ, 'Q', 81, 'VK_Q', empty, empty],
524 > [0, ScanCode.KeyR, 'KeyR', KeyCode.KeyR, 'R', 82, 'VK_R', empty, empty],
525 > [0, ScanCode.KeyS, 'KeyS', KeyCode.KeyS, 'S', 83, 'VK_S', empty, empty],
526 > [0, ScanCode.KeyT, 'KeyT', KeyCode.KeyT, 'T', 84, 'VK_T', empty, empty],
527 > [0, ScanCode.KeyU, 'KeyU', KeyCode.KeyU, 'U', 85, 'VK_U', empty, empty],
528 > [0, ScanCode.KeyV, 'KeyV', KeyCode.KeyV, 'V', 86, 'VK_V', empty, empty],
529 > [0, ScanCode.KeyW, 'KeyW', KeyCode.KeyW, 'W', 87, 'VK_W', empty, empty],
530 > [0, ScanCode.KeyX, 'KeyX', KeyCode.KeyX, 'X', 88, 'VK_X', empty, empty],
531 > [0, ScanCode.KeyY, 'KeyY', KeyCode.KeyY, 'Y', 89, 'VK_Y', empty, empty],
532 > [0, ScanCode.KeyZ, 'KeyZ', KeyCode.KeyZ, 'Z', 90, 'VK_Z', empty, empty],
533 > [0, ScanCode.Digit1, 'Digit1', KeyCode.Digit1, '1', 49, 'VK_1', empty, empty],
534 > [0, ScanCode.Digit2, 'Digit2', KeyCode.Digit2, '2', 50, 'VK_2', empty, empty],
535 > [0, ScanCode.Digit3, 'Digit3', KeyCode.Digit3, '3', 51, 'VK_3', empty, empty],
536 > [0, ScanCode.Digit4, 'Digit4', KeyCode.Digit4, '4', 52, 'VK_4', empty, empty],
537 > [0, ScanCode.Digit5, 'Digit5', KeyCode.Digit5, '5', 53, 'VK_5', empty, empty],
538 > [0, ScanCode.Digit6, 'Digit6', KeyCode.Digit6, '6', 54, 'VK_6', empty, empty],
539 > [0, ScanCode.Digit7, 'Digit7', KeyCode.Digit7, '7', 55, 'VK_7', empty, empty],
540 > [0, ScanCode.Digit8, 'Digit8', KeyCode.Digit8, '8', 56, 'VK_8', empty, empty],
541 > [0, ScanCode.Digit9, 'Digit9', KeyCode.Digit9, '9', 57, 'VK_9', empty, empty],
542 > [0, ScanCode.Digit0, 'Digit0', KeyCode.Digit0, '0', 48, 'VK_0', empty, empty],
543 > [1, ScanCode.Enter, 'Enter', KeyCode.Enter, 'Enter', 13, 'VK_RETURN', empty, empty],
544 > [1, ScanCode.Escape, 'Escape', KeyCode.Escape, 'Escape', 27, 'VK_ESCAPE', empty, empty],
545 > [1, ScanCode.Backspace, 'Backspace', KeyCode.Backspace, 'Backspace', 8, 'VK_BACK', empty, empty],
546 > [1, ScanCode.Tab, 'Tab', KeyCode.Tab, 'Tab', 9, 'VK_TAB', empty, empty],
547 > [1, ScanCode.Space, 'Space', KeyCode.Space, 'Space', 32, 'VK_SPACE', empty, empty],
548 > [0, ScanCode.Minus, 'Minus', KeyCode.Minus, '-', 189, 'VK_OEM_MINUS', '-', 'OEM_MINUS'],
549 > [0, ScanCode.Equal, 'Equal', KeyCode.Equal, '=', 187, 'VK_OEM_PLUS', '=', 'OEM_PLUS'],
550 > [0, ScanCode.BracketLeft, 'BracketLeft', KeyCode.BracketLeft, '[', 219, 'VK_OEM_4', '[', 'OEM_4'],
551 > [0, ScanCode.BracketRight, 'BracketRight', KeyCode.BracketRight, ']', 221, 'VK_OEM_6', ']', 'OEM_6'],
552 > [0, ScanCode.Backslash, 'Backslash', KeyCode.Backslash, '\\', 220, 'VK_OEM_5', '\\', 'OEM_5'],
553 > [0, ScanCode.IntlHash, 'IntlHash', KeyCode.Unknown, empty, 0, empty, empty, empty], // has been dropped from the w3c spec
554 > [0, ScanCode.Semicolon, 'Semicolon', KeyCode.Semicolon, ';', 186, 'VK_OEM_1', ';', 'OEM_1'],
555 > [0, ScanCode.Quote, 'Quote', KeyCode.Quote, '\'', 222, 'VK_OEM_7', '\'', 'OEM_7'],
556 > [0, ScanCode.Backquote, 'Backquote', KeyCode.Backquote, '`', 192, 'VK_OEM_3', '`', 'OEM_3'],
557 > [0, ScanCode.Comma, 'Comma', KeyCode.Comma, ',', 188, 'VK_OEM_COMMA', ',', 'OEM_COMMA'],
558 > [0, ScanCode.Period, 'Period', KeyCode.Period, '.', 190, 'VK_OEM_PERIOD', '.', 'OEM_PERIOD'],
559 > [0, ScanCode.Slash, 'Slash', KeyCode.Slash, '/', 191, 'VK_OEM_2', '/', 'OEM_2'],
560 > [1, ScanCode.CapsLock, 'CapsLock', KeyCode.CapsLock, 'CapsLock', 20, 'VK_CAPITAL', empty, empty],
561 > [1, ScanCode.F1, 'F1', KeyCode.F1, 'F1', 112, 'VK_F1', empty, empty],
562 > [1, ScanCode.F2, 'F2', KeyCode.F2, 'F2', 113, 'VK_F2', empty, empty],
563 > [1, ScanCode.F3, 'F3', KeyCode.F3, 'F3', 114, 'VK_F3', empty, empty],
564 > [1, ScanCode.F4, 'F4', KeyCode.F4, 'F4', 115, 'VK_F4', empty, empty],
565 > [1, ScanCode.F5, 'F5', KeyCode.F5, 'F5', 116, 'VK_F5', empty, empty],
566 > [1, ScanCode.F6, 'F6', KeyCode.F6, 'F6', 117, 'VK_F6', empty, empty],
567 > [1, ScanCode.F7, 'F7', KeyCode.F7, 'F7', 118, 'VK_F7', empty, empty],
568 > [1, ScanCode.F8, 'F8', KeyCode.F8, 'F8', 119, 'VK_F8', empty, empty],
569 > [1, ScanCode.F9, 'F9', KeyCode.F9, 'F9', 120, 'VK_F9', empty, empty],
570 > [1, ScanCode.F10, 'F10', KeyCode.F10, 'F10', 121, 'VK_F10', empty, empty],
571 > [1, ScanCode.F11, 'F11', KeyCode.F11, 'F11', 122, 'VK_F11', empty, empty],
572 > [1, ScanCode.F12, 'F12', KeyCode.F12, 'F12', 123, 'VK_F12', empty, empty],
573 > [1, ScanCode.PrintScreen, 'PrintScreen', KeyCode.Unknown, empty, 0, empty, empty, empty],
574 > [1, ScanCode.ScrollLock, 'ScrollLock', KeyCode.ScrollLock, 'ScrollLock', 145, 'VK_SCROLL', empty, empty],
575 > [1, ScanCode.Pause, 'Pause', KeyCode.PauseBreak, 'PauseBreak', 19, 'VK_PAUSE', empty, empty],
576 > [1, ScanCode.Insert, 'Insert', KeyCode.Insert, 'Insert', 45, 'VK_INSERT', empty, empty],
577 > [1, ScanCode.Home, 'Home', KeyCode.Home, 'Home', 36, 'VK_HOME', empty, empty],
578 > [1, ScanCode.PageUp, 'PageUp', KeyCode.PageUp, 'PageUp', 33, 'VK_PRIOR', empty, empty],
579 > [1, ScanCode.Delete, 'Delete', KeyCode.Delete, 'Del', 46, 'VK_DELETE', 'Delete', empty],
580 > [1, ScanCode.End, 'End', KeyCode.End, 'End', 35, 'VK_END', empty, empty],
581 > [1, ScanCode.PageDown, 'PageDown', KeyCode.PageDown, 'PageDown', 34, 'VK_NEXT', empty, empty],
582 > [1, ScanCode.ArrowRight, 'ArrowRight', KeyCode.RightArrow, 'RightArrow', 39, 'VK_RIGHT', 'Right', empty],
583 > [1, ScanCode.ArrowLeft, 'ArrowLeft', KeyCode.LeftArrow, 'LeftArrow', 37, 'VK_LEFT', 'Left', empty],
584 > [1, ScanCode.ArrowDown, 'ArrowDown', KeyCode.DownArrow, 'DownArrow', 40, 'VK_DOWN', 'Down', empty],
585 > [1, ScanCode.ArrowUp, 'ArrowUp', KeyCode.UpArrow, 'UpArrow', 38, 'VK_UP', 'Up', empty],
586 > [1, ScanCode.NumLock, 'NumLock', KeyCode.NumLock, 'NumLock', 144, 'VK_NUMLOCK', empty, empty],
587 > [1, ScanCode.NumpadDivide, 'NumpadDivide', KeyCode.NumpadDivide, 'NumPad_Divide', 111, 'VK_DIVIDE', empty, empty],
588 > [1, ScanCode.NumpadMultiply, 'NumpadMultiply', KeyCode.NumpadMultiply, 'NumPad_Multiply', 106, 'VK_MULTIPLY', empty, empty],
589 > [1, ScanCode.NumpadSubtract, 'NumpadSubtract', KeyCode.NumpadSubtract, 'NumPad_Subtract', 109, 'VK_SUBTRACT', empty, empty],
590 > [1, ScanCode.NumpadAdd, 'NumpadAdd', KeyCode.NumpadAdd, 'NumPad_Add', 107, 'VK_ADD', empty, empty],
591 > [1, ScanCode.NumpadEnter, 'NumpadEnter', KeyCode.Enter, empty, 0, empty, empty, empty],
592 > [1, ScanCode.Numpad1, 'Numpad1', KeyCode.Numpad1, 'NumPad1', 97, 'VK_NUMPAD1', empty, empty],
593 > [1, ScanCode.Numpad2, 'Numpad2', KeyCode.Numpad2, 'NumPad2', 98, 'VK_NUMPAD2', empty, empty],
594 > [1, ScanCode.Numpad3, 'Numpad3', KeyCode.Numpad3, 'NumPad3', 99, 'VK_NUMPAD3', empty, empty],
595 > [1, ScanCode.Numpad4, 'Numpad4', KeyCode.Numpad4, 'NumPad4', 100, 'VK_NUMPAD4', empty, empty],
596 > [1, ScanCode.Numpad5, 'Numpad5', KeyCode.Numpad5, 'NumPad5', 101, 'VK_NUMPAD5', empty, empty],
597 > [1, ScanCode.Numpad6, 'Numpad6', KeyCode.Numpad6, 'NumPad6', 102, 'VK_NUMPAD6', empty, empty],
598 > [1, ScanCode.Numpad7, 'Numpad7', KeyCode.Numpad7, 'NumPad7', 103, 'VK_NUMPAD7', empty, empty],
599 > [1, ScanCode.Numpad8, 'Numpad8', KeyCode.Numpad8, 'NumPad8', 104, 'VK_NUMPAD8', empty, empty],
600 > [1, ScanCode.Numpad9, 'Numpad9', KeyCode.Numpad9, 'NumPad9', 105, 'VK_NUMPAD9', empty, empty],
601 > [1, ScanCode.Numpad0, 'Numpad0', KeyCode.Numpad0, 'NumPad0', 96, 'VK_NUMPAD0', empty, empty],
602 > [1, ScanCode.NumpadDecimal, 'NumpadDecimal', KeyCode.NumpadDecimal, 'NumPad_Decimal', 110, 'VK_DECIMAL', empty, empty],
603 > [0, ScanCode.IntlBackslash, 'IntlBackslash', KeyCode.IntlBackslash, 'OEM_102', 226, 'VK_OEM_102', empty, empty],
604 > [1, ScanCode.ContextMenu, 'ContextMenu', KeyCode.ContextMenu, 'ContextMenu', 93, empty, empty, empty],
605 > [1, ScanCode.Power, 'Power', KeyCode.Unknown, empty, 0, empty, empty, empty],
606 > [1, ScanCode.NumpadEqual, 'NumpadEqual', KeyCode.Unknown, empty, 0, empty, empty, empty],
607 > [1, ScanCode.F13, 'F13', KeyCode.F13, 'F13', 124, 'VK_F13', empty, empty],
608 > [1, ScanCode.F14, 'F14', KeyCode.F14, 'F14', 125, 'VK_F14', empty, empty],
609 > [1, ScanCode.F15, 'F15', KeyCode.F15, 'F15', 126, 'VK_F15', empty, empty],
610 > [1, ScanCode.F16, 'F16', KeyCode.F16, 'F16', 127, 'VK_F16', empty, empty],
611 > [1, ScanCode.F17, 'F17', KeyCode.F17, 'F17', 128, 'VK_F17', empty, empty],
612 > [1, ScanCode.F18, 'F18', KeyCode.F18, 'F18', 129, 'VK_F18', empty, empty],
613 > [1, ScanCode.F19, 'F19', KeyCode.F19, 'F19', 130, 'VK_F19', empty, empty],
614 > [1, ScanCode.F20, 'F20', KeyCode.F20, 'F20', 131, 'VK_F20', empty, empty],
615 > [1, ScanCode.F21, 'F21', KeyCode.F21, 'F21', 132, 'VK_F21', empty, empty],
616 > [1, ScanCode.F22, 'F22', KeyCode.F22, 'F22', 133, 'VK_F22', empty, empty],
617 > [1, ScanCode.F23, 'F23', KeyCode.F23, 'F23', 134, 'VK_F23', empty, empty],
618 > [1, ScanCode.F24, 'F24', KeyCode.F24, 'F24', 135, 'VK_F24', empty, empty],
619 > [1, ScanCode.Open, 'Open', KeyCode.Unknown, empty, 0, empty, empty, empty],
620 > [1, ScanCode.Help, 'Help', KeyCode.Unknown, empty, 0, empty, empty, empty],
621 > [1, ScanCode.Select, 'Select', KeyCode.Unknown, empty, 0, empty, empty, empty],
622 > [1, ScanCode.Again, 'Again', KeyCode.Unknown, empty, 0, empty, empty, empty],
623 > [1, ScanCode.Undo, 'Undo', KeyCode.Unknown, empty, 0, empty, empty, empty],
624 > [1, ScanCode.Cut, 'Cut', KeyCode.Unknown, empty, 0, empty, empty, empty],
625 > [1, ScanCode.Copy, 'Copy', KeyCode.Unknown, empty, 0, empty, empty, empty],
626 > [1, ScanCode.Paste, 'Paste', KeyCode.Unknown, empty, 0, empty, empty, empty],
627 > [1, ScanCode.Find, 'Find', KeyCode.Unknown, empty, 0, empty, empty, empty],
628 > [1, ScanCode.AudioVolumeMute, 'AudioVolumeMute', KeyCode.AudioVolumeMute, 'AudioVolumeMute', 173, 'VK_VOLUME_MUTE', empty, empty],
629 > [1, ScanCode.AudioVolumeUp, 'AudioVolumeUp', KeyCode.AudioVolumeUp, 'AudioVolumeUp', 175, 'VK_VOLUME_UP', empty, empty],
630 > [1, ScanCode.AudioVolumeDown, 'AudioVolumeDown', KeyCode.AudioVolumeDown, 'AudioVolumeDown', 174, 'VK_VOLUME_DOWN', empty, empty],
631 > [1, ScanCode.NumpadComma, 'NumpadComma', KeyCode.NUMPAD_SEPARATOR, 'NumPad_Separator', 108, 'VK_SEPARATOR', empty, empty],
632 > [0, ScanCode.IntlRo, 'IntlRo', KeyCode.ABNT_C1, 'ABNT_C1', 193, 'VK_ABNT_C1', empty, empty],
633 > [1, ScanCode.KanaMode, 'KanaMode', KeyCode.Unknown, empty, 0, empty, empty, empty],
634 > [0, ScanCode.IntlYen, 'IntlYen', KeyCode.Unknown, empty, 0, empty, empty, empty],
635 > [1, ScanCode.Convert, 'Convert', KeyCode.Unknown, empty, 0, empty, empty, empty],
636 > [1, ScanCode.NonConvert, 'NonConvert', KeyCode.Unknown, empty, 0, empty, empty, empty],
637 > [1, ScanCode.Lang1, 'Lang1', KeyCode.Unknown, empty, 0, empty, empty, empty],
638 > [1, ScanCode.Lang2, 'Lang2', KeyCode.Unknown, empty, 0, empty, empty, empty],
639 > [1, ScanCode.Lang3, 'Lang3', KeyCode.Unknown, empty, 0, empty, empty, empty],
640 > [1, ScanCode.Lang4, 'Lang4', KeyCode.Unknown, empty, 0, empty, empty, empty],
641 > [1, ScanCode.Lang5, 'Lang5', KeyCode.Unknown, empty, 0, empty, empty, empty],
642 > [1, ScanCode.Abort, 'Abort', KeyCode.Unknown, empty, 0, empty, empty, empty],
643 > [1, ScanCode.Props, 'Props', KeyCode.Unknown, empty, 0, empty, empty, empty],
644 > [1, ScanCode.NumpadParenLeft, 'NumpadParenLeft', KeyCode.Unknown, empty, 0, empty, empty, empty],
645 > [1, ScanCode.NumpadParenRight, 'NumpadParenRight', KeyCode.Unknown, empty, 0, empty, empty, empty],
646 > [1, ScanCode.NumpadBackspace, 'NumpadBackspace', KeyCode.Unknown, empty, 0, empty, empty, empty],
647 > [1, ScanCode.NumpadMemoryStore, 'NumpadMemoryStore', KeyCode.Unknown, empty, 0, empty, empty, empty],
648 > [1, ScanCode.NumpadMemoryRecall, 'NumpadMemoryRecall', KeyCode.Unknown, empty, 0, empty, empty, empty],
649 > [1, ScanCode.NumpadMemoryClear, 'NumpadMemoryClear', KeyCode.Unknown, empty, 0, empty, empty, empty],
650 > [1, ScanCode.NumpadMemoryAdd, 'NumpadMemoryAdd', KeyCode.Unknown, empty, 0, empty, empty, empty],
651 > [1, ScanCode.NumpadMemorySubtract, 'NumpadMemorySubtract', KeyCode.Unknown, empty, 0, empty, empty, empty],
652 > [1, ScanCode.NumpadClear, 'NumpadClear', KeyCode.Clear, 'Clear', 12, 'VK_CLEAR', empty, empty],
653 > [1, ScanCode.NumpadClearEntry, 'NumpadClearEntry', KeyCode.Unknown, empty, 0, empty, empty, empty],
654 > [1, ScanCode.None, empty, KeyCode.Ctrl, 'Ctrl', 17, 'VK_CONTROL', empty, empty],
655 > [1, ScanCode.None, empty, KeyCode.Shift, 'Shift', 16, 'VK_SHIFT', empty, empty],
656 > [1, ScanCode.None, empty, KeyCode.Alt, 'Alt', 18, 'VK_MENU', empty, empty],
657 > [1, ScanCode.None, empty, KeyCode.Meta, 'Meta', 91, 'VK_COMMAND', empty, empty],
658 > [1, ScanCode.ControlLeft, 'ControlLeft', KeyCode.Ctrl, empty, 0, 'VK_LCONTROL', empty, empty],
659 > [1, ScanCode.ShiftLeft, 'ShiftLeft', KeyCode.Shift, empty, 0, 'VK_LSHIFT', empty, empty],
660 > [1, ScanCode.AltLeft, 'AltLeft', KeyCode.Alt, empty, 0, 'VK_LMENU', empty, empty],
661 > [1, ScanCode.MetaLeft, 'MetaLeft', KeyCode.Meta, empty, 0, 'VK_LWIN', empty, empty],
662 > [1, ScanCode.ControlRight, 'ControlRight', KeyCode.Ctrl, empty, 0, 'VK_RCONTROL', empty, empty],
663 > [1, ScanCode.ShiftRight, 'ShiftRight', KeyCode.Shift, empty, 0, 'VK_RSHIFT', empty, empty],
664 > [1, ScanCode.AltRight, 'AltRight', KeyCode.Alt, empty, 0, 'VK_RMENU', empty, empty],
665 > [1, ScanCode.MetaRight, 'MetaRight', KeyCode.Meta, empty, 0, 'VK_RWIN', empty, empty],
666 > [1, ScanCode.BrightnessUp, 'BrightnessUp', KeyCode.Unknown, empty, 0, empty, empty, empty],
667 > [1, ScanCode.BrightnessDown, 'BrightnessDown', KeyCode.Unknown, empty, 0, empty, empty, empty],
668 > [1, ScanCode.MediaPlay, 'MediaPlay', KeyCode.Unknown, empty, 0, empty, empty, empty],
669 > [1, ScanCode.MediaRecord, 'MediaRecord', KeyCode.Unknown, empty, 0, empty, empty, empty],
670 > [1, ScanCode.MediaFastForward, 'MediaFastForward', KeyCode.Unknown, empty, 0, empty, empty, empty],
671 > [1, ScanCode.MediaRewind, 'MediaRewind', KeyCode.Unknown, empty, 0, empty, empty, empty],
672 > [1, ScanCode.MediaTrackNext, 'MediaTrackNext', KeyCode.MediaTrackNext, 'MediaTrackNext', 176, 'VK_MEDIA_NEXT_TRACK', empty, empty],
673 > [1, ScanCode.MediaTrackPrevious, 'MediaTrackPrevious', KeyCode.MediaTrackPrevious, 'MediaTrackPrevious', 177, 'VK_MEDIA_PREV_TRACK', empty, empty],
674 > [1, ScanCode.MediaStop, 'MediaStop', KeyCode.MediaStop, 'MediaStop', 178, 'VK_MEDIA_STOP', empty, empty],
675 > [1, ScanCode.Eject, 'Eject', KeyCode.Unknown, empty, 0, empty, empty, empty],
676 > [1, ScanCode.MediaPlayPause, 'MediaPlayPause', KeyCode.MediaPlayPause, 'MediaPlayPause', 179, 'VK_MEDIA_PLAY_PAUSE', empty, empty],
677 > [1, ScanCode.MediaSelect, 'MediaSelect', KeyCode.LaunchMediaPlayer, 'LaunchMediaPlayer', 181, 'VK_MEDIA_LAUNCH_MEDIA_SELECT', empty, empty],
678 > [1, ScanCode.LaunchMail, 'LaunchMail', KeyCode.LaunchMail, 'LaunchMail', 180, 'VK_MEDIA_LAUNCH_MAIL', empty, empty],
679 > [1, ScanCode.LaunchApp2, 'LaunchApp2', KeyCode.LaunchApp2, 'LaunchApp2', 183, 'VK_MEDIA_LAUNCH_APP2', empty, empty],
680 > [1, ScanCode.LaunchApp1, 'LaunchApp1', KeyCode.Unknown, empty, 0, 'VK_MEDIA_LAUNCH_APP1', empty, empty],
681 > [1, ScanCode.SelectTask, 'SelectTask', KeyCode.Unknown, empty, 0, empty, empty, empty],
682 > [1, ScanCode.LaunchScreenSaver, 'LaunchScreenSaver', KeyCode.Unknown, empty, 0, empty, empty, empty],
683 > [1, ScanCode.BrowserSearch, 'BrowserSearch', KeyCode.BrowserSearch, 'BrowserSearch', 170, 'VK_BROWSER_SEARCH', empty, empty],
684 > [1, ScanCode.BrowserHome, 'BrowserHome', KeyCode.BrowserHome, 'BrowserHome', 172, 'VK_BROWSER_HOME', empty, empty],
685 > [1, ScanCode.BrowserBack, 'BrowserBack', KeyCode.BrowserBack, 'BrowserBack', 166, 'VK_BROWSER_BACK', empty, empty],
686 > [1, ScanCode.BrowserForward, 'BrowserForward', KeyCode.BrowserForward, 'BrowserForward', 167, 'VK_BROWSER_FORWARD', empty, empty],
687 > [1, ScanCode.BrowserStop, 'BrowserStop', KeyCode.Unknown, empty, 0, 'VK_BROWSER_STOP', empty, empty],
688 > [1, ScanCode.BrowserRefresh, 'BrowserRefresh', KeyCode.Unknown, empty, 0, 'VK_BROWSER_REFRESH', empty, empty],
689 > [1, ScanCode.BrowserFavorites, 'BrowserFavorites', KeyCode.Unknown, empty, 0, 'VK_BROWSER_FAVORITES', empty, empty],
690 > [1, ScanCode.ZoomToggle, 'ZoomToggle', KeyCode.Unknown, empty, 0, empty, empty, empty],
691 > [1, ScanCode.MailReply, 'MailReply', KeyCode.Unknown, empty, 0, empty, empty, empty],
692 > [1, ScanCode.MailForward, 'MailForward', KeyCode.Unknown, empty, 0, empty, empty, empty],
693 > [1, ScanCode.MailSend, 'MailSend', KeyCode.Unknown, empty, 0, empty, empty, empty],
694 >
695 > // See https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html
696 > // If an Input Method Editor is processing key input and the event is keydown, return 229.
697 > [1, ScanCode.None, empty, KeyCode.KEY_IN_COMPOSITION, 'KeyInComposition', 229, empty, empty, empty],
698 > [1, ScanCode.None, empty, KeyCode.ABNT_C2, 'ABNT_C2', 194, 'VK_ABNT_C2', empty, empty],
699 > [1, ScanCode.None, empty, KeyCode.OEM_8, 'OEM_8', 223, 'VK_OEM_8', empty, empty],
700 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_KANA', empty, empty],
701 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_HANGUL', empty, empty],
702 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_JUNJA', empty, empty],
703 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_FINAL', empty, empty],
704 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_HANJA', empty, empty],
705 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_KANJI', empty, empty],
706 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_CONVERT', empty, empty],
707 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_NONCONVERT', empty, empty],
708 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_ACCEPT', empty, empty],
709 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_MODECHANGE', empty, empty],
710 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_SELECT', empty, empty],
711 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PRINT', empty, empty],
712 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_EXECUTE', empty, empty],
713 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_SNAPSHOT', empty, empty],
714 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_HELP', empty, empty],
715 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_APPS', empty, empty],
716 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PROCESSKEY', empty, empty],
717 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PACKET', empty, empty],
718 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_DBE_SBCSCHAR', empty, empty],
719 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_DBE_DBCSCHAR', empty, empty],
720 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_ATTN', empty, empty],
721 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_CRSEL', empty, empty],
722 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_EXSEL', empty, empty],
723 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_EREOF', empty, empty],
724 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PLAY', empty, empty],
725 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_ZOOM', empty, empty],
726 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_NONAME', empty, empty],
727 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PA1', empty, empty],
728 > [1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_OEM_CLEAR', empty, empty],
729 > ];
730 >
731 > const seenKeyCode: boolean[] = [];
732 > const seenScanCode: boolean[] = [];
733 > for (const mapping of mappings) {
734 > const [immutable, scanCode, scanCodeStr, keyCode, keyCodeStr, eventKeyCode, vkey, usUserSettingsLabel, generalUserSettingsLabel] = mapping;
735 > if (!seenScanCode[scanCode]) {
736 > seenScanCode[scanCode] = true;
737 > scanCodeIntToStr[scanCode] = scanCodeStr;
738 > scanCodeStrToInt[scanCodeStr] = scanCode;
739 > scanCodeLowerCaseStrToInt[scanCodeStr.toLowerCase()] = scanCode;
740 > if (immutable) {
741 > IMMUTABLE_CODE_TO_KEY_CODE[scanCode] = keyCode;
742 > if ((keyCode !== KeyCode.Unknown) && (keyCode !== KeyCode.Enter) && !isModifierKey(keyCode)) {
743 > IMMUTABLE_KEY_CODE_TO_CODE[keyCode] = scanCode;
744 > }
745 > }
746 > }
747 > if (!seenKeyCode[keyCode]) {
748 > seenKeyCode[keyCode] = true;
749 > if (!keyCodeStr) {
750 throw new Error(`String representation missing for key code ${keyCode} around scan code ${scanCodeStr}`);
751 }
752 > uiMap.define(keyCode, keyCodeStr); keyCodes.ts
753 > userSettingsUSMap.define(keyCode, usUserSettingsLabel || keyCodeStr);
754 > userSettingsGeneralMap.define(keyCode, generalUserSettingsLabel || usUserSettingsLabel || keyCodeStr);
755 > }
756 > if (eventKeyCode) {
757 > EVENT_KEY_CODE_MAP[eventKeyCode] = keyCode;
758 > }
759 > if (scanCodeStr) {
760 > SCAN_CODE_STR_TO_EVENT_KEY_CODE[scanCodeStr] = eventKeyCode;
761 > }
762 > if (vkey) {
763 > NATIVE_WINDOWS_KEY_CODE_TO_KEY_CODE[vkey] = keyCode;
764 > }
765 > }
766 > // Manually added due to the exclusion above (due to duplication with NumpadEnter)
767 > IMMUTABLE_KEY_CODE_TO_CODE[KeyCode.Enter] = ScanCode.Enter;
768 >
769 > })();
770 >
771 > export namespace KeyCodeUtils {
772 > export function toString(keyCode: KeyCode): string {
773 return uiMap.keyCodeToStr(keyCode);
774 }
775 > export function fromString(key: string): KeyCode { keyCodes.ts
776 return uiMap.strToKeyCode(key);
777 }
778 > keyCodes.ts
779 > export function toUserSettingsUS(keyCode: KeyCode): string {
780 return userSettingsUSMap.keyCodeToStr(keyCode);
781 }
782 > export function toUserSettingsGeneral(keyCode: KeyCode): string { keyCodes.ts
783 return userSettingsGeneralMap.keyCodeToStr(keyCode);
784 }
785 > export function fromUserSettings(key: string): KeyCode { keyCodes.ts
786 return userSettingsUSMap.strToKeyCode(key) || userSettingsGeneralMap.strToKeyCode(key);
787 }
788 > keyCodes.ts
789 > export function toElectronAccelerator(keyCode: KeyCode): string | null {
790 if (keyCode >= KeyCode.Numpad0 && keyCode <= KeyCode.NumpadDivide) {
791 // [Electron Accelerators] Electron is able to parse numpad keys, but unfortunately it
815 return uiMap.keyCodeToStr(keyCode);
816 }
817 > } keyCodes.ts
818 >
819 > export const enum KeyMod {
820 > CtrlCmd = (1 << 11) >>> 0,
821 > Shift = (1 << 10) >>> 0,
822 > Alt = (1 << 9) >>> 0,
823 > WinCtrl = (1 << 8) >>> 0,
824 > }
825 >
826 > export function KeyChord(firstPart: number, secondPart: number): number {
827 const chordPart = ((secondPart & 0x0000FFFF) << 16) >>> 0;
828 return (firstPart | chordPart) >>> 0;
829 }
830 > keyCodes.ts
831 > export function isModifierKey(keyCode: KeyCode): boolean {
832 > return (
833 > keyCode === KeyCode.Ctrl
834 > || keyCode === KeyCode.Shift
835 > || keyCode === KeyCode.Alt
836 > || keyCode === KeyCode.Meta
837 > );
838 > }
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/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/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations.ts 443 covered LOC · 109 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- heuristicSequenceOptimizations.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 { forEachWithNeighbors } from '../../../../base/common/arrays.js';
7 > import { OffsetRange } from '../../core/ranges/offsetRange.js';
8 > import { ISequence, OffsetPair, SequenceDiff } from './algorithms/diffAlgorithm.js';
9 > import { LineSequence } from './lineSequence.js';
10 > import { LinesSliceCharSequence } from './linesSliceCharSequence.js';
11 >
12 > export function optimizeSequenceDiffs(sequence1: ISequence, sequence2: ISequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {
13 > let result = sequenceDiffs; heuristicSequenceOptimizations.ts
14 > result = joinSequenceDiffsByShifting(sequence1, sequence2, result);
15 > // Sometimes, calling this function twice improves the result.
16 > // Uncomment the second invocation and run the tests to see the difference.
17 > result = joinSequenceDiffsByShifting(sequence1, sequence2, result);
18 > result = shiftSequenceDiffs(sequence1, sequence2, result);
19 > return result;
20 > }
22 > /**
23 > * This function fixes issues like this:
24 > * ```
25 > * import { Baz, Bar } from "foo";
26 > * ```
27 > * <->
28 > * ```
29 > * import { Baz, Bar, Foo } from "foo";
30 > * ```
31 > * Computed diff: [ {Add "," after Bar}, {Add "Foo " after space} }
32 > * Improved diff: [{Add ", Foo" after Bar}]
33 > */
34 > function joinSequenceDiffsByShifting(sequence1: ISequence, sequence2: ISequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] { heuristicSequenceOptimizations.ts
35 > if (sequenceDiffs.length === 0) {
36 return sequenceDiffs;
37 }
39 > const result: SequenceDiff[] = [];
40 > result.push(sequenceDiffs[0]);
41 >
42 > // First move them all to the left as much as possible and join them if possible
43 > for (let i = 1; i < sequenceDiffs.length; i++) {
44 > const prevResult = result[result.length - 1]; heuristicSequenceOptimizations.ts
45 > let cur = sequenceDiffs[i];
46 >
47 > if (cur.seq1Range.isEmpty || cur.seq2Range.isEmpty) {
48 > const length = cur.seq1Range.start - prevResult.seq1Range.endExclusive; heuristicSequenceOptimizations.ts
49 > let d;
50 > for (d = 1; d <= length; d++) {
51 > if (
52 > sequence1.getElement(cur.seq1Range.start - d) !== sequence1.getElement(cur.seq1Range.endExclusive - d) ||
53 > sequence2.getElement(cur.seq2Range.start - d) !== sequence2.getElement(cur.seq2Range.endExclusive - d)) {
55 > }
57 > d--;
58 >
59 > if (d === length) {
60 // Merge previous and current diff
61 result[result.length - 1] = new SequenceDiff(
65 continue;
66 }
68 > cur = cur.delta(-d);
69 > }
71 > result.push(cur);
72 > }
74 > const result2: SequenceDiff[] = [];
75 > // Then move them all to the right and join them again if possible
76 > for (let i = 0; i < result.length - 1; i++) {
77 > const nextResult = result[i + 1]; heuristicSequenceOptimizations.ts
78 > let cur = result[i];
79 >
80 > if (cur.seq1Range.isEmpty || cur.seq2Range.isEmpty) {
81 > const length = nextResult.seq1Range.start - cur.seq1Range.endExclusive; heuristicSequenceOptimizations.ts
82 > let d;
83 > for (d = 0; d < length; d++) {
84 > if (
85 > !sequence1.isStronglyEqual(cur.seq1Range.start + d, cur.seq1Range.endExclusive + d) ||
86 > !sequence2.isStronglyEqual(cur.seq2Range.start + d, cur.seq2Range.endExclusive + d) heuristicSequenceOptimizations.ts
89 > }
91 >
92 > if (d === length) {
93 // Merge previous and current diff, write to result!
94 result[i + 1] = new SequenceDiff(
98 continue;
99 }
101 > if (d > 0) {
102 > cur = cur.delta(d); heuristicSequenceOptimizations.ts
103 > }
106 > result2.push(cur);
107 > }
109 > if (result.length > 0) {
110 > result2.push(result[result.length - 1]);
111 > }
112 >
113 > return result2;
114 > }
116 > // align character level diffs at whitespace characters
117 > // import { IBar } from "foo";
118 > // import { I[Arr, I]Bar } from "foo";
119 > // ->
120 > // import { [IArr, ]IBar } from "foo";
121 >
122 > // import { ITransaction, observableValue, transaction } from 'vs/base/common/observable';
123 > // import { ITransaction, observable[FromEvent, observable]Value, transaction } from 'vs/base/common/observable';
124 > // ->
125 > // import { ITransaction, [observableFromEvent, ]observableValue, transaction } from 'vs/base/common/observable';
126 >
127 > // collectBrackets(level + 1, levelPerBracketType);
128 > // collectBrackets(level + 1, levelPerBracket[ + 1, levelPerBracket]Type);
129 > // ->
130 > // collectBrackets(level + 1, [levelPerBracket + 1, ]levelPerBracketType);
131 >
132 > function shiftSequenceDiffs(sequence1: ISequence, sequence2: ISequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] { heuristicSequenceOptimizations.ts
133 > if (!sequence1.getBoundaryScore || !sequence2.getBoundaryScore) {
134 return sequenceDiffs;
135 }
137 > for (let i = 0; i < sequenceDiffs.length; i++) {
138 > const prevDiff = (i > 0 ? sequenceDiffs[i - 1] : undefined); heuristicSequenceOptimizations.ts
139 > const diff = sequenceDiffs[i];
140 > const nextDiff = (i + 1 < sequenceDiffs.length ? sequenceDiffs[i + 1] : undefined);
141 >
142 > const seq1ValidRange = new OffsetRange(prevDiff ? prevDiff.seq1Range.endExclusive + 1 : 0, nextDiff ? nextDiff.seq1Range.start - 1 : sequence1.length);
143 > const seq2ValidRange = new OffsetRange(prevDiff ? prevDiff.seq2Range.endExclusive + 1 : 0, nextDiff ? nextDiff.seq2Range.start - 1 : sequence2.length);
144 >
145 > if (diff.seq1Range.isEmpty) {
146 > sequenceDiffs[i] = shiftDiffToBetterPosition(diff, sequence1, sequence2, seq1ValidRange, seq2ValidRange); heuristicSequenceOptimizations.ts
147 > } else if (diff.seq2Range.isEmpty) { heuristicSequenceOptimizations.ts
148 > sequenceDiffs[i] = shiftDiffToBetterPosition(diff.swap(), sequence2, sequence1, seq2ValidRange, seq1ValidRange).swap(); heuristicSequenceOptimizations.ts
149 > }
152 > return sequenceDiffs;
153 > }
155 > function shiftDiffToBetterPosition(diff: SequenceDiff, sequence1: ISequence, sequence2: ISequence, seq1ValidRange: OffsetRange, seq2ValidRange: OffsetRange,) { heuristicSequenceOptimizations.ts
156 > const maxShiftLimit = 100; // To prevent performance issues
157 >
158 > // don't touch previous or next!
159 > let deltaBefore = 1;
160 > while (
161 > diff.seq1Range.start - deltaBefore >= seq1ValidRange.start &&
162 > diff.seq2Range.start - deltaBefore >= seq2ValidRange.start && heuristicSequenceOptimizations.ts
163 > sequence2.isStronglyEqual(diff.seq2Range.start - deltaBefore, diff.seq2Range.endExclusive - deltaBefore) && deltaBefore < maxShiftLimit heuristicSequenceOptimizations.ts
164 > ) {
165 > deltaBefore++; heuristicSequenceOptimizations.ts
166 > }
167 > deltaBefore--; heuristicSequenceOptimizations.ts
168 >
169 > let deltaAfter = 0;
170 > while (
171 > diff.seq1Range.start + deltaAfter < seq1ValidRange.endExclusive &&
172 > diff.seq2Range.endExclusive + deltaAfter < seq2ValidRange.endExclusive && heuristicSequenceOptimizations.ts
173 > sequence2.isStronglyEqual(diff.seq2Range.start + deltaAfter, diff.seq2Range.endExclusive + deltaAfter) && deltaAfter < maxShiftLimit heuristicSequenceOptimizations.ts
174 > ) {
175 > deltaAfter++; heuristicSequenceOptimizations.ts
176 > }
178 > if (deltaBefore === 0 && deltaAfter === 0) {
180 > }
182 > // Visualize `[sequence1.text, diff.seq1Range.start + deltaAfter]`
183 > // and `[sequence2.text, diff.seq2Range.start + deltaAfter, diff.seq2Range.endExclusive + deltaAfter]`
184 >
185 > let bestDelta = 0;
186 > let bestScore = -1;
187 > // find best scored delta
188 > for (let delta = -deltaBefore; delta <= deltaAfter; delta++) {
189 > const seq2OffsetStart = diff.seq2Range.start + delta;
190 > const seq2OffsetEndExclusive = diff.seq2Range.endExclusive + delta;
191 > const seq1Offset = diff.seq1Range.start + delta;
192 >
193 > const score = sequence1.getBoundaryScore!(seq1Offset) + sequence2.getBoundaryScore!(seq2OffsetStart) + sequence2.getBoundaryScore!(seq2OffsetEndExclusive);
194 > if (score > bestScore) {
195 > bestScore = score;
196 > bestDelta = delta;
197 > }
198 > }
199 >
200 > return diff.delta(bestDelta);
201 > }
203 > export function removeShortMatches(sequence1: ISequence, sequence2: ISequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {
204 > const result: SequenceDiff[] = []; heuristicSequenceOptimizations.ts
205 > for (const s of sequenceDiffs) {
206 > const last = result[result.length - 1];
207 > if (!last) {
208 > result.push(s);
209 > continue;
210 > }
212 > if (s.seq1Range.start - last.seq1Range.endExclusive <= 2 || s.seq2Range.start - last.seq2Range.endExclusive <= 2) { heuristicSequenceOptimizations.ts
213 > result[result.length - 1] = new SequenceDiff(last.seq1Range.join(s.seq1Range), last.seq2Range.join(s.seq2Range)); heuristicSequenceOptimizations.ts
215 > result.push(s); heuristicSequenceOptimizations.ts
216 > }
218 >
219 > return result;
220 > }
222 > export function extendDiffsToEntireWordIfAppropriate(
223 > sequence1: LinesSliceCharSequence, heuristicSequenceOptimizations.ts
224 > sequence2: LinesSliceCharSequence,
225 > sequenceDiffs: SequenceDiff[],
226 > findParent: (seq: LinesSliceCharSequence, idx: number) => OffsetRange | undefined,
227 > force: boolean = false,
228 > ): SequenceDiff[] {
229 > const equalMappings = SequenceDiff.invert(sequenceDiffs, sequence1.length);
230 >
231 > const additional: SequenceDiff[] = [];
232 >
233 > let lastPoint = new OffsetPair(0, 0);
234 >
235 > function scanWord(pair: OffsetPair, equalMapping: SequenceDiff) {
236 > if (pair.offset1 < lastPoint.offset1 || pair.offset2 < lastPoint.offset2) { heuristicSequenceOptimizations.ts
238 > }
240 > const w1 = findParent(sequence1, pair.offset1);
241 > const w2 = findParent(sequence2, pair.offset2);
242 > if (!w1 || !w2) {
243 > return;
244 > }
245 > let w = new SequenceDiff(w1, w2); heuristicSequenceOptimizations.ts
246 > const equalPart = w.intersect(equalMapping)!;
247 >
248 > let equalChars1 = equalPart.seq1Range.length;
249 > let equalChars2 = equalPart.seq2Range.length;
250 >
251 > // The words do not touch previous equals mappings, as we would have processed them already.
252 > // But they might touch the next ones.
253 >
254 > while (equalMappings.length > 0) {
255 > const next = equalMappings[0]; heuristicSequenceOptimizations.ts
256 > const intersects = next.seq1Range.intersects(w.seq1Range) || next.seq2Range.intersects(w.seq2Range);
257 > if (!intersects) {
259 > }
261 > const v1 = findParent(sequence1, next.seq1Range.start);
262 > const v2 = findParent(sequence2, next.seq2Range.start);
263 > // Because there is an intersection, we know that the words are not empty.
264 > const v = new SequenceDiff(v1!, v2!);
265 > const equalPart = v.intersect(next)!;
266 >
267 > equalChars1 += equalPart.seq1Range.length;
268 > equalChars2 += equalPart.seq2Range.length;
269 >
270 > w = w.join(v);
271 >
272 > if (w.seq1Range.endExclusive >= next.seq1Range.endExclusive) {
273 > // The word extends beyond the next equal mapping. heuristicSequenceOptimizations.ts
274 > equalMappings.shift();
276 break;
277 }
280 > if ((force && equalChars1 + equalChars2 < w.seq1Range.length + w.seq2Range.length) || equalChars1 + equalChars2 < (w.seq1Range.length + w.seq2Range.length) * 2 / 3) { heuristicSequenceOptimizations.ts
281 > additional.push(w); heuristicSequenceOptimizations.ts
282 > }
284 > lastPoint = w.getEndExclusives();
287 > while (equalMappings.length > 0) {
288 > const next = equalMappings.shift()!;
289 > if (next.seq1Range.isEmpty) {
291 > }
292 > scanWord(next.getStarts(), next); heuristicSequenceOptimizations.ts
293 > // The equal parts are not empty, so -1 gives us a character that is equal in both parts.
294 > scanWord(next.getEndExclusives().delta(-1), next);
295 > }
297 > const merged = mergeSequenceDiffs(sequenceDiffs, additional);
298 > return merged;
299 > }
301 > function mergeSequenceDiffs(sequenceDiffs1: SequenceDiff[], sequenceDiffs2: SequenceDiff[]): SequenceDiff[] { heuristicSequenceOptimizations.ts
302 > const result: SequenceDiff[] = [];
303 >
304 > while (sequenceDiffs1.length > 0 || sequenceDiffs2.length > 0) {
305 > const sd1 = sequenceDiffs1[0];
306 > const sd2 = sequenceDiffs2[0];
307 >
308 > let next: SequenceDiff;
309 > if (sd1 && (!sd2 || sd1.seq1Range.start < sd2.seq1Range.start)) {
310 > next = sequenceDiffs1.shift()!;
311 > } else {
312 > next = sequenceDiffs2.shift()!; heuristicSequenceOptimizations.ts
313 > }
315 > if (result.length > 0 && result[result.length - 1].seq1Range.endExclusive >= next.seq1Range.start) {
316 > result[result.length - 1] = result[result.length - 1].join(next); heuristicSequenceOptimizations.ts
318 > result.push(next);
319 > }
320 > }
321 >
322 > return result;
323 > }
325 > export function removeVeryShortMatchingLinesBetweenDiffs(sequence1: LineSequence, _sequence2: LineSequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {
326 > let diffs = sequenceDiffs; heuristicSequenceOptimizations.ts
327 > if (diffs.length === 0) {
328 return diffs;
329 }
331 > let counter = 0;
332 > let shouldRepeat: boolean;
333 > do {
334 > shouldRepeat = false;
335 >
336 > const result: SequenceDiff[] = [
337 > diffs[0]
338 > ];
339 >
340 > for (let i = 1; i < diffs.length; i++) {
341 > const cur = diffs[i]; heuristicSequenceOptimizations.ts
342 > const lastResult = result[result.length - 1];
343 >
344 > function shouldJoinDiffs(before: SequenceDiff, after: SequenceDiff): boolean {
345 > const unchangedRange = new OffsetRange(lastResult.seq1Range.endExclusive, cur.seq1Range.start);
346 >
347 > const unchangedText = sequence1.getText(unchangedRange);
348 > const unchangedTextWithoutWs = unchangedText.replace(/\s/g, '');
349 > if (unchangedTextWithoutWs.length <= 4
350 > && (before.seq1Range.length + before.seq2Range.length > 5 || after.seq1Range.length + after.seq2Range.length > 5)) {
351 return true;
352 }
354 > return false;
356 >
357 > const shouldJoin = shouldJoinDiffs(lastResult, cur);
358 > if (shouldJoin) {
359 shouldRepeat = true;
360 result[result.length - 1] = result[result.length - 1].join(cur);
362 > result.push(cur); heuristicSequenceOptimizations.ts
363 > }
365 >
366 > diffs = result;
367 > } while (counter++ < 10 && shouldRepeat); heuristicSequenceOptimizations.ts
369 > return diffs;
370 > }
372 > export function removeVeryShortMatchingTextBetweenLongDiffs(sequence1: LinesSliceCharSequence, sequence2: LinesSliceCharSequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {
373 > let diffs = sequenceDiffs; heuristicSequenceOptimizations.ts
374 > if (diffs.length === 0) {
375 return diffs;
376 }
378 > let counter = 0;
379 > let shouldRepeat: boolean;
380 > do {
381 > shouldRepeat = false;
382 >
383 > const result: SequenceDiff[] = [
384 > diffs[0]
385 > ];
386 >
387 > for (let i = 1; i < diffs.length; i++) {
388 > const cur = diffs[i]; heuristicSequenceOptimizations.ts
389 > const lastResult = result[result.length - 1];
390 >
391 > function shouldJoinDiffs(before: SequenceDiff, after: SequenceDiff): boolean {
392 > const unchangedRange = new OffsetRange(lastResult.seq1Range.endExclusive, cur.seq1Range.start);
393 >
394 > const unchangedLineCount = sequence1.countLinesIn(unchangedRange);
395 > if (unchangedLineCount > 5 || unchangedRange.length > 500) {
396 return false;
397 }
399 > const unchangedText = sequence1.getText(unchangedRange).trim();
400 > if (unchangedText.length > 20 || unchangedText.split(/\r\n|\r|\n/).length > 1) {
401 > return false; heuristicSequenceOptimizations.ts
402 > }
404 > const beforeLineCount1 = sequence1.countLinesIn(before.seq1Range);
405 > const beforeSeq1Length = before.seq1Range.length;
406 > const beforeLineCount2 = sequence2.countLinesIn(before.seq2Range);
407 > const beforeSeq2Length = before.seq2Range.length;
408 >
409 > const afterLineCount1 = sequence1.countLinesIn(after.seq1Range);
410 > const afterSeq1Length = after.seq1Range.length;
411 > const afterLineCount2 = sequence2.countLinesIn(after.seq2Range);
412 > const afterSeq2Length = after.seq2Range.length;
413 >
414 > // TODO: Maybe a neural net can be used to derive the result from these numbers
415 >
416 > const max = 2 * 40 + 50;
417 > function cap(v: number): number {
418 > return Math.min(v, max);
419 > }
420 >
421 > if (Math.pow(Math.pow(cap(beforeLineCount1 * 40 + beforeSeq1Length), 1.5) + Math.pow(cap(beforeLineCount2 * 40 + beforeSeq2Length), 1.5), 1.5)
422 > + Math.pow(Math.pow(cap(afterLineCount1 * 40 + afterSeq1Length), 1.5) + Math.pow(cap(afterLineCount2 * 40 + afterSeq2Length), 1.5), 1.5) > ((max ** 1.5) ** 1.5) * 1.3) {
424 > }
425 > return false; heuristicSequenceOptimizations.ts
427 >
428 > const shouldJoin = shouldJoinDiffs(lastResult, cur);
429 > if (shouldJoin) {
430 > shouldRepeat = true; heuristicSequenceOptimizations.ts
431 > result[result.length - 1] = result[result.length - 1].join(cur);
433 > result.push(cur);
434 > }
435 > }
436 >
437 > diffs = result;
438 > } while (counter++ < 10 && shouldRepeat); heuristicSequenceOptimizations.ts
439 >
440 > const newDiffs: SequenceDiff[] = [];
441 >
442 > // Remove short suffixes/prefixes
443 > forEachWithNeighbors(diffs, (prev, cur, next) => {
444 > let newDiff = cur;
445 >
446 > function shouldMarkAsChanged(text: string): boolean {
447 > return text.length > 0 && text.trim().length <= 3 && cur.seq1Range.length + cur.seq2Range.length > 100;
448 > }
449 >
450 > const fullRange1 = sequence1.extendToFullLines(cur.seq1Range);
451 > const prefix = sequence1.getText(new OffsetRange(fullRange1.start, cur.seq1Range.start));
452 > if (shouldMarkAsChanged(prefix)) {
453 > newDiff = newDiff.deltaStart(-prefix.length); heuristicSequenceOptimizations.ts
454 > }
455 > const suffix = sequence1.getText(new OffsetRange(cur.seq1Range.endExclusive, fullRange1.endExclusive)); heuristicSequenceOptimizations.ts
456 > if (shouldMarkAsChanged(suffix)) {
457 > newDiff = newDiff.deltaEnd(suffix.length); heuristicSequenceOptimizations.ts
458 > }
460 > const availableSpace = SequenceDiff.fromOffsetPairs(
461 > prev ? prev.getEndExclusives() : OffsetPair.zero,
462 > next ? next.getStarts() : OffsetPair.max,
463 > );
464 > const result = newDiff.intersect(availableSpace)!;
465 > if (newDiffs.length > 0 && result.getStarts().equals(newDiffs[newDiffs.length - 1].getEndExclusives())) {
466 > newDiffs[newDiffs.length - 1] = newDiffs[newDiffs.length - 1].join(result); heuristicSequenceOptimizations.ts
468 > newDiffs.push(result);
469 > }
470 > });
471 >
472 > return newDiffs;
473 > }
src/vs/base/common/arrays.ts 431 covered LOC · 84 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; arrays.ts
176 > let last: T | undefined;
177 > for (const item of items) {
178 > if (last !== undefined && shouldBeGrouped(last, item)) { arrays.ts
179 > currentGroup!.push(item); arrays.ts
180 > } else { arrays.ts
181 > if (currentGroup) {
182 > yield currentGroup; arrays.ts
183 > }
184 > currentGroup = [item]; arrays.ts
185 > }
186 > last = item;
187 > }
188 > if (currentGroup) { arrays.ts
189 > yield currentGroup; arrays.ts
190 > }
191 > } arrays.ts
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++) { arrays.ts
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++) { arrays.ts
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)); arrays.ts
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 411 covered LOC · 70 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) {
73 path = _slash;
76 }
77 break;
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); uri.ts
273 > if (!match) {
274 return new Uri(_empty, _empty, _empty, _empty, _empty);
275 }
276 > return new Uri( uri.ts
277 > match[2] || _empty,
278 > percentDecode(match[4] || _empty),
279 > percentDecode(match[5] || _empty),
280 > percentDecode(match[7] || _empty),
281 > percentDecode(match[9] || _empty),
282 > _strict
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
309 let authority = _empty;
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) { uri.ts
469 > if (!this._formatted) { uri.ts
470 > this._formatted = _asFormatted(this, false);
471 > }
472 > return this._formatted;
473 > } else { uri.ts
474 // we don't cache that
475 return _asFormatted(this, true);
476 }
477 > } uri.ts
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 { uri.ts
542 > let res: string | undefined = undefined;
543 > let nativeEncodePos = -1;
544 >
545 > for (let pos = 0; pos < uriComponent.length; pos++) {
546 > const code = uriComponent.charCodeAt(pos);
547 >
548 > // unreserved characters: https://tools.ietf.org/html/rfc3986#section-2.3
549 > if (
550 > (code >= CharCode.a && code <= CharCode.z)
551 > || (code >= CharCode.A && code <= CharCode.Z) uri.ts
552 > || (code >= CharCode.Digit0 && code <= CharCode.Digit9)
553 || code === CharCode.Dash
554 || code === CharCode.Period
559 || (isAuthority && code === CharCode.CloseSquareBracket)
560 || (isAuthority && code === CharCode.Colon)
561 > ) { uri.ts
562 > // check if we are delaying native encode
563 > if (nativeEncodePos !== -1) {
564 res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));
565 nativeEncodePos = -1;
566 }
567 > // check if we write into a new string (by default we try to return the param) uri.ts
568 > if (res !== undefined) {
569 res += uriComponent.charAt(pos);
570 }
571 > uri.ts
572 > } else {
573 // encoding needed, we need to allocate a new string
574 if (res === undefined) {
594 }
595 }
596 > } uri.ts
597 >
598 > if (nativeEncodePos !== -1) {
599 res += encodeURIComponent(uriComponent.substring(nativeEncodePos));
600 }
601 > uri.ts
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 { uri.ts
657 >
658 > const encoder = !skipEncoding
659 > ? encodeURIComponentFast uri.ts
660 : encodeURIComponentMinimal;
661 > uri.ts
662 > let res = '';
663 > let { scheme, authority, path, query, fragment } = uri;
664 > if (scheme) {
665 > res += scheme;
666 > res += ':';
667 > }
668 > if (authority || scheme === 'file') {
669 res += _slash;
670 res += _slash;
671 }
672 > if (authority) { uri.ts
673 let idx = authority.indexOf('@');
674 if (idx !== -1) {
697 }
698 }
699 > if (path) { uri.ts
700 > // lower-case windows drive letters in /C:/fff or C:/fff uri.ts
701 > if (path.length >= 3 && path.charCodeAt(0) === CharCode.Slash && path.charCodeAt(2) === CharCode.Colon) {
702 const code = path.charCodeAt(1);
703 if (code >= CharCode.A && code <= CharCode.Z) {
704 path = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // "/c:".length === 3
705 }
706 > } else if (path.length >= 2 && path.charCodeAt(1) === CharCode.Colon) { uri.ts
707 const code = path.charCodeAt(0);
708 if (code >= CharCode.A && code <= CharCode.Z) {
710 }
711 }
712 > // encode the rest of the path uri.ts
713 > res += encoder(path, true, false);
714 > }
715 > if (query) { uri.ts
716 res += '?';
717 res += encoder(query, false, false);
718 }
719 > if (fragment) { uri.ts
720 > res += '#'; uri.ts
721 > res += !skipEncoding ? encodeURIComponentFast(fragment, false, false) : fragment;
722 > }
723 > return res; uri.ts
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 { uri.ts
743 > if (!str.match(_rEncodedAsHex)) {
744 > return str;
745 > }
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 325 covered LOC · 100 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>>(); map.ts
240 > this._head = undefined;
241 > this._tail = undefined;
242 > this._size = 0;
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(); map.ts
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); map.ts
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/stream.ts 325 covered LOC · 29 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- stream.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 './cancellation.js';
7 > import { onUnexpectedError } from './errors.js';
8 > import { DisposableStore, toDisposable } from './lifecycle.js';
9 >
10 > /**
11 > * The payload that flows in readable stream events.
12 > */
13 > export type ReadableStreamEventPayload<T> = T | Error | 'end';
14 >
15 > export interface ReadableStreamEvents<T> {
16 >
17 > /**
18 > * The 'data' event is emitted whenever the stream is
19 > * relinquishing ownership of a chunk of data to a consumer.
20 > *
21 > * NOTE: PLEASE UNDERSTAND THAT ADDING A DATA LISTENER CAN
22 > * TURN THE STREAM INTO FLOWING MODE. IT IS THEREFOR THE
23 > * LAST LISTENER THAT SHOULD BE ADDED AND NOT THE FIRST
24 > *
25 > * Use `listenStream` as a helper method to listen to
26 > * stream events in the right order.
27 > */
28 > on(event: 'data', callback: (data: T) => void): void;
29 >
30 > /**
31 > * Emitted when any error occurs.
32 > */
33 > on(event: 'error', callback: (err: Error) => void): void;
34 >
35 > /**
36 > * The 'end' event is emitted when there is no more data
37 > * to be consumed from the stream. The 'end' event will
38 > * not be emitted unless the data is completely consumed.
39 > */
40 > on(event: 'end', callback: () => void): void;
41 > }
42 >
43 > /**
44 > * A interface that emulates the API shape of a node.js readable
45 > * stream for use in native and web environments.
46 > */
47 > export interface ReadableStream<T> extends ReadableStreamEvents<T> {
48 >
49 > /**
50 > * Stops emitting any events until resume() is called.
51 > */
52 > pause(): void;
53 >
54 > /**
55 > * Starts emitting events again after pause() was called.
56 > */
57 > resume(): void;
58 >
59 > /**
60 > * Destroys the stream and stops emitting any event.
61 > */
62 > destroy(): void;
63 >
64 > /**
65 > * Allows to remove a listener that was previously added.
66 > */
67 > removeListener(event: string, callback: Function): void;
68 > }
69 >
70 > /**
71 > * A interface that emulates the API shape of a node.js readable
72 > * for use in native and web environments.
73 > */
74 > export interface Readable<T> {
75 >
76 > /**
77 > * Read data from the underlying source. Will return
78 > * null to indicate that no more data can be read.
79 > */
80 > read(): T | null;
81 > }
82 >
83 > export function isReadable<T>(obj: unknown): obj is Readable<T> {
84 const candidate = obj as Readable<T> | undefined;
85 if (!candidate) {
89 return typeof candidate.read === 'function';
90 }
91 > stream.ts
92 > /**
93 > * A interface that emulates the API shape of a node.js writeable
94 > * stream for use in native and web environments.
95 > */
96 > export interface WriteableStream<T> extends ReadableStream<T> {
97 >
98 > /**
99 > * Writing data to the stream will trigger the on('data')
100 > * event listener if the stream is flowing and buffer the
101 > * data otherwise until the stream is flowing.
102 > *
103 > * If a `highWaterMark` is configured and writing to the
104 > * stream reaches this mark, a promise will be returned
105 > * that should be awaited on before writing more data.
106 > * Otherwise there is a risk of buffering a large number
107 > * of data chunks without consumer.
108 > */
109 > write(data: T): void | Promise<void>;
110 >
111 > /**
112 > * Signals an error to the consumer of the stream via the
113 > * on('error') handler if the stream is flowing.
114 > *
115 > * NOTE: call `end` to signal that the stream has ended,
116 > * this DOES NOT happen automatically from `error`.
117 > */
118 > error(error: Error): void;
119 >
120 > /**
121 > * Signals the end of the stream to the consumer. If the
122 > * result is provided, will trigger the on('data') event
123 > * listener if the stream is flowing and buffer the data
124 > * otherwise until the stream is flowing.
125 > */
126 > end(result?: T): void;
127 > }
128 >
129 > /**
130 > * A stream that has a buffer already read. Returns the original stream
131 > * that was read as well as the chunks that got read.
132 > *
133 > * The `ended` flag indicates if the stream has been fully consumed.
134 > */
135 > export interface ReadableBufferedStream<T> {
136 >
137 > /**
138 > * The original stream that is being read.
139 > */
140 > stream: ReadableStream<T>;
141 >
142 > /**
143 > * An array of chunks already read from this stream.
144 > */
145 > buffer: T[];
146 >
147 > /**
148 > * Signals if the stream has ended or not. If not, consumers
149 > * should continue to read from the stream until consumed.
150 > */
151 > ended: boolean;
152 > }
153 >
154 > export function isReadableStream<T>(obj: unknown): obj is ReadableStream<T> {
155 const candidate = obj as ReadableStream<T> | undefined;
156 if (!candidate) {
160 return [candidate.on, candidate.pause, candidate.resume, candidate.destroy].every(fn => typeof fn === 'function');
161 }
162 > stream.ts
163 > export function isReadableBufferedStream<T>(obj: unknown): obj is ReadableBufferedStream<T> {
164 const candidate = obj as ReadableBufferedStream<T> | undefined;
165 if (!candidate) {
169 return isReadableStream(candidate.stream) && Array.isArray(candidate.buffer) && typeof candidate.ended === 'boolean';
170 }
171 > stream.ts
172 > export interface IReducer<T, R = T> {
173 > (data: T[]): R;
174 > }
175 >
176 > export interface IDataTransformer<Original, Transformed> {
177 > (data: Original): Transformed;
178 > }
179 >
180 > export interface IErrorTransformer {
181 > (error: Error): Error;
182 > }
183 >
184 > export interface ITransformer<Original, Transformed> {
185 > data: IDataTransformer<Original, Transformed>;
186 > error?: IErrorTransformer;
187 > }
188 >
189 > export function newWriteableStream<T>(reducer: IReducer<T> | null, options?: WriteableStreamOptions): WriteableStream<T> {
190 return new WriteableStreamImpl<T>(reducer, options);
191 }
192 > stream.ts
193 > export interface WriteableStreamOptions {
194 >
195 > /**
196 > * The number of objects to buffer before WriteableStream#write()
197 > * signals back that the buffer is full. Can be used to reduce
198 > * the memory pressure when the stream is not flowing.
199 > */
200 > highWaterMark?: number;
201 > }
202 >
203 > class WriteableStreamImpl<T> implements WriteableStream<T> {
204 >
205 > private readonly state = {
206 > flowing: false,
207 > ended: false,
208 > destroyed: false
209 > };
210 >
211 > private readonly buffer = {
212 > data: [] as T[],
213 > error: [] as Error[]
214 > };
215 >
216 > private readonly listeners = {
217 > data: [] as { (data: T): void }[],
218 > error: [] as { (error: Error): void }[],
219 > end: [] as { (): void }[]
220 > };
221 >
222 > private readonly pendingWritePromises: Function[] = [];
223 >
224 > /**
225 > * @param reducer a function that reduces the buffered data into a single object;
226 > * because some objects can be complex and non-reducible, we also
227 > * allow passing the explicit `null` value to skip the reduce step
228 > * @param options stream options
229 > */
230 > constructor(private reducer: IReducer<T> | null, private options?: WriteableStreamOptions) { }
231 >
232 > pause(): void {
233 if (this.state.destroyed) {
234 return;
237 this.state.flowing = false;
238 }
239 > stream.ts
240 > resume(): void {
241 if (this.state.destroyed) {
242 return;
252 }
253 }
254 > stream.ts
255 > write(data: T): void | Promise<void> {
256 if (this.state.destroyed) {
257 return;
273 }
274 }
275 > stream.ts
276 > error(error: Error): void {
277 if (this.state.destroyed) {
278 return;
289 }
290 }
291 > stream.ts
292 > end(result?: T): void {
293 if (this.state.destroyed) {
294 return;
312 }
313 }
314 > stream.ts
315 > private emitData(data: T): void {
316 this.listeners.data.slice(0).forEach(listener => listener(data)); // slice to avoid listener mutation from delivering event
317 }
318 > stream.ts
319 > private emitError(error: Error): void {
320 if (this.listeners.error.length === 0) {
321 onUnexpectedError(error); // nobody listened to this error so we log it as unexpected
324 }
325 }
326 > stream.ts
327 > private emitEnd(): void {
328 this.listeners.end.slice(0).forEach(listener => listener()); // slice to avoid listener mutation from delivering event
329 }
330 > stream.ts
331 > on(event: 'data', callback: (data: T) => void): void;
332 > on(event: 'error', callback: (err: Error) => void): void;
333 > on(event: 'end', callback: () => void): void;
334 > on(event: 'data' | 'error' | 'end', callback: ((data: T) => void) | ((err: Error) => void) | (() => void)): void {
335 if (this.state.destroyed) {
336 return;
372 }
373 }
374 > stream.ts
375 > removeListener(event: string, callback: Function): void {
376 if (this.state.destroyed) {
377 return;
401 }
402 }
403 > stream.ts
404 > private flowData(): void {
405 // if buffer is empty, nothing to do
406 if (this.buffer.data.length === 0) {
428 pendingWritePromises.forEach(pendingWritePromise => pendingWritePromise());
429 }
430 > stream.ts
431 > private flowErrors(): void {
432 if (this.listeners.error.length > 0) {
433 for (const error of this.buffer.error) {
438 }
439 }
440 > stream.ts
441 > private flowEnd(): boolean {
442 if (this.state.ended) {
443 this.emitEnd();
448 return false;
449 }
450 > stream.ts
451 > destroy(): void {
452 if (!this.state.destroyed) {
453 this.state.destroyed = true;
464 }
465 }
466 > } stream.ts
467 >
468 > /**
469 > * Helper to fully read a T readable into a T.
470 > */
471 > export function consumeReadable<T>(readable: Readable<T>, reducer: IReducer<T>): T {
472 const chunks: T[] = [];
473
479 return reducer(chunks);
480 }
481 > stream.ts
482 > /**
483 > * Helper to read a T readable up to a maximum of chunks. If the limit is
484 > * reached, will return a readable instead to ensure all data can still
485 > * be read.
486 > */
487 > export function peekReadable<T>(readable: Readable<T>, reducer: IReducer<T>, maxChunks: number): T | Readable<T> {
488 const chunks: T[] = [];
489
527 };
528 }
529 > stream.ts
530 > /**
531 > * Helper to fully read a T stream into a T or consuming
532 > * a stream fully, awaiting all the events without caring
533 > * about the data.
534 > */
535 > export function consumeStream<T, R = T>(stream: ReadableStreamEvents<T>, reducer: IReducer<T, R>): Promise<R>;
536 > export function consumeStream(stream: ReadableStreamEvents<unknown>): Promise<undefined>;
537 > export function consumeStream<T, R = T>(stream: ReadableStreamEvents<T>, reducer?: IReducer<T, R>): Promise<R | undefined> {
538 return new Promise((resolve, reject) => {
539 const chunks: T[] = [];
562 });
563 }
564 > stream.ts
565 > export interface IStreamListener<T> {
566 >
567 > /**
568 > * The 'data' event is emitted whenever the stream is
569 > * relinquishing ownership of a chunk of data to a consumer.
570 > */
571 > onData(data: T): void;
572 >
573 > /**
574 > * Emitted when any error occurs.
575 > */
576 > onError(err: Error): void;
577 >
578 > /**
579 > * The 'end' event is emitted when there is no more data
580 > * to be consumed from the stream. The 'end' event will
581 > * not be emitted unless the data is completely consumed.
582 > */
583 > onEnd(): void;
584 > }
585 >
586 > /**
587 > * Helper to listen to all events of a T stream in proper order.
588 > */
589 > export function listenStream<T>(stream: ReadableStreamEvents<T>, listener: IStreamListener<T>, token?: CancellationToken): void {
590
591 stream.on('error', error => {
610 });
611 }
612 > stream.ts
613 > /**
614 > * Helper to peek up to `maxChunks` into a stream. The return type signals if
615 > * the stream has ended or not. If not, caller needs to add a `data` listener
616 > * to continue reading.
617 > */
618 > export function peekStream<T>(stream: ReadableStream<T>, maxChunks: number): Promise<ReadableBufferedStream<T>> {
619 return new Promise((resolve, reject) => {
620 const streamListeners = new DisposableStore();
666 });
667 }
668 > stream.ts
669 > /**
670 > * Helper to create a readable stream from an existing T.
671 > */
672 > export function toStream<T>(t: T, reducer: IReducer<T>): ReadableStream<T> {
673 const stream = newWriteableStream<T>(reducer);
674
677 return stream;
678 }
679 > stream.ts
680 > /**
681 > * Helper to create an empty stream
682 > */
683 > export function emptyStream(): ReadableStream<never> {
684 const stream = newWriteableStream<never>(() => { throw new Error('not supported'); });
685 stream.end();
687 return stream;
688 }
689 > stream.ts
690 > /**
691 > * Helper to convert a T into a Readable<T>.
692 > */
693 > export function toReadable<T>(t: T): Readable<T> {
694 let consumed = false;
695
706 };
707 }
708 > stream.ts
709 > /**
710 > * Helper to transform a readable stream into another stream.
711 > */
712 > export function transform<Original, Transformed>(stream: ReadableStreamEvents<Original>, transformer: ITransformer<Original, Transformed>, reducer: IReducer<Transformed>): ReadableStream<Transformed> {
713 const target = newWriteableStream<Transformed>(reducer);
714
721 return target;
722 }
723 > stream.ts
724 > /**
725 > * Helper to take an existing readable that will
726 > * have a prefix injected to the beginning.
727 > */
728 > export function prefixedReadable<T>(prefix: T, readable: Readable<T>, reducer: IReducer<T>): Readable<T> {
729 let prefixHandled = false;
730
751 };
752 }
753 > stream.ts
754 > /**
755 > * Helper to take an existing stream that will
756 > * have a prefix injected to the beginning.
757 > */
758 > export function prefixedStream<T>(prefix: T, stream: ReadableStream<T>, reducer: IReducer<T>): ReadableStream<T> {
759 let prefixHandled = false;
760
src/vs/base/common/diff/diff.ts 319 covered LOC · 38 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- diff.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 { DiffChange } from './diffChange.js';
7 > import { stringHash } from '../hash.js';
8 > import { Constants } from '../uint.js';
9 >
10 > export class StringDiffSequence implements ISequence {
11 >
12 > constructor(private source: string) { }
13 >
14 > getElements(): Int32Array | number[] | string[] {
15 const source = this.source;
16 const characters = new Int32Array(source.length);
20 return characters;
21 }
22 > } diff.ts
23 >
24 > export function stringDiff(original: string, modified: string, pretty: boolean): IDiffChange[] {
25 return new LcsDiff(new StringDiffSequence(original), new StringDiffSequence(modified)).ComputeDiff(pretty).changes;
26 }
27 > diff.ts
28 > export interface ISequence {
29 > getElements(): Int32Array | number[] | string[];
30 > getStrictElement?(index: number): string;
31 > }
32 >
33 > export interface IDiffChange {
34 > /**
35 > * The position of the first element in the original sequence which
36 > * this change affects.
37 > */
38 > originalStart: number;
39 >
40 > /**
41 > * The number of elements from the original sequence which were
42 > * affected.
43 > */
44 > originalLength: number;
45 >
46 > /**
47 > * The position of the first element in the modified sequence which
48 > * this change affects.
49 > */
50 > modifiedStart: number;
51 >
52 > /**
53 > * The number of elements from the modified sequence which were
54 > * affected (added).
55 > */
56 > modifiedLength: number;
57 > }
58 >
59 > export interface IContinueProcessingPredicate {
60 > (furthestOriginalIndex: number, matchLengthOfLongest: number): boolean;
61 > }
62 >
63 > export interface IDiffResult {
64 > quitEarly: boolean;
65 > changes: IDiffChange[];
66 > }
67 >
68 > //
69 > // The code below has been ported from a C# implementation in VS
70 > //
71 >
72 > class Debug {
73 >
74 > public static Assert(condition: boolean, message: string): void {
75 if (!condition) {
76 throw new Error(message);
77 }
78 }
79 > } diff.ts
80 >
81 > class MyArray {
82 > /**
83 > * Copies a range of elements from an Array starting at the specified source index and pastes
84 > * them to another Array starting at the specified destination index. The length and the indexes
85 > * are specified as 64-bit integers.
86 > * sourceArray:
87 > * The Array that contains the data to copy.
88 > * sourceIndex:
89 > * A 64-bit integer that represents the index in the sourceArray at which copying begins.
90 > * destinationArray:
91 > * The Array that receives the data.
92 > * destinationIndex:
93 > * A 64-bit integer that represents the index in the destinationArray at which storing begins.
94 > * length:
95 > * A 64-bit integer that represents the number of elements to copy.
96 > */
97 > public static Copy(sourceArray: unknown[], sourceIndex: number, destinationArray: unknown[], destinationIndex: number, length: number) {
98 for (let i = 0; i < length; i++) {
99 destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
100 }
101 }
102 > public static Copy2(sourceArray: Int32Array, sourceIndex: number, destinationArray: Int32Array, destinationIndex: number, length: number) { diff.ts
103 for (let i = 0; i < length; i++) {
104 destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
105 }
106 }
107 > } diff.ts
108 >
109 > //*****************************************************************************
110 > // LcsDiff.cs
111 > //
112 > // An implementation of the difference algorithm described in
113 > // "An O(ND) Difference Algorithm and its variations" by Eugene W. Myers
114 > //
115 > // Copyright (C) 2008 Microsoft Corporation @minifier_do_not_preserve
116 > //*****************************************************************************
117 >
118 > // Our total memory usage for storing history is (worst-case):
119 > // 2 * [(MaxDifferencesHistory + 1) * (MaxDifferencesHistory + 1) - 1] * sizeof(int)
120 > // 2 * [1448*1448 - 1] * 4 = 16773624 = 16MB
121 > const enum LocalConstants {
122 > MaxDifferencesHistory = 1447
123 > }
124 >
125 > /**
126 > * A utility class which helps to create the set of DiffChanges from
127 > * a difference operation. This class accepts original DiffElements and
128 > * modified DiffElements that are involved in a particular change. The
129 > * MarkNextChange() method can be called to mark the separation between
130 > * distinct changes. At the end, the Changes property can be called to retrieve
131 > * the constructed changes.
132 > */
133 > class DiffChangeHelper {
134 >
135 > private m_changes: DiffChange[];
136 > private m_originalStart: number;
137 > private m_modifiedStart: number;
138 > private m_originalCount: number;
139 > private m_modifiedCount: number;
140 >
141 > /**
142 > * Constructs a new DiffChangeHelper for the given DiffSequences.
143 > */
144 > constructor() {
145 this.m_changes = [];
146 this.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;
149 this.m_modifiedCount = 0;
150 }
151 > diff.ts
152 > /**
153 > * Marks the beginning of the next change in the set of differences.
154 > */
155 > public MarkNextChange(): void {
156 // Only add to the list if there is something to add
157 if (this.m_originalCount > 0 || this.m_modifiedCount > 0) {
167 this.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;
168 }
169 > diff.ts
170 > /**
171 > * Adds the original element at the given position to the elements
172 > * affected by the current change. The modified index gives context
173 > * to the change position with respect to the original sequence.
174 > * @param originalIndex The index of the original element to add.
175 > * @param modifiedIndex The index of the modified element that provides corresponding position in the modified sequence.
176 > */
177 > public AddOriginalElement(originalIndex: number, modifiedIndex: number) {
178 // The 'true' start index is the smallest of the ones we've seen
179 this.m_originalStart = Math.min(this.m_originalStart, originalIndex);
182 this.m_originalCount++;
183 }
184 > diff.ts
185 > /**
186 > * Adds the modified element at the given position to the elements
187 > * affected by the current change. The original index gives context
188 > * to the change position with respect to the modified sequence.
189 > * @param originalIndex The index of the original element that provides corresponding position in the original sequence.
190 > * @param modifiedIndex The index of the modified element to add.
191 > */
192 > public AddModifiedElement(originalIndex: number, modifiedIndex: number): void {
193 // The 'true' start index is the smallest of the ones we've seen
194 this.m_originalStart = Math.min(this.m_originalStart, originalIndex);
197 this.m_modifiedCount++;
198 }
199 > diff.ts
200 > /**
201 > * Retrieves all of the changes marked by the class.
202 > */
203 > public getChanges(): DiffChange[] {
204 if (this.m_originalCount > 0 || this.m_modifiedCount > 0) {
205 // Finish up on whatever is left
209 return this.m_changes;
210 }
211 > diff.ts
212 > /**
213 > * Retrieves all of the changes marked by the class in the reverse order
214 > */
215 > public getReverseChanges(): DiffChange[] {
216 if (this.m_originalCount > 0 || this.m_modifiedCount > 0) {
217 // Finish up on whatever is left
222 return this.m_changes;
223 }
224 > diff.ts
225 > }
226 >
227 > /**
228 > * An implementation of the difference algorithm described in
229 > * "An O(ND) Difference Algorithm and its variations" by Eugene W. Myers
230 > */
231 > export class LcsDiff {
232 >
233 > private readonly ContinueProcessingPredicate: IContinueProcessingPredicate | null;
234 >
235 > private readonly _originalSequence: ISequence;
236 > private readonly _modifiedSequence: ISequence;
237 > private readonly _hasStrings: boolean;
238 > private readonly _originalStringElements: string[];
239 > private readonly _originalElementsOrHash: Int32Array;
240 > private readonly _modifiedStringElements: string[];
241 > private readonly _modifiedElementsOrHash: Int32Array;
242 >
243 > private m_forwardHistory: Int32Array[];
244 > private m_reverseHistory: Int32Array[];
245 >
246 > /**
247 > * Constructs the DiffFinder
248 > */
249 > constructor(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) {
250 this.ContinueProcessingPredicate = continueProcessingPredicate;
251
265 this.m_reverseHistory = [];
266 }
267 > diff.ts
268 > private static _isStringArray(arr: Int32Array | number[] | string[]): arr is string[] {
269 return (arr.length > 0 && typeof arr[0] === 'string');
270 }
271 > diff.ts
272 > private static _getElements(sequence: ISequence): [string[], Int32Array, boolean] {
273 const elements = sequence.getElements();
274
287 return [[], new Int32Array(elements), false];
288 }
289 > diff.ts
290 > private ElementsAreEqual(originalIndex: number, newIndex: number): boolean {
291 if (this._originalElementsOrHash[originalIndex] !== this._modifiedElementsOrHash[newIndex]) {
292 return false;
294 return (this._hasStrings ? this._originalStringElements[originalIndex] === this._modifiedStringElements[newIndex] : true);
295 }
296 > diff.ts
297 > private ElementsAreStrictEqual(originalIndex: number, newIndex: number): boolean {
298 if (!this.ElementsAreEqual(originalIndex, newIndex)) {
299 return false;
303 return (originalElement === modifiedElement);
304 }
305 > diff.ts
306 > private static _getStrictElement(sequence: ISequence, index: number): string | null {
307 if (typeof sequence.getStrictElement === 'function') {
308 return sequence.getStrictElement(index);
310 return null;
311 }
312 > diff.ts
313 > private OriginalElementsAreEqual(index1: number, index2: number): boolean {
314 if (this._originalElementsOrHash[index1] !== this._originalElementsOrHash[index2]) {
315 return false;
317 return (this._hasStrings ? this._originalStringElements[index1] === this._originalStringElements[index2] : true);
318 }
319 > diff.ts
320 > private ModifiedElementsAreEqual(index1: number, index2: number): boolean {
321 if (this._modifiedElementsOrHash[index1] !== this._modifiedElementsOrHash[index2]) {
322 return false;
324 return (this._hasStrings ? this._modifiedStringElements[index1] === this._modifiedStringElements[index2] : true);
325 }
326 > diff.ts
327 > public ComputeDiff(pretty: boolean): IDiffResult {
328 return this._ComputeDiff(0, this._originalElementsOrHash.length - 1, 0, this._modifiedElementsOrHash.length - 1, pretty);
329 }
330 > diff.ts
331 > /**
332 > * Computes the differences between the original and modified input
333 > * sequences on the bounded range.
334 > * @returns An array of the differences between the two input sequences.
335 > */
336 > private _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): IDiffResult {
337 const quitEarlyArr = [false];
338 let changes = this.ComputeDiffRecursive(originalStart, originalEnd, modifiedStart, modifiedEnd, quitEarlyArr);
350 };
351 }
352 > diff.ts
353 > /**
354 > * Private helper method which computes the differences on the bounded range
355 > * recursively.
356 > * @returns An array of the differences between the two input sequences.
357 > */
358 > private ComputeDiffRecursive(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, quitEarlyArr: boolean[]): DiffChange[] {
359 quitEarlyArr[0] = false;
360
439 ];
440 }
441 > diff.ts
442 > private WALKTRACE(diagonalForwardBase: number, diagonalForwardStart: number, diagonalForwardEnd: number, diagonalForwardOffset: number,
443 diagonalReverseBase: number, diagonalReverseStart: number, diagonalReverseEnd: number, diagonalReverseOffset: number,
444 forwardPoints: Int32Array, reversePoints: Int32Array,
565 return this.ConcatenateChanges(forwardChanges, reverseChanges);
566 }
567 > diff.ts
568 > /**
569 > * Given the range to compute the diff on, this method finds the point:
570 > * (midOriginal, midModified)
571 > * that exists in the middle of the LCS of the two sequences and
572 > * is the point at which the LCS problem may be broken down recursively.
573 > * This method will try to keep the LCS trace in memory. If the LCS recursion
574 > * point is calculated and the full trace is available in memory, then this method
575 > * will return the change list.
576 > * @param originalStart The start bound of the original sequence range
577 > * @param originalEnd The end bound of the original sequence range
578 > * @param modifiedStart The start bound of the modified sequence range
579 > * @param modifiedEnd The end bound of the modified sequence range
580 > * @param midOriginal The middle point of the original sequence range
581 > * @param midModified The middle point of the modified sequence range
582 > * @returns The diff changes, if available, otherwise null
583 > */
584 > private ComputeRecursionPoint(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, midOriginalArr: number[], midModifiedArr: number[], quitEarlyArr: boolean[]) {
585 let originalIndex = 0, modifiedIndex = 0;
586 let diagonalForwardStart = 0, diagonalForwardEnd = 0;
817 );
818 }
819 > diff.ts
820 > /**
821 > * Shifts the given changes to provide a more intuitive diff.
822 > * While the first element in a diff matches the first element after the diff,
823 > * we shift the diff down.
824 > *
825 > * @param changes The list of changes to shift
826 > * @returns The shifted changes
827 > */
828 > private PrettifyChanges(changes: DiffChange[]): DiffChange[] {
829
830 // Shift all the changes down first
957 return changes;
958 }
959 > diff.ts
960 > private _findBetterContiguousSequence(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number, desiredLength: number): [number, number] | null {
961 if (originalLength < desiredLength || modifiedLength < desiredLength) {
962 return null;
982 return null;
983 }
984 > diff.ts
985 > private _contiguousSequenceScore(originalStart: number, modifiedStart: number, length: number): number {
986 let score = 0;
987 for (let l = 0; l < length; l++) {
993 return score;
994 }
995 > diff.ts
996 > private _OriginalIsBoundary(index: number): boolean {
997 if (index <= 0 || index >= this._originalElementsOrHash.length - 1) {
998 return true;
1000 return (this._hasStrings && /^\s*$/.test(this._originalStringElements[index]));
1001 }
1002 > diff.ts
1003 > private _OriginalRegionIsBoundary(originalStart: number, originalLength: number): boolean {
1004 if (this._OriginalIsBoundary(originalStart) || this._OriginalIsBoundary(originalStart - 1)) {
1005 return true;
1013 return false;
1014 }
1015 > diff.ts
1016 > private _ModifiedIsBoundary(index: number): boolean {
1017 if (index <= 0 || index >= this._modifiedElementsOrHash.length - 1) {
1018 return true;
1020 return (this._hasStrings && /^\s*$/.test(this._modifiedStringElements[index]));
1021 }
1022 > diff.ts
1023 > private _ModifiedRegionIsBoundary(modifiedStart: number, modifiedLength: number): boolean {
1024 if (this._ModifiedIsBoundary(modifiedStart) || this._ModifiedIsBoundary(modifiedStart - 1)) {
1025 return true;
1033 return false;
1034 }
1035 > diff.ts
1036 > private _boundaryScore(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number): number {
1037 const originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0);
1038 const modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0);
1039 return (originalScore + modifiedScore);
1040 }
1041 > diff.ts
1042 > /**
1043 > * Concatenates the two input DiffChange lists and returns the resulting
1044 > * list.
1045 > * @param The left changes
1046 > * @param The right changes
1047 > * @returns The concatenated list
1048 > */
1049 > private ConcatenateChanges(left: DiffChange[], right: DiffChange[]): DiffChange[] {
1050 const mergedChangeArr: DiffChange[] = [];
1051
1071 }
1072 }
1073 > diff.ts
1074 > /**
1075 > * Returns true if the two changes overlap and can be merged into a single
1076 > * change
1077 > * @param left The left change
1078 > * @param right The right change
1079 > * @param mergedChange The merged change if the two overlap, null otherwise
1080 > * @returns True if the two changes overlap
1081 > */
1082 > private ChangesOverlap(left: DiffChange, right: DiffChange, mergedChangeArr: Array<DiffChange | null>): boolean {
1083 Debug.Assert(left.originalStart <= right.originalStart, 'Left change is not less than or equal to right change');
1084 Debug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change');
1104 }
1105 }
1106 > diff.ts
1107 > /**
1108 > * Helper method used to clip a diagonal index to the range of valid
1109 > * diagonals. This also decides whether or not the diagonal index,
1110 > * if it exceeds the boundary, should be clipped to the boundary or clipped
1111 > * one inside the boundary depending on the Even/Odd status of the boundary
1112 > * and numDifferences.
1113 > * @param diagonal The index of the diagonal to clip.
1114 > * @param numDifferences The current number of differences being iterated upon.
1115 > * @param diagonalBaseIndex The base reference diagonal.
1116 > * @param numDiagonals The total number of diagonals.
1117 > * @returns The clipped diagonal index.
1118 > */
1119 > private ClipDiagonalBound(diagonal: number, numDifferences: number, diagonalBaseIndex: number, numDiagonals: number): number {
1120 if (diagonal >= 0 && diagonal < numDiagonals) {
1121 // Nothing to clip, its in range
1137 }
1138 }
1139 > } diff.ts
1140 >
1141 >
1142 > /**
1143 > * Precomputed equality array for character codes.
1144 > */
1145 > const precomputedEqualityArray = new Uint32Array(0x10000);
1146 >
1147 > /**
1148 > * Computes the Levenshtein distance for strings of length <= 32.
1149 > * @param firstString - The first string.
1150 > * @param secondString - The second string.
1151 > * @returns The Levenshtein distance.
1152 > */
1153 > const computeLevenshteinDistanceForShortStrings = (firstString: string, secondString: string): number => {
1154 const firstStringLength = firstString.length;
1155 const secondStringLength = secondString.length;
1191 return distance;
1192 };
1193 > diff.ts
1194 > /**
1195 > * Computes the Levenshtein distance for strings of length > 32.
1196 > * @param firstString - The first string.
1197 > * @param secondString - The second string.
1198 > * @returns The Levenshtein distance.
1199 > */
1200 function computeLevenshteinDistanceForLongStrings(firstString: string, secondString: string): number {
1201 const firstStringLength = firstString.length;
1293 return distance;
1294 }
1295 > diff.ts
1296 > /**
1297 > * Computes the Levenshtein distance between two strings.
1298 > * @param firstString - The first string.
1299 > * @param secondString - The second string.
1300 > * @returns The Levenshtein distance.
1301 > */
1302 > export function computeLevenshteinDistance(firstString: string, secondString: string): number {
1303 if (firstString.length < secondString.length) {
1304 const temp = secondString;
src/vs/base/common/color.ts 308 covered LOC · 55 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- color.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 >
8 > function roundFloat(number: number, decimalPoints: number): number {
9 > const decimal = Math.pow(10, decimalPoints);
10 > return Math.round(number * decimal) / decimal;
11 > }
12 >
13 > export class RGBA {
14 > _rgbaBrand: void = undefined;
15 >
16 > /**
17 > * Red: integer in [0-255]
18 > */
19 > readonly r: number;
20 >
21 > /**
22 > * Green: integer in [0-255]
23 > */
24 > readonly g: number;
25 >
26 > /**
27 > * Blue: integer in [0-255]
28 > */
29 > readonly b: number;
30 >
31 > /**
32 > * Alpha: float in [0-1]
33 > */
34 > readonly a: number;
35 >
36 > constructor(r: number, g: number, b: number, a: number = 1) {
37 > this.r = Math.min(255, Math.max(0, r)) | 0;
38 > this.g = Math.min(255, Math.max(0, g)) | 0;
39 > this.b = Math.min(255, Math.max(0, b)) | 0;
40 > this.a = roundFloat(Math.max(Math.min(1, a), 0), 3);
41 > }
42 >
43 > static equals(a: RGBA, b: RGBA): boolean {
44 return a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a;
45 }
46 > } color.ts
47 >
48 > export class HSLA {
49 >
50 > _hslaBrand: void = undefined;
51 >
52 > /**
53 > * Hue: integer in [0, 360]
54 > */
55 > readonly h: number;
56 >
57 > /**
58 > * Saturation: float in [0, 1]
59 > */
60 > readonly s: number;
61 >
62 > /**
63 > * Luminosity: float in [0, 1]
64 > */
65 > readonly l: number;
66 >
67 > /**
68 > * Alpha: float in [0, 1]
69 > */
70 > readonly a: number;
71 >
72 > constructor(h: number, s: number, l: number, a: number) {
73 this.h = Math.max(Math.min(360, h), 0) | 0;
74 this.s = roundFloat(Math.max(Math.min(1, s), 0), 3);
76 this.a = roundFloat(Math.max(Math.min(1, a), 0), 3);
77 }
78 > color.ts
79 > static equals(a: HSLA, b: HSLA): boolean {
80 return a.h === b.h && a.s === b.s && a.l === b.l && a.a === b.a;
81 }
82 > color.ts
83 > /**
84 > * Converts an RGB color value to HSL. Conversion formula
85 > * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
86 > * Assumes r, g, and b are contained in the set [0, 255] and
87 > * returns h in the set [0, 360], s, and l in the set [0, 1].
88 > */
89 > static fromRGBA(rgba: RGBA): HSLA {
90 const r = rgba.r / 255;
91 const g = rgba.g / 255;
114 return new HSLA(h, s, l, a);
115 }
116 > color.ts
117 > private static _hue2rgb(p: number, q: number, t: number): number {
118 if (t < 0) {
119 t += 1;
133 return p;
134 }
135 > color.ts
136 > /**
137 > * Converts an HSL color value to RGB. Conversion formula
138 > * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
139 > * Assumes h in the set [0, 360] s, and l are contained in the set [0, 1] and
140 > * returns r, g, and b in the set [0, 255].
141 > */
142 > static toRGBA(hsla: HSLA): RGBA {
143 const h = hsla.h / 360;
144 const { s, l, a } = hsla;
157 return new RGBA(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a);
158 }
159 > } color.ts
160 >
161 > export class HSVA {
162 >
163 > _hsvaBrand: void = undefined;
164 >
165 > /**
166 > * Hue: integer in [0, 360]
167 > */
168 > readonly h: number;
169 >
170 > /**
171 > * Saturation: float in [0, 1]
172 > */
173 > readonly s: number;
174 >
175 > /**
176 > * Value: float in [0, 1]
177 > */
178 > readonly v: number;
179 >
180 > /**
181 > * Alpha: float in [0, 1]
182 > */
183 > readonly a: number;
184 >
185 > constructor(h: number, s: number, v: number, a: number) {
186 this.h = Math.max(Math.min(360, h), 0) | 0;
187 this.s = roundFloat(Math.max(Math.min(1, s), 0), 3);
189 this.a = roundFloat(Math.max(Math.min(1, a), 0), 3);
190 }
191 > color.ts
192 > static equals(a: HSVA, b: HSVA): boolean {
193 return a.h === b.h && a.s === b.s && a.v === b.v && a.a === b.a;
194 }
195 > color.ts
196 > // from http://www.rapidtables.com/convert/color/rgb-to-hsv.htm
197 > static fromRGBA(rgba: RGBA): HSVA {
198 const r = rgba.r / 255;
199 const g = rgba.g / 255;
217 return new HSVA(Math.round(m * 60), s, cmax, rgba.a);
218 }
219 > color.ts
220 > // from http://www.rapidtables.com/convert/color/hsv-to-rgb.htm
221 > static toRGBA(hsva: HSVA): RGBA {
222 const { h, s, v, a } = hsva;
223 const c = v * s;
252 return new RGBA(r, g, b, a);
253 }
254 > } color.ts
255 >
256 > export class Color {
257 >
258 > static fromHex(hex: string): Color {
259 return Color.Format.CSS.parseHex(hex) || Color.red;
260 }
261 > color.ts
262 > static equals(a: Color | null, b: Color | null): boolean {
263 if (!a && !b) {
264 return true;
269 return a.equals(b);
270 }
271 > color.ts
272 > readonly rgba: RGBA;
273 > private _hsla?: HSLA;
274 > get hsla(): HSLA {
275 if (this._hsla) {
276 return this._hsla;
279 }
280 }
281 > color.ts
282 > private _hsva?: HSVA;
283 > get hsva(): HSVA {
284 if (this._hsva) {
285 return this._hsva;
287 return HSVA.fromRGBA(this.rgba);
288 }
289 > color.ts
290 > constructor(arg: RGBA | HSLA | HSVA) {
291 > if (!arg) {
292 throw new Error('Color needs a value');
293 > } else if (arg instanceof RGBA) { color.ts
294 > this.rgba = arg;
295 > } else if (arg instanceof HSLA) {
296 this._hsla = arg;
297 this.rgba = HSLA.toRGBA(arg);
302 throw new Error('Invalid color ctor argument');
303 }
304 > } color.ts
305 >
306 > equals(other: Color | null): boolean {
307 return !!other && RGBA.equals(this.rgba, other.rgba) && HSLA.equals(this.hsla, other.hsla) && HSVA.equals(this.hsva, other.hsva);
308 }
309 > color.ts
310 > /**
311 > * http://www.w3.org/TR/WCAG20/#relativeluminancedef
312 > * Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white.
313 > */
314 > getRelativeLuminance(): number {
315 const R = Color._relativeLuminanceForComponent(this.rgba.r);
316 const G = Color._relativeLuminanceForComponent(this.rgba.g);
320 return roundFloat(luminance, 4);
321 }
322 > color.ts
323 > /**
324 > * Reduces the "foreground" color on this "background" color unti it is
325 > * below the relative luminace ratio.
326 > * @returns the new foreground color
327 > * @see https://github.com/xtermjs/xterm.js/blob/44f9fa39ae03e2ca6d28354d88a399608686770e/src/common/Color.ts#L315
328 > */
329 > reduceRelativeLuminace(foreground: Color, ratio: number): Color {
330 // This is a naive but fast approach to reducing luminance as converting to
331 // HSL and back is expensive
343 return new Color(new RGBA(fgR, fgG, fgB));
344 }
345 > color.ts
346 > /**
347 > * Increases the "foreground" color on this "background" color unti it is
348 > * below the relative luminace ratio.
349 > * @returns the new foreground color
350 > * @see https://github.com/xtermjs/xterm.js/blob/44f9fa39ae03e2ca6d28354d88a399608686770e/src/common/Color.ts#L335
351 > */
352 > increaseRelativeLuminace(foreground: Color, ratio: number): Color {
353 // This is a naive but fast approach to reducing luminance as converting to
354 // HSL and back is expensive
364 return new Color(new RGBA(fgR, fgG, fgB));
365 }
366 > color.ts
367 > private static _relativeLuminanceForComponent(color: number): number {
368 const c = color / 255;
369 return (c <= 0.03928) ? c / 12.92 : Math.pow(((c + 0.055) / 1.055), 2.4);
370 }
371 > color.ts
372 > /**
373 > * http://www.w3.org/TR/WCAG20/#contrast-ratiodef
374 > * Returns the contrast ration number in the set [1, 21].
375 > */
376 > getContrastRatio(another: Color): number {
377 const lum1 = this.getRelativeLuminance();
378 const lum2 = another.getRelativeLuminance();
379 return lum1 > lum2 ? (lum1 + 0.05) / (lum2 + 0.05) : (lum2 + 0.05) / (lum1 + 0.05);
380 }
381 > color.ts
382 > /**
383 > * http://24ways.org/2010/calculating-color-contrast
384 > * Return 'true' if darker color otherwise 'false'
385 > */
386 > isDarker(): boolean {
387 const yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;
388 return yiq < 128;
389 }
390 > color.ts
391 > /**
392 > * http://24ways.org/2010/calculating-color-contrast
393 > * Return 'true' if lighter color otherwise 'false'
394 > */
395 > isLighter(): boolean {
396 const yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;
397 return yiq >= 128;
398 }
399 > color.ts
400 > isLighterThan(another: Color): boolean {
401 const lum1 = this.getRelativeLuminance();
402 const lum2 = another.getRelativeLuminance();
403 return lum1 > lum2;
404 }
405 > color.ts
406 > isDarkerThan(another: Color): boolean {
407 const lum1 = this.getRelativeLuminance();
408 const lum2 = another.getRelativeLuminance();
409 return lum1 < lum2;
410 }
411 > color.ts
412 > /**
413 > * Based on xterm.js: https://github.com/xtermjs/xterm.js/blob/44f9fa39ae03e2ca6d28354d88a399608686770e/src/common/Color.ts#L288
414 > *
415 > * Given a foreground color and a background color, either increase or reduce the luminance of the
416 > * foreground color until the specified contrast ratio is met. If pure white or black is hit
417 > * without the contrast ratio being met, go the other direction using the background color as the
418 > * foreground color and take either the first or second result depending on which has the higher
419 > * contrast ratio.
420 > *
421 > * @param foreground The foreground color.
422 > * @param ratio The contrast ratio to achieve.
423 > * @returns The adjusted foreground color.
424 > */
425 > ensureConstrast(foreground: Color, ratio: number): Color {
426 const bgL = this.getRelativeLuminance();
427 const fgL = foreground.getRelativeLuminance();
450 return foreground;
451 }
452 > color.ts
453 > lighten(factor: number): Color {
454 return new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l + this.hsla.l * factor, this.hsla.a));
455 }
456 > color.ts
457 > darken(factor: number): Color {
458 return new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l - this.hsla.l * factor, this.hsla.a));
459 }
460 > color.ts
461 > transparent(factor: number): Color {
462 const { r, g, b, a } = this.rgba;
463 return new Color(new RGBA(r, g, b, a * factor));
464 }
465 > color.ts
466 > isTransparent(): boolean {
467 return this.rgba.a === 0;
468 }
469 > color.ts
470 > isOpaque(): boolean {
471 return this.rgba.a === 1;
472 }
473 > color.ts
474 > opposite(): Color {
475 return new Color(new RGBA(255 - this.rgba.r, 255 - this.rgba.g, 255 - this.rgba.b, this.rgba.a));
476 }
477 > color.ts
478 > blend(c: Color): Color {
479 const rgba = c.rgba;
480
494 return new Color(new RGBA(r, g, b, a));
495 }
496 > color.ts
497 > /**
498 > * Mixes the current color with the provided color based on the given factor.
499 > * @param color The color to mix with
500 > * @param factor The factor of mixing (0 means this color, 1 means the input color, 0.5 means equal mix)
501 > * @returns A new color representing the mix
502 > */
503 > mix(color: Color, factor: number = 0.5): Color {
504 const normalize = Math.min(Math.max(factor, 0), 1);
505 const thisRGBA = this.rgba;
513 return new Color(new RGBA(r, g, b, a));
514 }
515 > color.ts
516 > makeOpaque(opaqueBackground: Color): Color {
517 if (this.isOpaque() || opaqueBackground.rgba.a !== 1) {
518 // only allow to blend onto a non-opaque color onto a opaque color
530 ));
531 }
532 > color.ts
533 > flatten(...backgrounds: Color[]): Color {
534 const background = backgrounds.reduceRight((accumulator, color) => {
535 return Color._flatten(color, accumulator);
537 return Color._flatten(this, background);
538 }
539 > color.ts
540 > private static _flatten(foreground: Color, background: Color) {
541 const backgroundAlpha = 1 - foreground.rgba.a;
542 return new Color(new RGBA(
546 ));
547 }
548 > color.ts
549 > private _toString?: string;
550 > toString(): string {
551 if (!this._toString) {
552 this._toString = Color.Format.CSS.format(this);
554 return this._toString;
555 }
556 > color.ts
557 > private _toNumber32Bit?: number;
558 > toNumber32Bit(): number {
559 if (!this._toNumber32Bit) {
560 this._toNumber32Bit = (
567 return this._toNumber32Bit;
568 }
569 > color.ts
570 > static getLighterColor(of: Color, relative: Color, factor?: number): Color {
571 if (of.isLighterThan(relative)) {
572 return of;
578 return of.lighten(factor);
579 }
580 > color.ts
581 > static getDarkerColor(of: Color, relative: Color, factor?: number): Color {
582 if (of.isDarkerThan(relative)) {
583 return of;
589 return of.darken(factor);
590 }
591 > color.ts
592 > static readonly white = new Color(new RGBA(255, 255, 255, 1));
593 > static readonly black = new Color(new RGBA(0, 0, 0, 1));
594 > static readonly red = new Color(new RGBA(255, 0, 0, 1));
595 > static readonly blue = new Color(new RGBA(0, 0, 255, 1));
596 > static readonly green = new Color(new RGBA(0, 255, 0, 1));
597 > static readonly cyan = new Color(new RGBA(0, 255, 255, 1));
598 > static readonly lightgrey = new Color(new RGBA(211, 211, 211, 1));
599 > static readonly transparent = new Color(new RGBA(0, 0, 0, 0));
600 > }
601 >
602 > export namespace Color {
603 > export namespace Format {
604 > export namespace CSS {
605 >
606 > export function formatRGB(color: Color): string {
607 if (color.rgba.a === 1) {
608 return `rgb(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b})`;
611 return Color.Format.CSS.formatRGBA(color);
612 }
613 > color.ts
614 > export function formatRGBA(color: Color): string {
615 return `rgba(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b}, ${+(color.rgba.a).toFixed(2)})`;
616 }
617 > color.ts
618 > export function formatHSL(color: Color): string {
619 if (color.hsla.a === 1) {
620 return `hsl(${color.hsla.h}, ${Math.round(color.hsla.s * 100)}%, ${Math.round(color.hsla.l * 100)}%)`;
623 return Color.Format.CSS.formatHSLA(color);
624 }
625 > color.ts
626 > export function formatHSLA(color: Color): string {
627 return `hsla(${color.hsla.h}, ${Math.round(color.hsla.s * 100)}%, ${Math.round(color.hsla.l * 100)}%, ${color.hsla.a.toFixed(2)})`;
628 }
629 > color.ts
630 > function _toTwoDigitHex(n: number): string {
631 const r = n.toString(16);
632 return r.length !== 2 ? '0' + r : r;
633 }
634 > color.ts
635 > /**
636 > * Formats the color as #RRGGBB
637 > */
638 > export function formatHex(color: Color): string {
639 return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}`;
640 }
641 > color.ts
642 > /**
643 > * Formats the color as #RRGGBBAA
644 > * If 'compact' is set, colors without transparancy will be printed as #RRGGBB
645 > */
646 > export function formatHexA(color: Color, compact = false): string {
647 if (compact && color.rgba.a === 1) {
648 return Color.Format.CSS.formatHex(color);
651 return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}${_toTwoDigitHex(Math.round(color.rgba.a * 255))}`;
652 }
653 > color.ts
654 > /**
655 > * The default format will use HEX if opaque and RGBA otherwise.
656 > */
657 > export function format(color: Color): string {
658 if (color.isOpaque()) {
659 return Color.Format.CSS.formatHex(color);
662 return Color.Format.CSS.formatRGBA(color);
663 }
664 > color.ts
665 > /**
666 > * Parse a CSS color and return a {@link Color}.
667 > * @param css The CSS color to parse.
668 > * @see https://drafts.csswg.org/css-color/#typedef-color
669 > */
670 > export function parse(css: string): Color | null {
671 if (css === 'transparent') {
672 return Color.transparent;
699 return parseNamedKeyword(css);
700 }
701 > color.ts
702 > function parseNamedKeyword(css: string): Color | null {
703 // https://drafts.csswg.org/css-color/#named-colors
704 switch (css) {
854 }
855 }
856 > color.ts
857 > /**
858 > * Converts an Hex color value to a Color.
859 > * returns r, g, and b are contained in the set [0, 255]
860 > * @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA).
861 > */
862 > export function parseHex(hex: string): Color | null {
863 const length = hex.length;
864
910 return null;
911 }
912 > color.ts
913 > function _parseHexDigit(charCode: CharCode): number {
914 switch (charCode) {
915 case CharCode.Digit0: return 0;
938 return 0;
939 }
940 > } color.ts
941 > }
942 > }
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/types.ts 286 covered LOC · 25 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
35 // are subclasses of any put not positvely matched by the function. Hence type
41 && !(obj instanceof Date);
42 }
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/editor/common/core/range.ts 272 covered LOC · 53 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- range.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 { IPosition, Position } from './position.js';
7 >
8 > /**
9 > * A range in the editor. This interface is suitable for serialization.
10 > */
11 > export interface IRange {
12 > /**
13 > * Line number on which the range starts (starts at 1).
14 > */
15 > readonly startLineNumber: number;
16 > /**
17 > * Column on which the range starts in line `startLineNumber` (starts at 1).
18 > */
19 > readonly startColumn: number;
20 > /**
21 > * Line number on which the range ends.
22 > */
23 > readonly endLineNumber: number;
24 > /**
25 > * Column on which the range ends in line `endLineNumber`.
26 > */
27 > readonly endColumn: number;
28 > }
29 >
30 > /**
31 > * A range in the editor. (startLineNumber,startColumn) is <= (endLineNumber,endColumn)
32 > */
33 > export class Range {
34 >
35 > /**
36 > * Line number on which the range starts (starts at 1).
37 > */
38 > public readonly startLineNumber: number;
39 > /**
40 > * Column on which the range starts in line `startLineNumber` (starts at 1).
41 > */
42 > public readonly startColumn: number;
43 > /**
44 > * Line number on which the range ends.
45 > */
46 > public readonly endLineNumber: number;
47 > /**
48 > * Column on which the range ends in line `endLineNumber`.
49 > */
50 > public readonly endColumn: number;
51 >
52 > constructor(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number) {
53 > if ((startLineNumber > endLineNumber) || (startLineNumber === endLineNumber && startColumn > endColumn)) { range.ts
54 this.startLineNumber = endLineNumber;
55 this.startColumn = endColumn;
56 this.endLineNumber = startLineNumber;
57 this.endColumn = startColumn;
58 > } else { range.ts
59 > this.startLineNumber = startLineNumber; range.ts
60 > this.startColumn = startColumn;
61 > this.endLineNumber = endLineNumber;
62 > this.endColumn = endColumn;
63 > }
64 > } range.ts
65 > range.ts
66 > /**
67 > * Test if this range is empty.
68 > */
69 > public isEmpty(): boolean {
70 return Range.isEmpty(this);
71 }
72 > range.ts
73 > /**
74 > * Test if `range` is empty.
75 > */
76 > public static isEmpty(range: IRange): boolean {
77 > return (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn); range.ts
78 > }
79 > range.ts
80 > /**
81 > * Test if position is in this range. If the position is at the edges, will return true.
82 > */
83 > public containsPosition(position: IPosition): boolean {
84 return Range.containsPosition(this, position);
85 }
86 > range.ts
87 > /**
88 > * Test if `position` is in `range`. If the position is at the edges, will return true.
89 > */
90 > public static containsPosition(range: IRange, position: IPosition): boolean {
91 if (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) {
92 return false;
100 return true;
101 }
102 > range.ts
103 > /**
104 > * Test if `position` is in `range`. If the position is at the edges, will return false.
105 > * @internal
106 > */
107 > public static strictContainsPosition(range: IRange, position: IPosition): boolean {
108 if (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) {
109 return false;
117 return true;
118 }
119 > range.ts
120 > /**
121 > * Test if range is in this range. If the range is equal to this range, will return true.
122 > */
123 > public containsRange(range: IRange): boolean {
124 return Range.containsRange(this, range);
125 }
126 > range.ts
127 > /**
128 > * Test if `otherRange` is in `range`. If the ranges are equal, will return true.
129 > */
130 > public static containsRange(range: IRange, otherRange: IRange): boolean {
131 if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) {
132 return false;
143 return true;
144 }
145 > range.ts
146 > /**
147 > * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true.
148 > */
149 > public strictContainsRange(range: IRange): boolean {
150 return Range.strictContainsRange(this, range);
151 }
152 > range.ts
153 > /**
154 > * Test if `otherRange` is strictly in `range` (must start after, and end before). If the ranges are equal, will return false.
155 > */
156 > public static strictContainsRange(range: IRange, otherRange: IRange): boolean {
157 if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) {
158 return false;
169 return true;
170 }
171 > range.ts
172 > /**
173 > * A reunion of the two ranges.
174 > * The smallest position will be used as the start point, and the largest one as the end point.
175 > */
176 > public plusRange(range: IRange): Range {
177 return Range.plusRange(this, range);
178 }
179 > range.ts
180 > /**
181 > * A reunion of the two ranges.
182 > * The smallest position will be used as the start point, and the largest one as the end point.
183 > */
184 > public static plusRange(a: IRange, b: IRange): Range {
185 let startLineNumber: number;
186 let startColumn: number;
212 return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
213 }
214 > range.ts
215 > /**
216 > * A intersection of the two ranges.
217 > */
218 > public intersectRanges(range: IRange): Range | null {
219 return Range.intersectRanges(this, range);
220 }
221 > range.ts
222 > /**
223 > * A intersection of the two ranges.
224 > */
225 > public static intersectRanges(a: IRange, b: IRange): Range | null {
226 let resultStartLineNumber = a.startLineNumber;
227 let resultStartColumn = a.startColumn;
256 return new Range(resultStartLineNumber, resultStartColumn, resultEndLineNumber, resultEndColumn);
257 }
258 > range.ts
259 > /**
260 > * Test if this range equals other.
261 > */
262 > public equalsRange(other: IRange | null | undefined): boolean {
263 return Range.equalsRange(this, other);
264 }
265 > range.ts
266 > /**
267 > * Test if range `a` equals `b`.
268 > */
269 > public static equalsRange(a: IRange | null | undefined, b: IRange | null | undefined): boolean {
270 if (!a && !b) {
271 return true;
280 );
281 }
282 > range.ts
283 > /**
284 > * Return the end position (which will be after or equal to the start position)
285 > */
286 > public getEndPosition(): Position {
287 > return Range.getEndPosition(this); range.ts
288 > }
289 > range.ts
290 > /**
291 > * Return the end position (which will be after or equal to the start position)
292 > */
293 > public static getEndPosition(range: IRange): Position {
294 > return new Position(range.endLineNumber, range.endColumn); range.ts
295 > }
296 > range.ts
297 > /**
298 > * Return the start position (which will be before or equal to the end position)
299 > */
300 > public getStartPosition(): Position {
301 > return Range.getStartPosition(this); range.ts
302 > }
303 > range.ts
304 > /**
305 > * Return the start position (which will be before or equal to the end position)
306 > */
307 > public static getStartPosition(range: IRange): Position {
308 > return new Position(range.startLineNumber, range.startColumn); range.ts
309 > }
310 > range.ts
311 > /**
312 > * Transform to a user presentable string representation.
313 > */
314 > public toString(): string {
315 > return '[' + this.startLineNumber + ',' + this.startColumn + ' -> ' + this.endLineNumber + ',' + this.endColumn + ']'; range.ts
316 > }
317 > range.ts
318 > /**
319 > * Create a new range using this range's start position, and using endLineNumber and endColumn as the end position.
320 > */
321 > public setEndPosition(endLineNumber: number, endColumn: number): Range {
322 return new Range(this.startLineNumber, this.startColumn, endLineNumber, endColumn);
323 }
324 > range.ts
325 > /**
326 > * Create a new range using this range's end position, and using startLineNumber and startColumn as the start position.
327 > */
328 > public setStartPosition(startLineNumber: number, startColumn: number): Range {
329 return new Range(startLineNumber, startColumn, this.endLineNumber, this.endColumn);
330 }
331 > range.ts
332 > /**
333 > * Create a new empty range using this range's start position.
334 > */
335 > public collapseToStart(): Range {
336 return Range.collapseToStart(this);
337 }
338 > range.ts
339 > /**
340 > * Create a new empty range using this range's start position.
341 > */
342 > public static collapseToStart(range: IRange): Range {
343 return new Range(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn);
344 }
345 > range.ts
346 > /**
347 > * Create a new empty range using this range's end position.
348 > */
349 > public collapseToEnd(): Range {
350 return Range.collapseToEnd(this);
351 }
352 > range.ts
353 > /**
354 > * Create a new empty range using this range's end position.
355 > */
356 > public static collapseToEnd(range: IRange): Range {
357 return new Range(range.endLineNumber, range.endColumn, range.endLineNumber, range.endColumn);
358 }
359 > range.ts
360 > /**
361 > * Moves the range by the given amount of lines.
362 > */
363 > public delta(lineCount: number): Range {
364 return new Range(this.startLineNumber + lineCount, this.startColumn, this.endLineNumber + lineCount, this.endColumn);
365 }
366 > range.ts
367 > /**
368 > * Test if this range starts and ends on the same line.
369 > */
370 > public isSingleLine(): boolean {
371 return this.startLineNumber === this.endLineNumber;
372 }
373 > range.ts
374 > // ---
375 >
376 > public static fromPositions(start: IPosition, end: IPosition = start): Range {
377 > return new Range(start.lineNumber, start.column, end.lineNumber, end.column); range.ts
378 > }
379 > range.ts
380 > /**
381 > * Create a `Range` from an `IRange`.
382 > */
383 > public static lift(range: undefined | null): null;
384 > public static lift(range: IRange): Range;
385 > public static lift(range: IRange | undefined | null): Range | null;
386 > public static lift(range: IRange | undefined | null): Range | null {
387 > if (!range) { range.ts
388 return null;
389 }
390 > return new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn); range.ts
391 > }
392 > range.ts
393 > /**
394 > * Test if `obj` is an `IRange`.
395 > */
396 > public static isIRange(obj: unknown): obj is IRange {
397 return (
398 !!obj
403 );
404 }
405 > range.ts
406 > /**
407 > * Test if the two ranges are touching in any way.
408 > */
409 > public static areIntersectingOrTouching(a: IRange, b: IRange): boolean {
410 // Check if `a` is before `b`
411 if (a.endLineNumber < b.startLineNumber || (a.endLineNumber === b.startLineNumber && a.endColumn < b.startColumn)) {
421 return true;
422 }
423 > range.ts
424 > /**
425 > * Test if the two ranges are intersecting. If the ranges are touching it returns true.
426 > */
427 > public static areIntersecting(a: IRange, b: IRange): boolean {
428 // Check if `a` is before `b`
429 if (a.endLineNumber < b.startLineNumber || (a.endLineNumber === b.startLineNumber && a.endColumn <= b.startColumn)) {
439 return true;
440 }
441 > range.ts
442 > /**
443 > * Test if the two ranges are intersecting, but not touching at all.
444 > */
445 > public static areOnlyIntersecting(a: IRange, b: IRange): boolean {
446 // Check if `a` is before `b`
447 if (a.endLineNumber < (b.startLineNumber - 1) || (a.endLineNumber === b.startLineNumber && a.endColumn < (b.startColumn - 1))) {
457 return true;
458 }
459 > range.ts
460 > /**
461 > * A function that compares ranges, useful for sorting ranges
462 > * It will first compare ranges on the startPosition and then on the endPosition
463 > */
464 > public static compareRangesUsingStarts(a: IRange | null | undefined, b: IRange | null | undefined): number {
465 if (a && b) {
466 const aStartLineNumber = a.startLineNumber | 0;
490 return aExists - bExists;
491 }
492 > range.ts
493 > /**
494 > * A function that compares ranges, useful for sorting ranges
495 > * It will first compare ranges on the endPosition and then on the startPosition
496 > */
497 > public static compareRangesUsingEnds(a: IRange, b: IRange): number {
498 if (a.endLineNumber === b.endLineNumber) {
499 if (a.endColumn === b.endColumn) {
507 return a.endLineNumber - b.endLineNumber;
508 }
509 > range.ts
510 > /**
511 > * Test if the range spans multiple lines.
512 > */
513 > public static spansMultipleLines(range: IRange): boolean {
514 return range.endLineNumber > range.startLineNumber;
515 }
516 > range.ts
517 > public toJSON(): IRange {
518 return this;
519 }
520 > } range.ts
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/editor/common/services/editorWebWorker.ts 235 covered LOC · 36 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editorWebWorker.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 { stringDiff } from '../../../base/common/diff/diff.js';
7 > import { IDisposable } from '../../../base/common/lifecycle.js';
8 > import { URI } from '../../../base/common/uri.js';
9 > import { IWebWorkerServerRequestHandler } from '../../../base/common/worker/webWorker.js';
10 > import { Position } from '../core/position.js';
11 > import { IRange, Range } from '../core/range.js';
12 > import { EndOfLineSequence, ITextModel } from '../model.js';
13 > import { IMirrorTextModel, IModelChangedEvent } from '../model/mirrorTextModel.js';
14 > import { IColorInformation, IInplaceReplaceSupportResult, ILink, TextEdit } from '../languages.js';
15 > import { computeLinks } from '../languages/linkComputer.js';
16 > import { BasicInplaceReplace } from '../languages/supports/inplaceReplaceSupport.js';
17 > import { DiffAlgorithmName, IDiffComputationResult, ILineChange, IUnicodeHighlightsResult } from './editorWorker.js';
18 > import { createMonacoBaseAPI } from './editorBaseApi.js';
19 > import { StopWatch } from '../../../base/common/stopwatch.js';
20 > import { UnicodeTextModelHighlighter, UnicodeHighlighterOptions } from './unicodeTextModelHighlighter.js';
21 > import { DiffComputer, IChange } from '../diff/legacyLinesDiffComputer.js';
22 > import { ILinesDiffComputer, ILinesDiffComputerOptions } from '../diff/linesDiffComputer.js';
23 > import { DetailedLineRangeMapping } from '../diff/rangeMapping.js';
24 > import { linesDiffComputers } from '../diff/linesDiffComputers.js';
25 > import { IDocumentDiffProviderOptions } from '../diff/documentDiffProvider.js';
26 > import { BugIndicatingError } from '../../../base/common/errors.js';
27 > import { computeDefaultDocumentColors } from '../languages/defaultDocumentColorsComputer.js';
28 > import { FindSectionHeaderOptions, SectionHeader, findSectionHeaders } from './findSectionHeaders.js';
29 > import { IRawModelData, IWorkerTextModelSyncChannelServer } from './textModelSync/textModelSync.protocol.js';
30 > import { ICommonModel, WorkerTextModelSyncServer } from './textModelSync/textModelSync.impl.js';
31 > import { ISerializedStringEdit, StringEdit } from '../core/edits/stringEdit.js';
32 > import { StringText } from '../core/text/abstractText.js';
33 > import { ensureDependenciesAreSet } from '../core/text/positionToOffset.js';
34 >
35 > export interface IMirrorModel extends IMirrorTextModel {
36 > readonly uri: URI;
37 > readonly version: number;
38 > getValue(): string;
39 > }
40 >
41 > export interface IWorkerContext<H = {}> {
42 > /**
43 > * A proxy to the main thread host object.
44 > */
45 > host: H;
46 > /**
47 > * Get all available mirror models in this worker.
48 > */
49 > getMirrorModels(): IMirrorModel[];
50 > }
51 >
52 > /**
53 > * Range of a word inside a model.
54 > * @internal
55 > */
56 > export interface IWordRange {
57 > /**
58 > * The index where the word starts.
59 > */
60 > readonly start: number;
61 > /**
62 > * The index where the word ends.
63 > */
64 > readonly end: number;
65 > }
66 >
67 > /**
68 > * @internal
69 > */
70 > export class EditorWorker implements IDisposable, IWorkerTextModelSyncChannelServer, IWebWorkerServerRequestHandler {
71 > _requestHandlerBrand: void = undefined;
72 >
73 > private readonly _workerTextModelSyncServer = new WorkerTextModelSyncServer();
74 >
75 > constructor(
76 > private readonly _foreignModule: unknown | null = null
77 > ) { }
78 >
79 > dispose(): void {
80 }
82 > public async $ping() {
83 return 'pong';
84 }
86 > protected _getModel(uri: string): ICommonModel | undefined {
87 > return this._workerTextModelSyncServer.getModel(uri);
88 > }
89 >
90 > public getModels(): ICommonModel[] {
91 return this._workerTextModelSyncServer.getModels();
92 }
94 > public $acceptNewModel(data: IRawModelData): void {
95 > this._workerTextModelSyncServer.$acceptNewModel(data);
96 > }
97 >
98 > public $acceptModelChanged(uri: string, e: IModelChangedEvent): void {
99 this._workerTextModelSyncServer.$acceptModelChanged(uri, e);
100 }
102 > public $acceptRemovedModel(uri: string): void {
103 this._workerTextModelSyncServer.$acceptRemovedModel(uri);
104 }
106 > public async $computeUnicodeHighlights(url: string, options: UnicodeHighlighterOptions, range?: IRange): Promise<IUnicodeHighlightsResult> {
107 const model = this._getModel(url);
108 if (!model) {
111 return UnicodeTextModelHighlighter.computeUnicodeHighlights(model, options, range);
112 }
114 > public async $findSectionHeaders(url: string, options: FindSectionHeaderOptions): Promise<SectionHeader[]> {
115 const model = this._getModel(url);
116 if (!model) {
119 return findSectionHeaders(model, options);
120 }
122 > // ---- BEGIN diff --------------------------------------------------------------------------
123 >
124 > public async $computeDiff(originalUrl: string, modifiedUrl: string, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): Promise<IDiffComputationResult | null> {
125 const original = this._getModel(originalUrl);
126 const modified = this._getModel(modifiedUrl);
133 return result;
134 }
136 > private static computeDiff(originalTextModel: ICommonModel | ITextModel, modifiedTextModel: ICommonModel | ITextModel, options: IDocumentDiffProviderOptions, diffAlgorithm: ILinesDiffComputer): IDiffComputationResult {
137
138 const originalLines = originalTextModel.getLinesContent();
169 };
170 }
172 > private static _modelsAreIdentical(original: ICommonModel | ITextModel, modified: ICommonModel | ITextModel): boolean {
173 const originalLineCount = original.getLineCount();
174 const modifiedLineCount = modified.getLineCount();
185 return true;
186 }
188 > public async $computeDirtyDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean): Promise<IChange[] | null> {
189 const original = this._getModel(originalUrl);
190 const modified = this._getModel(modifiedUrl);
204 return diffComputer.computeDiff().changes;
205 }
207 > public async $computeStringDiff(original: string, modified: string, options: { maxComputationTimeMs: number }, algorithm: DiffAlgorithmName): Promise<ISerializedStringEdit> {
208 return (await computeStringDiff(original, modified, options, algorithm)).toJson();
209 }
211 > // ---- END diff --------------------------------------------------------------------------
212 >
213 >
214 > // ---- BEGIN minimal edits ---------------------------------------------------------------
215 >
216 > private static readonly _diffLimit = 100000;
217 >
218 > public async $computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[], pretty: boolean): Promise<TextEdit[]> {
219 const model = this._getModel(modelUrl);
220 if (!model) {
297 return result;
298 }
300 > public $computeHumanReadableDiff(modelUrl: string, edits: TextEdit[], options: ILinesDiffComputerOptions): TextEdit[] {
301 > const model = this._getModel(modelUrl); editorWebWorker.ts
302 > if (!model) {
303 return edits;
304 }
306 > const result: TextEdit[] = [];
307 > let lastEol: EndOfLineSequence | undefined = undefined;
308 >
309 > edits = edits.slice(0).sort((a, b) => {
310 if (a.range && b.range) {
311 return Range.compareRangesUsingStarts(a.range, b.range);
315 const bRng = b.range ? 0 : 1;
316 return aRng - bRng;
317 > }); editorWebWorker.ts
318 >
319 > for (let { range, text, eol } of edits) {
320 >
321 > if (typeof eol === 'number') {
322 lastEol = eol;
323 }
325 > if (Range.isEmpty(range) && !text) {
326 // empty change
327 continue;
328 }
330 > const original = model.getValueInRange(range);
331 > text = text.replace(/\r\n|\n|\r/g, model.eol);
332 >
333 > if (original === text) {
334 // noop
335 continue;
336 }
338 > // make sure diff won't take too long
339 > if (Math.max(text.length, original.length) > EditorWorker._diffLimit) {
340 result.push({ range, text });
341 continue;
342 }
344 > // compute diff between original and edit.text
345 >
346 > const originalLines = original.split(/\r\n|\n|\r/);
347 > const modifiedLines = text.split(/\r\n|\n|\r/);
348 >
349 > const diff = linesDiffComputers.getDefault().computeDiff(originalLines, modifiedLines, options);
350 >
351 > const start = Range.lift(range).getStartPosition();
352 >
353 > function addPositions(pos1: Position, pos2: Position): Position {
354 > return new Position(pos1.lineNumber + pos2.lineNumber - 1, pos2.lineNumber === 1 ? pos1.column + pos2.column - 1 : pos2.column);
355 > }
356 >
357 > function getText(lines: string[], range: Range): string[] {
358 > const result: string[] = [];
359 > for (let i = range.startLineNumber; i <= range.endLineNumber; i++) {
360 > const line = lines[i - 1];
361 > if (i === range.startLineNumber && i === range.endLineNumber) {
362 > result.push(line.substring(range.startColumn - 1, range.endColumn - 1)); editorWebWorker.ts
363 > } else if (i === range.startLineNumber) { editorWebWorker.ts
364 > result.push(line.substring(range.startColumn - 1)); editorWebWorker.ts
365 > } else if (i === range.endLineNumber) {
366 > result.push(line.substring(0, range.endColumn - 1));
367 > } else {
368 result.push(line);
369 }
371 > return result;
372 > }
373 >
374 > for (const c of diff.changes) {
375 > if (c.innerChanges) {
376 > for (const x of c.innerChanges) {
377 > result.push({
378 > range: Range.fromPositions(
379 > addPositions(start, x.originalRange.getStartPosition()),
380 > addPositions(start, x.originalRange.getEndPosition())
381 > ),
382 > text: getText(modifiedLines, x.modifiedRange).join(model.eol)
383 > });
384 > }
385 > } else {
386 throw new BugIndicatingError('The experimental diff algorithm always produces inner changes');
387 }
389 > }
390 >
391 > if (typeof lastEol === 'number') {
392 result.push({ eol: lastEol, text: '', range: { startLineNumber: 0, startColumn: 0, endLineNumber: 0, endColumn: 0 } });
393 }
395 > return result;
396 > }
398 > // ---- END minimal edits ---------------------------------------------------------------
399 >
400 > public async $computeLinks(modelUrl: string): Promise<ILink[] | null> {
401 const model = this._getModel(modelUrl);
402 if (!model) {
406 return computeLinks(model);
407 }
409 > // --- BEGIN default document colors -----------------------------------------------------------
410 >
411 > public async $computeDefaultDocumentColors(modelUrl: string): Promise<IColorInformation[] | null> {
412 const model = this._getModel(modelUrl);
413 if (!model) {
416 return computeDefaultDocumentColors(model);
417 }
419 > // ---- BEGIN suggest --------------------------------------------------------------------------
420 >
421 > private static readonly _suggestionsLimit = 10000;
422 >
423 > public async $textualSuggest(modelUrls: string[], leadingWord: string | undefined, wordDef: string, wordDefFlags: string): Promise<{ words: string[]; duration: number } | null> {
424
425 const sw = new StopWatch();
446 return { words: Array.from(seen), duration: sw.elapsed() };
447 }
449 >
450 > // ---- END suggest --------------------------------------------------------------------------
451 >
452 > //#region -- word ranges --
453 >
454 > public async $computeWordRanges(modelUrl: string, range: IRange, wordDef: string, wordDefFlags: string): Promise<{ [word: string]: IRange[] }> {
455 const model = this._getModel(modelUrl);
456 if (!model) {
480 return result;
481 }
483 > //#endregion
484 >
485 > public async $navigateValueSet(modelUrl: string, range: IRange, up: boolean, wordDef: string, wordDefFlags: string): Promise<IInplaceReplaceSupportResult | null> {
486 const model = this._getModel(modelUrl);
487 if (!model) {
510 return result;
511 }
513 > // ---- BEGIN foreign module support --------------------------------------------------------------------------
514 >
515 > // foreign method request
516 > public $fmr(method: string, args: unknown[]): Promise<unknown> {
517 if (!this._foreignModule || typeof (this._foreignModule as Record<string, unknown>)[method] !== 'function') {
518 return Promise.reject(new Error('Missing requestHandler or method: ' + method));
525 }
526 }
528 > // ---- END foreign module support --------------------------------------------------------------------------
529 > }
530 >
531 > // This is only available in a Web Worker
532 > declare function importScripts(...urls: string[]): void;
533 >
534 > if (typeof importScripts === 'function') {
535 // Running in a web worker
536 globalThis.monaco = createMonacoBaseAPI();
537 }
539 function resolveLinesDiffComputer(algorithm: DiffAlgorithmName): ILinesDiffComputer | Promise<ILinesDiffComputer> {
540 switch (algorithm) {
545 }
546 }
548 > /**
549 > * @internal
550 > */
551 export async function computeStringDiff(original: string, modified: string, options: { maxComputationTimeMs: number }, algorithm: DiffAlgorithmName): Promise<StringEdit> {
552 const diffAlgorithm = await resolveLinesDiffComputer(algorithm);
src/vs/editor/common/core/edits/stringEdit.ts 232 covered LOC · 63 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- stringEdit.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 { commonPrefixLength, commonSuffixLength } from '../../../../base/common/strings.js';
7 > import { OffsetRange } from '../ranges/offsetRange.js';
8 > import { StringText } from '../text/abstractText.js';
9 > import { BaseEdit, BaseReplacement } from './edit.js';
10 >
11 >
12 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
13 > export abstract class BaseStringEdit<T extends BaseStringReplacement<T> = BaseStringReplacement<any>, TEdit extends BaseStringEdit<T, TEdit> = BaseStringEdit<any, any>> extends BaseEdit<T, TEdit> {
14 > get TReplacement(): T {
15 throw new Error('TReplacement is not defined for BaseStringEdit');
16 }
18 > public static composeOrUndefined<T extends BaseStringEdit>(edits: readonly T[]): T | undefined {
19 if (edits.length === 0) {
20 return undefined;
27 return result;
28 }
30 > /**
31 > * r := trySwap(e1, e2);
32 > * e1.compose(e2) === r.e1.compose(r.e2)
33 > */
34 > public static trySwap(e1: BaseStringEdit, e2: BaseStringEdit): { e1: StringEdit; e2: StringEdit } | undefined {
35 // TODO make this more efficient
36 const e1Inv = e1.inverseOnSlice((start, endEx) => ' '.repeat(endEx - start));
47 return { e1: e1_, e2: e2_ };
48 }
50 > public apply(base: string): string {
51 const resultText: string[] = [];
52 let pos = 0;
59 return resultText.join('');
60 }
62 >
63 > /**
64 > * Creates an edit that reverts this edit.
65 > */
66 > public inverseOnSlice(getOriginalSlice: (start: number, endEx: number) => string): StringEdit {
67 const edits: StringReplacement[] = [];
68 let offset = 0;
76 return new StringEdit(edits);
77 }
79 > /**
80 > * Creates an edit that reverts this edit.
81 > */
82 > public inverse(original: string): StringEdit {
83 return this.inverseOnSlice((start, endEx) => original.substring(start, endEx));
84 }
86 > public rebaseSkipConflicting(base: StringEdit): StringEdit {
87 return this._tryRebase(base, false)!;
88 }
90 > public tryRebase(base: StringEdit): StringEdit | undefined {
91 return this._tryRebase(base, true);
92 }
94 > private _tryRebase(base: StringEdit, noOverlap: boolean): StringEdit | undefined {
95 const newEdits: StringReplacement[] = [];
96
137 return new StringEdit(newEdits);
138 }
140 > public toJson(): ISerializedStringEdit {
141 return this.replacements.map(e => e.toJson());
142 }
144 > public isNeutralOn(text: string): boolean {
145 return this.replacements.every(e => e.isNeutralOn(text));
146 }
148 > public removeCommonSuffixPrefix(originalText: string): StringEdit {
149 const edits: StringReplacement[] = [];
150 for (const e of this.replacements) {
156 return new StringEdit(edits);
157 }
159 > public normalizeEOL(eol: '\r\n' | '\n'): StringEdit {
160 return new StringEdit(this.replacements.map(edit => edit.normalizeEOL(eol)));
161 }
163 > /**
164 > * If `e1.apply(source) === e2.apply(source)`, then `e1.normalizeOnSource(source).equals(e2.normalizeOnSource(source))`.
165 > */
166 > public normalizeOnSource(source: string): StringEdit {
167 const result = this.apply(source);
168
174 return e.toEdit();
175 }
177 > public removeCommonSuffixAndPrefix(source: string): TEdit {
178 return this._createNew(this.replacements.map(e => e.removeCommonSuffixAndPrefix(source))).normalize();
179 }
181 > public applyOnText(docContents: StringText): StringText {
182 return new StringText(this.apply(docContents.value));
183 }
185 > public mapData<TData extends IEditData<TData>>(f: (replacement: T) => TData): AnnotatedStringEdit<TData> {
186 return new AnnotatedStringEdit(
187 this.replacements.map(e => new AnnotatedStringReplacement(
192 );
193 }
194 > } stringEdit.ts
195 >
196 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
197 > export abstract class BaseStringReplacement<T extends BaseStringReplacement<T> = BaseStringReplacement<any>> extends BaseReplacement<T> {
198 > constructor(
199 range: OffsetRange,
200 public readonly newText: string
202 super(range);
203 }
205 > getNewLength(): number { return this.newText.length; }
206 >
207 > override toString(): string {
208 return `${this.replaceRange} -> ${JSON.stringify(this.newText)}`;
209 }
211 > replace(str: string): string {
212 return str.substring(0, this.replaceRange.start) + this.newText + str.substring(this.replaceRange.endExclusive);
213 }
215 > /**
216 > * Checks if the edit would produce no changes when applied to the given text.
217 > */
218 > isNeutralOn(text: string): boolean {
219 return this.newText === text.substring(this.replaceRange.start, this.replaceRange.endExclusive);
220 }
222 > removeCommonSuffixPrefix(originalText: string): StringReplacement {
223 const oldText = originalText.substring(this.replaceRange.start, this.replaceRange.endExclusive);
224
238 return new StringReplacement(replaceRange, newText);
239 }
241 > normalizeEOL(eol: '\r\n' | '\n'): StringReplacement {
242 const newText = this.newText.replace(/\r\n|\n/g, eol);
243 return new StringReplacement(this.replaceRange, newText);
244 }
246 > public removeCommonSuffixAndPrefix(source: string): T {
247 return this.removeCommonSuffix(source).removeCommonPrefix(source);
248 }
250 > public removeCommonPrefix(source: string): T {
251 const oldText = this.replaceRange.substring(source);
252
258 return this.slice(this.replaceRange.deltaStart(prefixLen), new OffsetRange(prefixLen, this.newText.length));
259 }
261 > public removeCommonSuffix(source: string): T {
262 const oldText = this.replaceRange.substring(source);
263
268 return this.slice(this.replaceRange.deltaEnd(-suffixLen), new OffsetRange(0, this.newText.length - suffixLen));
269 }
271 > public toEdit(): StringEdit {
272 return new StringEdit([this]);
273 }
275 > public toJson(): ISerializedStringReplacement {
276 return ({
277 txt: this.newText,
280 });
281 }
282 > } stringEdit.ts
283 >
284 >
285 > /**
286 > * Represents a set of replacements to a string.
287 > * All these replacements are applied at once.
288 > */
289 > export class StringEdit extends BaseStringEdit<StringReplacement, StringEdit> {
290 > /**
291 > * Parses an edit from its string representation.
292 > * E.g. [[2, 12) -> "fgh", [14, 20) -> "qrst", [22, 22) -> "de\n"]
293 > */
294 > public static parse(toStringValue: string): StringEdit {
295 const replacements: StringReplacement[] = [];
296 const regex = /\[(\d+),\s*(\d+)\)\s*->\s*"([^"]*)"/g;
306 return new StringEdit(replacements);
307 }
309 > public static readonly empty = new StringEdit([]);
310 >
311 > public static create(replacements: readonly StringReplacement[]): StringEdit {
312 return new StringEdit(replacements);
313 }
315 > public static single(replacement: StringReplacement): StringEdit {
316 return new StringEdit([replacement]);
317 }
319 > public static replace(range: OffsetRange, replacement: string): StringEdit {
320 return new StringEdit([new StringReplacement(range, replacement)]);
321 }
323 > public static insert(offset: number, replacement: string): StringEdit {
324 return new StringEdit([new StringReplacement(OffsetRange.emptyAt(offset), replacement)]);
325 }
327 > public static delete(range: OffsetRange): StringEdit {
328 return new StringEdit([new StringReplacement(range, '')]);
329 }
331 > public static fromJson(data: ISerializedStringEdit): StringEdit {
332 return new StringEdit(data.map(StringReplacement.fromJson));
333 }
335 > public static compose(edits: readonly StringEdit[]): StringEdit {
336 if (edits.length === 0) {
337 return StringEdit.empty;
343 return result;
344 }
346 > /**
347 > * The replacements are applied in order!
348 > * Equals `StringEdit.compose(replacements.map(r => r.toEdit()))`, but is much more performant.
349 > */
350 > public static composeSequentialReplacements(replacements: readonly StringReplacement[]): StringEdit {
351 let edit = StringEdit.empty;
352 let curEditReplacements: StringReplacement[] = []; // These are reverse sorted
367 return edit;
368 }
370 > constructor(replacements: readonly StringReplacement[]) {
371 > super(replacements);
372 > }
373 >
374 > protected override _createNew(replacements: readonly StringReplacement[]): StringEdit {
375 return new StringEdit(replacements);
376 }
377 > } stringEdit.ts
378 >
379 > /**
380 > * Warning: Be careful when changing this type, as it is used for serialization!
381 > */
382 > export type ISerializedStringEdit = ISerializedStringReplacement[];
383 >
384 > /**
385 > * Warning: Be careful when changing this type, as it is used for serialization!
386 > */
387 > export interface ISerializedStringReplacement {
388 > txt: string;
389 > pos: number;
390 > len: number;
391 > }
392 >
393 > export class StringReplacement extends BaseStringReplacement<StringReplacement> {
394 > public static insert(offset: number, text: string): StringReplacement {
395 return new StringReplacement(OffsetRange.emptyAt(offset), text);
396 }
398 > public static replace(range: OffsetRange, text: string): StringReplacement {
399 return new StringReplacement(range, text);
400 }
402 > public static delete(range: OffsetRange): StringReplacement {
403 return new StringReplacement(range, '');
404 }
406 > public static fromJson(data: ISerializedStringReplacement): StringReplacement {
407 return new StringReplacement(OffsetRange.ofStartAndLength(data.pos, data.len), data.txt);
408 }
410 > override equals(other: StringReplacement): boolean {
411 return this.replaceRange.equals(other.replaceRange) && this.newText === other.newText;
412 }
414 > override tryJoinTouching(other: StringReplacement): StringReplacement | undefined {
415 return new StringReplacement(this.replaceRange.joinRightTouching(other.replaceRange), this.newText + other.newText);
416 }
418 > override slice(range: OffsetRange, rangeInReplacement?: OffsetRange): StringReplacement {
419 return new StringReplacement(range, rangeInReplacement ? rangeInReplacement.substring(this.newText) : this.newText);
420 }
421 > } stringEdit.ts
422 >
423 > export function applyEditsToRanges(sortedRanges: OffsetRange[], edit: StringEdit): OffsetRange[] {
424 sortedRanges = sortedRanges.slice();
425
487 return result;
488 }
490 > /**
491 > * Represents data associated to a single edit, which survives certain edit operations.
492 > */
493 > export interface IEditData<T> {
494 > join(other: T): T | undefined;
495 > }
496 >
497 > export class VoidEditData implements IEditData<VoidEditData> {
498 > join(other: VoidEditData): VoidEditData | undefined {
499 return this;
500 }
501 > } stringEdit.ts
502 >
503 > /**
504 > * Represents a set of replacements to a string.
505 > * All these replacements are applied at once.
506 > */
507 > export class AnnotatedStringEdit<T extends IEditData<T>> extends BaseStringEdit<AnnotatedStringReplacement<T>, AnnotatedStringEdit<T>> {
508 > public static readonly empty = new AnnotatedStringEdit<never>([]);
509 >
510 > public static create<T extends IEditData<T>>(replacements: readonly AnnotatedStringReplacement<T>[]): AnnotatedStringEdit<T> {
511 return new AnnotatedStringEdit(replacements);
512 }
514 > public static single<T extends IEditData<T>>(replacement: AnnotatedStringReplacement<T>): AnnotatedStringEdit<T> {
515 return new AnnotatedStringEdit([replacement]);
516 }
518 > public static replace<T extends IEditData<T>>(range: OffsetRange, replacement: string, data: T): AnnotatedStringEdit<T> {
519 return new AnnotatedStringEdit([new AnnotatedStringReplacement(range, replacement, data)]);
520 }
522 > public static insert<T extends IEditData<T>>(offset: number, replacement: string, data: T): AnnotatedStringEdit<T> {
523 return new AnnotatedStringEdit([new AnnotatedStringReplacement(OffsetRange.emptyAt(offset), replacement, data)]);
524 }
526 > public static delete<T extends IEditData<T>>(range: OffsetRange, data: T): AnnotatedStringEdit<T> {
527 return new AnnotatedStringEdit([new AnnotatedStringReplacement(range, '', data)]);
528 }
530 > public static compose<T extends IEditData<T>>(edits: readonly AnnotatedStringEdit<T>[]): AnnotatedStringEdit<T> {
531 if (edits.length === 0) {
532 return AnnotatedStringEdit.empty;
538 return result;
539 }
541 > constructor(replacements: readonly AnnotatedStringReplacement<T>[]) {
542 > super(replacements);
543 > }
544 >
545 > protected override _createNew(replacements: readonly AnnotatedStringReplacement<T>[]): AnnotatedStringEdit<T> {
546 return new AnnotatedStringEdit<T>(replacements);
547 }
549 > public toStringEdit(filter?: (replacement: AnnotatedStringReplacement<T>) => boolean): StringEdit {
550 const newReplacements: StringReplacement[] = [];
551 for (const r of this.replacements) {
556 return new StringEdit(newReplacements);
557 }
558 > } stringEdit.ts
559 >
560 > export class AnnotatedStringReplacement<T extends IEditData<T>> extends BaseStringReplacement<AnnotatedStringReplacement<T>> {
561 > public static insert<T extends IEditData<T>>(offset: number, text: string, data: T): AnnotatedStringReplacement<T> {
562 > return new AnnotatedStringReplacement<T>(OffsetRange.emptyAt(offset), text, data);
563 > }
564 >
565 > public static replace<T extends IEditData<T>>(range: OffsetRange, text: string, data: T): AnnotatedStringReplacement<T> {
566 return new AnnotatedStringReplacement<T>(range, text, data);
567 }
569 > public static delete<T extends IEditData<T>>(range: OffsetRange, data: T): AnnotatedStringReplacement<T> {
570 return new AnnotatedStringReplacement<T>(range, '', data);
571 }
573 > constructor(
574 range: OffsetRange,
575 newText: string,
578 super(range, newText);
579 }
581 > override equals(other: AnnotatedStringReplacement<T>): boolean {
582 return this.replaceRange.equals(other.replaceRange) && this.newText === other.newText && this.data === other.data;
583 }
585 > tryJoinTouching(other: AnnotatedStringReplacement<T>): AnnotatedStringReplacement<T> | undefined {
586 const joined = this.data.join(other.data);
587 if (joined === undefined) {
590 return new AnnotatedStringReplacement(this.replaceRange.joinRightTouching(other.replaceRange), this.newText + other.newText, joined);
591 }
593 > slice(range: OffsetRange, rangeInReplacement?: OffsetRange): AnnotatedStringReplacement<T> {
594 return new AnnotatedStringReplacement(range, rangeInReplacement ? rangeInReplacement.substring(this.newText) : this.newText, this.data);
595 }
596 > } stringEdit.ts
597 >
598 > /**
599 > * Returns true if both ranges are empty (inserts) at the exact same position.
600 > * In this case, although they don't "intersect" in the traditional sense,
601 > * they conflict because the order of insertion matters.
602 > */
603 function areConcurrentInserts(r1: OffsetRange, r2: OffsetRange): boolean {
604 return r1.isEmpty && r2.isEmpty && r1.start === r2.start;
605 }
607 > /**
608 > * Returns true if `insert` is an empty range (insert) strictly inside `range`.
609 > * For example, insert at position 5 is inside [3, 7) but not inside [5, 7) or [3, 5).
610 > */
611 function isInsertStrictlyInsideRange(insert: OffsetRange, range: OffsetRange): boolean {
612 return insert.isEmpty && range.start < insert.start && insert.start < range.endExclusive;
src/vs/editor/common/diff/rangeMapping.ts 221 covered LOC · 56 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- rangeMapping.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 { groupAdjacentBy } from '../../../base/common/arrays.js';
7 > import { assertFn, checkAdjacentItems } from '../../../base/common/assert.js';
8 > import { BugIndicatingError } from '../../../base/common/errors.js';
9 > import { LineRange } from '../core/ranges/lineRange.js';
10 > import { Position } from '../core/position.js';
11 > import { Range } from '../core/range.js';
12 > import { TextReplacement, TextEdit } from '../core/edits/textEdit.js';
13 > import { AbstractText } from '../core/text/abstractText.js';
14 > import { IChange } from './legacyLinesDiffComputer.js';
15 >
16 > /**
17 > * Maps a line range in the original text model to a line range in the modified text model.
18 > */
19 > export class LineRangeMapping {
20 > public static inverse(mapping: readonly LineRangeMapping[], originalLineCount: number, modifiedLineCount: number): LineRangeMapping[] {
21 const result: LineRangeMapping[] = [];
22 let lastOriginalEndLineNumber = 1;
43 return result;
44 }
46 > public static clip(mapping: readonly LineRangeMapping[], originalRange: LineRange, modifiedRange: LineRange): LineRangeMapping[] {
47 const result: LineRangeMapping[] = [];
48 for (const m of mapping) {
55 return result;
56 }
58 > /**
59 > * The line range in the original text model.
60 > */
61 > public readonly original: LineRange;
62 >
63 > /**
64 > * The line range in the modified text model.
65 > */
66 > public readonly modified: LineRange;
67 >
68 > constructor(
69 > originalRange: LineRange, rangeMapping.ts
70 > modifiedRange: LineRange
71 > ) {
72 > this.original = originalRange;
73 > this.modified = modifiedRange;
74 > }
76 >
77 > public toString(): string {
78 return `{${this.original.toString()}->${this.modified.toString()}}`;
79 }
81 > public flip(): LineRangeMapping {
82 return new LineRangeMapping(this.modified, this.original);
83 }
85 > public join(other: LineRangeMapping): LineRangeMapping {
86 return new LineRangeMapping(
87 this.original.join(other.original),
89 );
90 }
92 > public get changedLineCount() {
93 return Math.max(this.original.length, this.modified.length);
94 }
96 > /**
97 > * This method assumes that the LineRangeMapping describes a valid diff!
98 > * I.e. if one range is empty, the other range cannot be the entire document.
99 > * It avoids various problems when the line range points to non-existing line-numbers.
100 > */
101 > public toRangeMapping(): RangeMapping {
102 const origInclusiveRange = this.original.toInclusiveRange();
103 const modInclusiveRange = this.modified.toInclusiveRange();
124 }
125 }
127 > /**
128 > * This method assumes that the LineRangeMapping describes a valid diff!
129 > * I.e. if one range is empty, the other range cannot be the entire document.
130 > * It avoids various problems when the line range points to non-existing line-numbers.
131 > */
132 > public toRangeMapping2(original: string[], modified: string[]): RangeMapping {
133 > if (isValidLineNumber(this.original.endLineNumberExclusive, original) rangeMapping.ts
134 > && isValidLineNumber(this.modified.endLineNumberExclusive, modified)) {
135 > return new RangeMapping( rangeMapping.ts
136 > new Range(this.original.startLineNumber, 1, this.original.endLineNumberExclusive, 1),
137 > new Range(this.modified.startLineNumber, 1, this.modified.endLineNumberExclusive, 1),
138 > );
139 > }
140
141 > if (!this.original.isEmpty && !this.modified.isEmpty) { rangeMapping.ts
142 return new RangeMapping(
143 Range.fromPositions(
152 }
153
154 > if (this.original.startLineNumber > 1 && this.modified.startLineNumber > 1) { rangeMapping.ts
155 return new RangeMapping(
156 Range.fromPositions(
169
170 throw new BugIndicatingError();
171 > } rangeMapping.ts
172 > } rangeMapping.ts
173 >
174 function normalizePosition(position: Position, content: string[]): Position {
175 if (position.lineNumber < 1) {
185 return position;
186 }
188 > function isValidLineNumber(lineNumber: number, lines: string[]): boolean { rangeMapping.ts
189 > return lineNumber >= 1 && lineNumber <= lines.length;
190 > }
192 > /**
193 > * Maps a line range in the original text model to a line range in the modified text model.
194 > * Also contains inner range mappings.
195 > */
196 > export class DetailedLineRangeMapping extends LineRangeMapping {
197 > public static toTextEdit(mapping: readonly DetailedLineRangeMapping[], modified: AbstractText): TextEdit {
198 const replacements: TextReplacement[] = [];
199 for (const m of mapping) {
205 return new TextEdit(replacements);
206 }
208 > public static fromRangeMappings(rangeMappings: RangeMapping[]): DetailedLineRangeMapping {
209 const originalRange = LineRange.join(rangeMappings.map(r => LineRange.fromRangeInclusive(r.originalRange)));
210 const modifiedRange = LineRange.join(rangeMappings.map(r => LineRange.fromRangeInclusive(r.modifiedRange)));
211 return new DetailedLineRangeMapping(originalRange, modifiedRange, rangeMappings);
212 }
214 > /**
215 > * If inner changes have not been computed, this is set to undefined.
216 > * Otherwise, it represents the character-level diff in this line range.
217 > * The original range of each range mapping should be contained in the original line range (same for modified), exceptions are new-lines.
218 > * Must not be an empty array.
219 > */
220 > public readonly innerChanges: RangeMapping[] | undefined;
221 >
222 > constructor(
223 > originalRange: LineRange, rangeMapping.ts
224 > modifiedRange: LineRange,
225 > innerChanges: RangeMapping[] | undefined
226 > ) {
227 > super(originalRange, modifiedRange);
228 > this.innerChanges = innerChanges;
229 > }
231 > public override flip(): DetailedLineRangeMapping {
232 return new DetailedLineRangeMapping(this.modified, this.original, this.innerChanges?.map(c => c.flip()));
233 }
235 > public withInnerChangesFromLineRanges(): DetailedLineRangeMapping {
236 return new DetailedLineRangeMapping(this.original, this.modified, [this.toRangeMapping()]);
237 }
238 > } rangeMapping.ts
239 >
240 > /**
241 > * Maps a range in the original text model to a range in the modified text model.
242 > */
243 > export class RangeMapping {
244 > public static fromEdit(edit: TextEdit): RangeMapping[] {
245 const newRanges = edit.getNewRanges();
246 const result = edit.replacements.map((e, idx) => new RangeMapping(e.range, newRanges[idx]));
247 return result;
248 }
250 > public static fromEditJoin(edit: TextEdit): RangeMapping {
251 const newRanges = edit.getNewRanges();
252 const result = edit.replacements.map((e, idx) => new RangeMapping(e.range, newRanges[idx]));
253 return RangeMapping.join(result);
254 }
256 > public static join(rangeMappings: RangeMapping[]): RangeMapping {
257 if (rangeMappings.length === 0) {
258 throw new BugIndicatingError('Cannot join an empty list of range mappings');
264 return result;
265 }
267 > public static assertSorted(rangeMappings: RangeMapping[]): void {
268 for (let i = 1; i < rangeMappings.length; i++) {
269 const previous = rangeMappings[i - 1];
277 }
278 }
280 > /**
281 > * The original range.
282 > */
283 > readonly originalRange: Range;
284 >
285 > /**
286 > * The modified range.
287 > */
288 > readonly modifiedRange: Range;
289 >
290 > constructor(
291 > originalRange: Range, rangeMapping.ts
292 > modifiedRange: Range
293 > ) {
294 > this.originalRange = originalRange;
295 > this.modifiedRange = modifiedRange;
296 > }
298 > public toString(): string {
299 return `{${this.originalRange.toString()}->${this.modifiedRange.toString()}}`;
300 }
302 > public flip(): RangeMapping {
303 return new RangeMapping(this.modifiedRange, this.originalRange);
304 }
306 > /**
307 > * Creates a single text edit that describes the change from the original to the modified text.
308 > */
309 > public toTextEdit(modified: AbstractText): TextReplacement {
310 const newText = modified.getValueOfRange(this.modifiedRange);
311 return new TextReplacement(this.originalRange, newText);
312 }
314 > public join(other: RangeMapping): RangeMapping {
315 return new RangeMapping(
316 this.originalRange.plusRange(other.originalRange),
318 );
319 }
320 > } rangeMapping.ts
321 >
322 > export function lineRangeMappingFromRangeMappings(alignments: readonly RangeMapping[], originalLines: AbstractText, modifiedLines: AbstractText, dontAssertStartLine: boolean = false): DetailedLineRangeMapping[] {
323 > const changes: DetailedLineRangeMapping[] = []; rangeMapping.ts
324 > for (const g of groupAdjacentBy(
325 > alignments.map(a => getLineRangeMapping(a, originalLines, modifiedLines)),
326 > (a1, a2) =>
327 > a1.original.intersectsOrTouches(a2.original) rangeMapping.ts
328 > || a1.modified.intersectsOrTouches(a2.modified) rangeMapping.ts
329 > )) { rangeMapping.ts
330 > const first = g[0]; rangeMapping.ts
331 > const last = g[g.length - 1];
332 >
333 > changes.push(new DetailedLineRangeMapping(
334 > first.original.join(last.original),
335 > first.modified.join(last.modified),
336 > g.map(a => a.innerChanges![0]),
337 > ));
338 > }
340 > assertFn(() => {
341 > if (!dontAssertStartLine && changes.length > 0) {
342 > if (changes[0].modified.startLineNumber !== changes[0].original.startLineNumber) { rangeMapping.ts
343 return false;
344 }
346 > if (modifiedLines.length.lineCount - changes[changes.length - 1].modified.endLineNumberExclusive !== originalLines.length.lineCount - changes[changes.length - 1].original.endLineNumberExclusive) {
347 return false;
348 }
349 > } rangeMapping.ts
350 > return checkAdjacentItems(changes, rangeMapping.ts
351 > (m1, m2) => m2.original.startLineNumber - m1.original.endLineNumberExclusive === m2.modified.startLineNumber - m1.modified.endLineNumberExclusive &&
352 > // There has to be an unchanged line in between (otherwise both diffs should have been joined) rangeMapping.ts
353 > m1.original.endLineNumberExclusive < m2.original.startLineNumber &&
354 > m1.modified.endLineNumberExclusive < m2.modified.startLineNumber,
355 > ); rangeMapping.ts
356 > });
357 >
358 > return changes;
359 > }
361 > export function getLineRangeMapping(rangeMapping: RangeMapping, originalLines: AbstractText, modifiedLines: AbstractText): DetailedLineRangeMapping {
362 > let lineStartDelta = 0; rangeMapping.ts
363 > let lineEndDelta = 0;
364 >
365 > // rangeMapping describes the edit that replaces `rangeMapping.originalRange` with `newText := getText(modifiedLines, rangeMapping.modifiedRange)`.
366 >
367 > // original: ]xxx \n <- this line is not modified
368 > // modified: ]xx \n
369 > if (rangeMapping.modifiedRange.endColumn === 1 && rangeMapping.originalRange.endColumn === 1
370 > && rangeMapping.originalRange.startLineNumber + lineStartDelta <= rangeMapping.originalRange.endLineNumber rangeMapping.ts
371 > && rangeMapping.modifiedRange.startLineNumber + lineStartDelta <= rangeMapping.modifiedRange.endLineNumber) { rangeMapping.ts
372 > // We can only do this if the range is not empty yet rangeMapping.ts
373 > lineEndDelta = -1;
374 > }
376 > // original: xxx[ \n <- this line is not modified
377 > // modified: xxx[ \n
378 > if (rangeMapping.modifiedRange.startColumn - 1 >= modifiedLines.getLineLength(rangeMapping.modifiedRange.startLineNumber)
379 && rangeMapping.originalRange.startColumn - 1 >= originalLines.getLineLength(rangeMapping.originalRange.startLineNumber)
380 && rangeMapping.originalRange.startLineNumber <= rangeMapping.originalRange.endLineNumber + lineEndDelta
381 > && rangeMapping.modifiedRange.startLineNumber <= rangeMapping.modifiedRange.endLineNumber + lineEndDelta) { rangeMapping.ts
382 // We can only do this if the range is not empty yet
383 lineStartDelta = 1;
384 }
386 > const originalLineRange = new LineRange(
387 > rangeMapping.originalRange.startLineNumber + lineStartDelta,
388 > rangeMapping.originalRange.endLineNumber + 1 + lineEndDelta
389 > );
390 > const modifiedLineRange = new LineRange(
391 > rangeMapping.modifiedRange.startLineNumber + lineStartDelta,
392 > rangeMapping.modifiedRange.endLineNumber + 1 + lineEndDelta
393 > );
394 >
395 > return new DetailedLineRangeMapping(originalLineRange, modifiedLineRange, [rangeMapping]);
396 > }
398 > export function lineRangeMappingFromChange(change: IChange): LineRangeMapping {
399 let originalRange: LineRange;
400 if (change.originalEndLineNumber === 0) {
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/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer.ts 197 covered LOC · 44 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- defaultLinesDiffComputer.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 { equals } from '../../../../base/common/arrays.js';
7 > import { assertFn } from '../../../../base/common/assert.js';
8 > import { LineRange } from '../../core/ranges/lineRange.js';
9 > import { OffsetRange } from '../../core/ranges/offsetRange.js';
10 > import { Position } from '../../core/position.js';
11 > import { Range } from '../../core/range.js';
12 > import { ArrayText } from '../../core/text/abstractText.js';
13 > import { ILinesDiffComputer, ILinesDiffComputerOptions, LinesDiff, MovedText } from '../linesDiffComputer.js';
14 > import { DetailedLineRangeMapping, LineRangeMapping, lineRangeMappingFromRangeMappings, RangeMapping } from '../rangeMapping.js';
15 > import { DateTimeout, InfiniteTimeout, ITimeout, SequenceDiff } from './algorithms/diffAlgorithm.js';
16 > import { DynamicProgrammingDiffing } from './algorithms/dynamicProgrammingDiffing.js';
17 > import { MyersDiffAlgorithm } from './algorithms/myersDiffAlgorithm.js';
18 > import { computeMovedLines } from './computeMovedLines.js';
19 > import { extendDiffsToEntireWordIfAppropriate, optimizeSequenceDiffs, removeShortMatches, removeVeryShortMatchingLinesBetweenDiffs, removeVeryShortMatchingTextBetweenLongDiffs } from './heuristicSequenceOptimizations.js';
20 > import { LineSequence } from './lineSequence.js';
21 > import { LinesSliceCharSequence } from './linesSliceCharSequence.js';
22 >
23 > export class DefaultLinesDiffComputer implements ILinesDiffComputer {
24 > private readonly dynamicProgrammingDiffing = new DynamicProgrammingDiffing(); defaultLinesDiffComputer.ts
25 > private readonly myersDiffingAlgorithm = new MyersDiffAlgorithm();
27 > computeDiff(originalLines: string[], modifiedLines: string[], options: ILinesDiffComputerOptions): LinesDiff {
28 > if (originalLines.length <= 1 && equals(originalLines, modifiedLines, (a, b) => a === b)) { defaultLinesDiffComputer.ts
29 return new LinesDiff([], [], false);
30 }
32 > if (originalLines.length === 1 && originalLines[0].length === 0 || modifiedLines.length === 1 && modifiedLines[0].length === 0) {
33 return new LinesDiff([
34 new DetailedLineRangeMapping(
44 ], [], false);
45 }
47 > const timeout = options.maxComputationTimeMs === 0 ? InfiniteTimeout.instance : new DateTimeout(options.maxComputationTimeMs); defaultLinesDiffComputer.ts
48 > const considerWhitespaceChanges = !options.ignoreTrimWhitespace;
49 >
50 > const perfectHashes = new Map<string, number>();
51 > function getOrCreateHash(text: string): number {
52 > let hash = perfectHashes.get(text); defaultLinesDiffComputer.ts
53 > if (hash === undefined) {
54 > hash = perfectHashes.size;
55 > perfectHashes.set(text, hash);
56 > }
57 > return hash;
58 > }
60 > const originalLinesHashes = originalLines.map((l) => getOrCreateHash(l.trim()));
61 > const modifiedLinesHashes = modifiedLines.map((l) => getOrCreateHash(l.trim()));
62 >
63 > const sequence1 = new LineSequence(originalLinesHashes, originalLines);
64 > const sequence2 = new LineSequence(modifiedLinesHashes, modifiedLines);
65 >
66 > const lineAlignmentResult = (() => {
67 > if (sequence1.length + sequence2.length < 1700) { defaultLinesDiffComputer.ts
68 > // Use the improved algorithm for small files
69 > return this.dynamicProgrammingDiffing.compute(
70 > sequence1,
71 > sequence2,
72 > timeout,
73 > (offset1, offset2) =>
74 > originalLines[offset1] === modifiedLines[offset2] defaultLinesDiffComputer.ts
75 > ? modifiedLines[offset2].length === 0 defaultLinesDiffComputer.ts
77 > : 1 + Math.log(1 + modifiedLines[offset2].length) defaultLinesDiffComputer.ts
80 > }
81
82 return this.myersDiffingAlgorithm.compute(
85 timeout
86 );
88 >
89 > let lineAlignments = lineAlignmentResult.diffs;
90 > let hitTimeout = lineAlignmentResult.hitTimeout;
91 > lineAlignments = optimizeSequenceDiffs(sequence1, sequence2, lineAlignments);
92 > lineAlignments = removeVeryShortMatchingLinesBetweenDiffs(sequence1, sequence2, lineAlignments);
93 >
94 > const alignments: RangeMapping[] = [];
95 >
96 > const scanForWhitespaceChanges = (equalLinesCount: number) => {
97 > if (!considerWhitespaceChanges) { defaultLinesDiffComputer.ts
98 return;
99 }
101 > for (let i = 0; i < equalLinesCount; i++) {
102 > const seq1Offset = seq1LastStart + i; defaultLinesDiffComputer.ts
103 > const seq2Offset = seq2LastStart + i;
104 > if (originalLines[seq1Offset] !== modifiedLines[seq2Offset]) {
105 // This is because of whitespace changes, diff these lines
106 const characterDiffs = this.refineDiff(originalLines, modifiedLines, new SequenceDiff(
115 }
116 }
120 > let seq1LastStart = 0;
121 > let seq2LastStart = 0;
122 >
123 > for (const diff of lineAlignments) {
124 > assertFn(() => diff.seq1Range.start - seq1LastStart === diff.seq2Range.start - seq2LastStart); defaultLinesDiffComputer.ts
125 >
126 > const equalLinesCount = diff.seq1Range.start - seq1LastStart;
127 >
128 > scanForWhitespaceChanges(equalLinesCount);
129 >
130 > seq1LastStart = diff.seq1Range.endExclusive;
131 > seq2LastStart = diff.seq2Range.endExclusive;
132 >
133 > const characterDiffs = this.refineDiff(originalLines, modifiedLines, diff, timeout, considerWhitespaceChanges, options);
134 > if (characterDiffs.hitTimeout) {
135 hitTimeout = true;
136 }
137 > for (const a of characterDiffs.mappings) { defaultLinesDiffComputer.ts
138 > alignments.push(a);
139 > }
140 > }
142 > scanForWhitespaceChanges(originalLines.length - seq1LastStart);
143 >
144 > const original = new ArrayText(originalLines);
145 > const modified = new ArrayText(modifiedLines);
146 >
147 > const changes = lineRangeMappingFromRangeMappings(alignments, original, modified);
148 >
149 > let moves: MovedText[] = [];
150 > if (options.computeMoves) {
151 moves = this.computeMoves(changes, originalLines, modifiedLines, originalLinesHashes, modifiedLinesHashes, timeout, considerWhitespaceChanges, options);
152 }
154 > // Make sure all ranges are valid
155 > assertFn(() => {
156 > function validatePosition(pos: Position, lines: string[]): boolean {
157 > if (pos.lineNumber < 1 || pos.lineNumber > lines.length) { return false; } defaultLinesDiffComputer.ts
158 > const line = lines[pos.lineNumber - 1];
159 > if (pos.column < 1 || pos.column > line.length + 1) { return false; }
160 > return true;
161 > }
163 > function validateRange(range: LineRange, lines: string[]): boolean {
164 > if (range.startLineNumber < 1 || range.startLineNumber > lines.length + 1) { return false; } defaultLinesDiffComputer.ts
165 > if (range.endLineNumberExclusive < 1 || range.endLineNumberExclusive > lines.length + 1) { return false; }
166 > return true;
167 > }
169 > for (const c of changes) {
170 > if (!c.innerChanges) { return false; } defaultLinesDiffComputer.ts
171 > for (const ic of c.innerChanges) {
172 > const valid = validatePosition(ic.modifiedRange.getStartPosition(), modifiedLines) && validatePosition(ic.modifiedRange.getEndPosition(), modifiedLines) &&
173 > validatePosition(ic.originalRange.getStartPosition(), originalLines) && validatePosition(ic.originalRange.getEndPosition(), originalLines);
174 > if (!valid) {
175 return false;
176 }
178 > if (!validateRange(c.modified, modifiedLines) || !validateRange(c.original, originalLines)) {
179 return false;
180 }
182 > return true; defaultLinesDiffComputer.ts
183 > });
184 >
185 > return new LinesDiff(changes, moves, hitTimeout);
188 > private computeMoves(
189 changes: DetailedLineRangeMapping[],
190 originalLines: string[],
214 return movesWithDiffs;
215 }
217 > private refineDiff(originalLines: string[], modifiedLines: string[], diff: SequenceDiff, timeout: ITimeout, considerWhitespaceChanges: boolean, options: ILinesDiffComputerOptions): { mappings: RangeMapping[]; hitTimeout: boolean } {
218 > const lineRangeMapping = toLineRangeMapping(diff); defaultLinesDiffComputer.ts
219 > const rangeMapping = lineRangeMapping.toRangeMapping2(originalLines, modifiedLines);
220 >
221 > const slice1 = new LinesSliceCharSequence(originalLines, rangeMapping.originalRange, considerWhitespaceChanges);
222 > const slice2 = new LinesSliceCharSequence(modifiedLines, rangeMapping.modifiedRange, considerWhitespaceChanges);
223 >
224 > const diffResult = slice1.length + slice2.length < 500
225 > ? this.dynamicProgrammingDiffing.compute(slice1, slice2, timeout) defaultLinesDiffComputer.ts
226 : this.myersDiffingAlgorithm.compute(slice1, slice2, timeout);
228 > const check = false;
229 >
230 > let diffs = diffResult.diffs;
231 > if (check) { SequenceDiff.assertSorted(diffs); }
232 > diffs = optimizeSequenceDiffs(slice1, slice2, diffs);
233 > if (check) { SequenceDiff.assertSorted(diffs); }
234 > diffs = extendDiffsToEntireWordIfAppropriate(slice1, slice2, diffs, (seq, idx) => seq.findWordContaining(idx));
235 > if (check) { SequenceDiff.assertSorted(diffs); }
236 >
237 > if (options.extendToSubwords) {
238 diffs = extendDiffsToEntireWordIfAppropriate(slice1, slice2, diffs, (seq, idx) => seq.findSubWordContaining(idx), true);
239 if (check) { SequenceDiff.assertSorted(diffs); }
240 }
242 > diffs = removeShortMatches(slice1, slice2, diffs);
243 > if (check) { SequenceDiff.assertSorted(diffs); }
244 > diffs = removeVeryShortMatchingTextBetweenLongDiffs(slice1, slice2, diffs);
245 > if (check) { SequenceDiff.assertSorted(diffs); }
246 >
247 > const result = diffs.map(
248 > (d) =>
249 > new RangeMapping(
250 > slice1.translateRange(d.seq1Range),
251 > slice2.translateRange(d.seq2Range)
252 > )
253 > );
254 >
255 > if (check) { RangeMapping.assertSorted(result); }
256 >
257 > // Assert: result applied on original should be the same as diff applied to original
258 >
259 > return {
260 > mappings: result,
261 > hitTimeout: diffResult.hitTimeout,
262 > };
263 > }
265 >
266 > function toLineRangeMapping(sequenceDiff: SequenceDiff) { defaultLinesDiffComputer.ts
267 > return new LineRangeMapping(
268 > new LineRange(sequenceDiff.seq1Range.start + 1, sequenceDiff.seq1Range.endExclusive + 1),
269 > new LineRange(sequenceDiff.seq2Range.start + 1, sequenceDiff.seq2Range.endExclusive + 1),
270 > );
271 > }
src/vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence.ts 197 covered LOC · 64 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- linesSliceCharSequence.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 { findLastIdxMonotonous, findLastMonotonous, findFirstMonotonous } from '../../../../base/common/arraysFind.js';
7 > import { CharCode } from '../../../../base/common/charCode.js';
8 > import { OffsetRange } from '../../core/ranges/offsetRange.js';
9 > import { Position } from '../../core/position.js';
10 > import { Range } from '../../core/range.js';
11 > import { ISequence } from './algorithms/diffAlgorithm.js';
12 > import { isSpace } from './utils.js';
13 >
14 > export class LinesSliceCharSequence implements ISequence {
15 > private readonly elements: number[] = [];
16 > private readonly firstElementOffsetByLineIdx: number[] = [];
17 > private readonly lineStartOffsets: number[] = [];
18 > private readonly trimmedWsLengthsByLineIdx: number[] = [];
19 >
20 > constructor(public readonly lines: string[], private readonly range: Range, public readonly considerWhitespaceChanges: boolean) {
21 > this.firstElementOffsetByLineIdx.push(0); linesSliceCharSequence.ts
22 > for (let lineNumber = this.range.startLineNumber; lineNumber <= this.range.endLineNumber; lineNumber++) {
23 > let line = lines[lineNumber - 1];
24 > let lineStartOffset = 0;
25 > if (lineNumber === this.range.startLineNumber && this.range.startColumn > 1) {
26 lineStartOffset = this.range.startColumn - 1;
27 line = line.substring(lineStartOffset);
28 }
29 > this.lineStartOffsets.push(lineStartOffset); linesSliceCharSequence.ts
30 >
31 > let trimmedWsLength = 0;
32 > if (!considerWhitespaceChanges) {
33 const trimmedStartLine = line.trimStart();
34 trimmedWsLength = line.length - trimmedStartLine.length;
35 line = trimmedStartLine.trimEnd();
36 }
37 > this.trimmedWsLengthsByLineIdx.push(trimmedWsLength); linesSliceCharSequence.ts
38 >
39 > const lineLength = lineNumber === this.range.endLineNumber ? Math.min(this.range.endColumn - 1 - lineStartOffset - trimmedWsLength, line.length) : line.length;
40 > for (let i = 0; i < lineLength; i++) {
41 > this.elements.push(line.charCodeAt(i));
42 > }
43 >
44 > if (lineNumber < this.range.endLineNumber) {
45 > this.elements.push('\n'.charCodeAt(0)); linesSliceCharSequence.ts
46 > this.firstElementOffsetByLineIdx.push(this.elements.length);
47 > }
49 > }
51 > toString() {
52 return `Slice: "${this.text}"`;
53 }
55 > get text(): string {
56 return this.getText(new OffsetRange(0, this.length));
57 }
59 > getText(range: OffsetRange): string {
60 > return this.elements.slice(range.start, range.endExclusive).map(e => String.fromCharCode(e)).join(''); linesSliceCharSequence.ts
61 > }
63 > getElement(offset: number): number {
64 > return this.elements[offset]; linesSliceCharSequence.ts
65 > }
67 > get length(): number {
68 > return this.elements.length; linesSliceCharSequence.ts
69 > }
71 > public getBoundaryScore(length: number): number {
72 > // a b c , d e f linesSliceCharSequence.ts
73 > // 11 0 0 12 15 6 13 0 0 11
74 >
75 > const prevCategory = getCategory(length > 0 ? this.elements[length - 1] : -1);
76 > const nextCategory = getCategory(length < this.elements.length ? this.elements[length] : -1);
77 >
78 > if (prevCategory === CharBoundaryCategory.LineBreakCR && nextCategory === CharBoundaryCategory.LineBreakLF) {
79 // don't break between \r and \n
80 return 0;
81 }
82 > if (prevCategory === CharBoundaryCategory.LineBreakLF) { linesSliceCharSequence.ts
83 > // prefer the linebreak before the change linesSliceCharSequence.ts
84 > return 150;
85 > }
87 > let score = 0;
88 > if (prevCategory !== nextCategory) {
89 > score += 10;
90 > if (prevCategory === CharBoundaryCategory.WordLower && nextCategory === CharBoundaryCategory.WordUpper) {
91 score += 1;
92 }
94 >
95 > score += getCategoryBoundaryScore(prevCategory);
96 > score += getCategoryBoundaryScore(nextCategory);
97 >
98 > return score;
99 > }
101 > public translateOffset(offset: number, preference: 'left' | 'right' = 'right'): Position {
102 > // find smallest i, so that lineBreakOffsets[i] <= offset using binary search linesSliceCharSequence.ts
103 > const i = findLastIdxMonotonous(this.firstElementOffsetByLineIdx, (value) => value <= offset);
104 > const lineOffset = offset - this.firstElementOffsetByLineIdx[i];
105 > return new Position(
106 > this.range.startLineNumber + i,
107 > 1 + this.lineStartOffsets[i] + lineOffset + ((lineOffset === 0 && preference === 'left') ? 0 : this.trimmedWsLengthsByLineIdx[i])
108 > );
109 > }
111 > public translateRange(range: OffsetRange): Range {
112 > const pos1 = this.translateOffset(range.start, 'right'); linesSliceCharSequence.ts
113 > const pos2 = this.translateOffset(range.endExclusive, 'left');
114 > if (pos2.isBefore(pos1)) {
115 return Range.fromPositions(pos2, pos2);
116 }
117 > return Range.fromPositions(pos1, pos2); linesSliceCharSequence.ts
118 > }
120 > /**
121 > * Finds the word that contains the character at the given offset
122 > */
123 > public findWordContaining(offset: number): OffsetRange | undefined {
124 > if (offset < 0 || offset >= this.elements.length) { linesSliceCharSequence.ts
125 return undefined;
126 }
128 > if (!isWordChar(this.elements[offset])) {
129 > return undefined;
130 > }
132 > // find start
133 > let start = offset;
134 > while (start > 0 && isWordChar(this.elements[start - 1])) { linesSliceCharSequence.ts
135 > start--; linesSliceCharSequence.ts
136 > }
138 > // find end
139 > let end = offset;
140 > while (end < this.elements.length && isWordChar(this.elements[end])) { linesSliceCharSequence.ts
142 > }
143 >
144 > return new OffsetRange(start, end);
147 > /** fooBar has the two sub-words foo and bar */
148 > public findSubWordContaining(offset: number): OffsetRange | undefined {
149 if (offset < 0 || offset >= this.elements.length) {
150 return undefined;
169 return new OffsetRange(start, end);
170 }
172 > public countLinesIn(range: OffsetRange): number {
173 > return this.translateOffset(range.endExclusive).lineNumber - this.translateOffset(range.start).lineNumber; linesSliceCharSequence.ts
174 > }
176 > public isStronglyEqual(offset1: number, offset2: number): boolean {
177 > return this.elements[offset1] === this.elements[offset2]; linesSliceCharSequence.ts
178 > }
180 > public extendToFullLines(range: OffsetRange): OffsetRange {
181 > const start = findLastMonotonous(this.firstElementOffsetByLineIdx, x => x <= range.start) ?? 0; linesSliceCharSequence.ts
182 > const end = findFirstMonotonous(this.firstElementOffsetByLineIdx, x => range.endExclusive <= x) ?? this.elements.length;
183 > return new OffsetRange(start, end);
184 > }
186 >
187 > function isWordChar(charCode: number): boolean { linesSliceCharSequence.ts
188 > return charCode >= CharCode.a && charCode <= CharCode.z
189 > || charCode >= CharCode.A && charCode <= CharCode.Z
190 > || charCode >= CharCode.Digit0 && charCode <= CharCode.Digit9;
191 > }
193 function isUpperCase(charCode: number): boolean {
194 return charCode >= CharCode.A && charCode <= CharCode.Z;
195 }
197 > const enum CharBoundaryCategory {
198 > WordLower,
199 > WordUpper,
200 > WordNumber,
201 > End,
202 > Other,
203 > Separator,
204 > Space,
205 > LineBreakCR,
206 > LineBreakLF,
207 > }
208 >
209 > const score: Record<CharBoundaryCategory, number> = {
210 > [CharBoundaryCategory.WordLower]: 0,
211 > [CharBoundaryCategory.WordUpper]: 0,
212 > [CharBoundaryCategory.WordNumber]: 0,
213 > [CharBoundaryCategory.End]: 10,
214 > [CharBoundaryCategory.Other]: 2,
215 > [CharBoundaryCategory.Separator]: 30,
216 > [CharBoundaryCategory.Space]: 3,
217 > [CharBoundaryCategory.LineBreakCR]: 10,
218 > [CharBoundaryCategory.LineBreakLF]: 10,
219 > };
220 >
221 > function getCategoryBoundaryScore(category: CharBoundaryCategory): number { linesSliceCharSequence.ts
222 > return score[category];
223 > }
225 > function getCategory(charCode: number): CharBoundaryCategory { linesSliceCharSequence.ts
226 > if (charCode === CharCode.LineFeed) {
227 > return CharBoundaryCategory.LineBreakLF; linesSliceCharSequence.ts
228 > } else if (charCode === CharCode.CarriageReturn) { linesSliceCharSequence.ts
229 return CharBoundaryCategory.LineBreakCR;
230 > } else if (isSpace(charCode)) { linesSliceCharSequence.ts
231 > return CharBoundaryCategory.Space; linesSliceCharSequence.ts
232 > } else if (charCode >= CharCode.a && charCode <= CharCode.z) { linesSliceCharSequence.ts
233 > return CharBoundaryCategory.WordLower; linesSliceCharSequence.ts
234 > } else if (charCode >= CharCode.A && charCode <= CharCode.Z) { linesSliceCharSequence.ts
235 return CharBoundaryCategory.WordUpper;
236 > } else if (charCode >= CharCode.Digit0 && charCode <= CharCode.Digit9) { linesSliceCharSequence.ts
237 return CharBoundaryCategory.WordNumber;
238 > } else if (charCode === -1) { linesSliceCharSequence.ts
239 > return CharBoundaryCategory.End; linesSliceCharSequence.ts
240 > } else if (charCode === CharCode.Comma || charCode === CharCode.Semicolon) { linesSliceCharSequence.ts
241 > return CharBoundaryCategory.Separator; linesSliceCharSequence.ts
242 > } else { linesSliceCharSequence.ts
243 > return CharBoundaryCategory.Other; linesSliceCharSequence.ts
244 > }
246
src/vs/editor/common/services/textModelSync/textModelSync.impl.ts 196 covered LOC · 48 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelSync.impl.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 { IntervalTimer } from '../../../../base/common/async.js';
7 > import { Disposable, DisposableStore, dispose, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
8 > import { URI } from '../../../../base/common/uri.js';
9 > import { IWebWorkerClient, IWebWorkerServer } from '../../../../base/common/worker/webWorker.js';
10 > import { IPosition, Position } from '../../core/position.js';
11 > import { IRange, Range } from '../../core/range.js';
12 > import { ensureValidWordDefinition, getWordAtText, IWordAtPosition } from '../../core/wordHelper.js';
13 > import { IDocumentColorComputerTarget } from '../../languages/defaultDocumentColorsComputer.js';
14 > import { ILinkComputerTarget } from '../../languages/linkComputer.js';
15 > import { MirrorTextModel as BaseMirrorModel, IModelChangedEvent } from '../../model/mirrorTextModel.js';
16 > import { IMirrorModel, IWordRange } from '../editorWebWorker.js';
17 > import { IModelService } from '../model.js';
18 > import { IRawModelData, IWorkerTextModelSyncChannelServer } from './textModelSync.protocol.js';
19 >
20 > /**
21 > * Stop syncing a model to the worker if it was not needed for 1 min.
22 > */
23 > export const STOP_SYNC_MODEL_DELTA_TIME_MS = 60 * 1000;
24 >
25 > export const WORKER_TEXT_MODEL_SYNC_CHANNEL = 'workerTextModelSync';
26 >
27 > export class WorkerTextModelSyncClient extends Disposable {
28 >
29 > public static create(workerClient: IWebWorkerClient<unknown>, modelService: IModelService): WorkerTextModelSyncClient {
30 > return new WorkerTextModelSyncClient(
31 > workerClient.getChannel<IWorkerTextModelSyncChannelServer>(WORKER_TEXT_MODEL_SYNC_CHANNEL),
32 > modelService
33 > );
34 > }
35 >
36 > private readonly _proxy: IWorkerTextModelSyncChannelServer;
37 > private readonly _modelService: IModelService;
38 > private _syncedModels: { [modelUrl: string]: IDisposable } = Object.create(null);
39 > private _syncedModelsLastUsedTime: { [modelUrl: string]: number } = Object.create(null);
40 >
41 > constructor(proxy: IWorkerTextModelSyncChannelServer, modelService: IModelService, keepIdleModels: boolean = false) {
42 super();
43 this._proxy = proxy;
50 }
51 }
53 > public override dispose(): void {
54 for (const modelUrl in this._syncedModels) {
55 dispose(this._syncedModels[modelUrl]);
59 super.dispose();
60 }
62 > public ensureSyncedResources(resources: URI[], forceLargeModels: boolean = false): void {
63 for (const resource of resources) {
64 const resourceStr = resource.toString();
72 }
73 }
75 > private _checkStopModelSync(): void {
76 const currentTime = (new Date()).getTime();
77
88 }
89 }
91 > private _beginModelSync(resource: URI, forceLargeModels: boolean): void {
92 const model = this._modelService.getModel(resource);
93 if (!model) {
120 this._syncedModels[modelUrl] = toDispose;
121 }
123 > private _stopModelSync(modelUrl: string): void {
124 const toDispose = this._syncedModels[modelUrl];
125 delete this._syncedModels[modelUrl];
127 dispose(toDispose);
128 }
130 >
131 > export class WorkerTextModelSyncServer implements IWorkerTextModelSyncChannelServer {
132 >
133 > private readonly _models: { [uri: string]: MirrorModel };
134 >
135 > constructor() {
136 > this._models = Object.create(null);
137 > }
138 >
139 > public bindToServer(workerServer: IWebWorkerServer): void {
140 workerServer.setChannel(WORKER_TEXT_MODEL_SYNC_CHANNEL, this);
141 }
143 > public getModel(uri: string): ICommonModel | undefined {
144 > return this._models[uri];
145 > }
146 >
147 > public getModels(): ICommonModel[] {
148 const all: MirrorModel[] = [];
149 Object.keys(this._models).forEach((key) => all.push(this._models[key]));
150 return all;
151 }
153 > $acceptNewModel(data: IRawModelData): void {
154 > this._models[data.url] = new MirrorModel(URI.parse(data.url), data.lines, data.EOL, data.versionId);
155 > }
156 >
157 > $acceptModelChanged(uri: string, e: IModelChangedEvent): void {
158 if (!this._models[uri]) {
159 return;
162 model.onEvents(e);
163 }
165 > $acceptRemovedModel(uri: string): void {
166 if (!this._models[uri]) {
167 return;
169 delete this._models[uri];
170 }
172 >
173 > export class MirrorModel extends BaseMirrorModel implements ICommonModel {
174 >
175 > public get uri(): URI {
176 > return this._uri; textModelSync.impl.ts
177 > }
179 > public get eol(): string {
180 > return this._eol; textModelSync.impl.ts
181 > }
183 > public getValue(): string {
184 > return this.getText(); textModelSync.impl.ts
185 > }
187 > public findMatches(regex: RegExp): RegExpMatchArray[] {
188 const matches = [];
189 for (let i = 0; i < this._lines.length; i++) {
200 return matches;
201 }
203 > public getLinesContent(): string[] {
204 return this._lines.slice(0);
205 }
207 > public getLineCount(): number {
208 return this._lines.length;
209 }
211 > public getLineContent(lineNumber: number): string {
212 return this._lines[lineNumber - 1];
213 }
215 > public getWordAtPosition(position: IPosition, wordDefinition: RegExp): Range | null {
216
217 const wordAtText = getWordAtText(
228 return null;
229 }
231 > public getWordUntilPosition(position: IPosition, wordDefinition: RegExp): IWordAtPosition {
232 const wordAtPosition = this.getWordAtPosition(position, wordDefinition);
233 if (!wordAtPosition) {
244 };
245 }
247 >
248 > public words(wordDefinition: RegExp): Iterable<string> {
249
250 const lines = this._lines;
277 };
278 }
280 > public getLineWords(lineNumber: number, wordDefinition: RegExp): IWordAtPosition[] {
281 const content = this._lines[lineNumber - 1];
282 const ranges = this._wordenize(content, wordDefinition);
291 return words;
292 }
294 > private _wordenize(content: string, wordDefinition: RegExp): IWordRange[] {
295 const result: IWordRange[] = [];
296 let match: RegExpExecArray | null;
307 return result;
308 }
310 > public getValueInRange(range: IRange): string {
311 > range = this._validateRange(range); textModelSync.impl.ts
312 >
313 > if (range.startLineNumber === range.endLineNumber) {
314 return this._lines[range.startLineNumber - 1].substring(range.startColumn - 1, range.endColumn - 1);
315 }
317 > const lineEnding = this._eol;
318 > const startLineIndex = range.startLineNumber - 1;
319 > const endLineIndex = range.endLineNumber - 1;
320 > const resultLines: string[] = [];
321 >
322 > resultLines.push(this._lines[startLineIndex].substring(range.startColumn - 1));
323 > for (let i = startLineIndex + 1; i < endLineIndex; i++) {
324 > resultLines.push(this._lines[i]); textModelSync.impl.ts
325 > }
326 > resultLines.push(this._lines[endLineIndex].substring(0, range.endColumn - 1)); textModelSync.impl.ts
327 >
328 > return resultLines.join(lineEnding);
331 > public offsetAt(position: IPosition): number {
332 position = this._validatePosition(position);
333 this._ensureLineStarts();
334 return this._lineStarts!.getPrefixSum(position.lineNumber - 2) + (position.column - 1);
335 }
337 > public positionAt(offset: number): IPosition {
338 offset = Math.floor(offset);
339 offset = Math.max(0, offset);
349 };
350 }
352 > private _validateRange(range: IRange): IRange {
354 > const start = this._validatePosition({ lineNumber: range.startLineNumber, column: range.startColumn });
355 > const end = this._validatePosition({ lineNumber: range.endLineNumber, column: range.endColumn });
356 >
357 > if (start.lineNumber !== range.startLineNumber
358 > || start.column !== range.startColumn
359 > || end.lineNumber !== range.endLineNumber
360 > || end.column !== range.endColumn) {
362 > return {
363 > startLineNumber: start.lineNumber,
364 > startColumn: start.column,
365 > endLineNumber: end.lineNumber,
366 > endColumn: end.column
367 > };
368 > }
369
370 return range;
373 > private _validatePosition(position: IPosition): IPosition {
374 > if (!Position.isIPosition(position)) { textModelSync.impl.ts
375 throw new Error('bad position');
376 }
377 > let { lineNumber, column } = position; textModelSync.impl.ts
378 > let hasChanged = false;
379 >
380 > if (lineNumber < 1) {
381 lineNumber = 1;
382 column = 1;
383 hasChanged = true;
384
385 > } else if (lineNumber > this._lines.length) { textModelSync.impl.ts
386 > lineNumber = this._lines.length; textModelSync.impl.ts
387 > column = this._lines[lineNumber - 1].length + 1;
388 > hasChanged = true;
389 >
390 > } else { textModelSync.impl.ts
391 > const maxCharacter = this._lines[lineNumber - 1].length + 1;
392 > if (column < 1) {
393 column = 1;
394 hasChanged = true;
395 }
396 > else if (column > maxCharacter) { textModelSync.impl.ts
397 column = maxCharacter;
398 hasChanged = true;
399 }
401 >
402 > if (!hasChanged) {
403 > return position;
404 > } else {
405 > return { lineNumber, column }; textModelSync.impl.ts
406 > }
409 >
410 > export interface ICommonModel extends ILinkComputerTarget, IDocumentColorComputerTarget, IMirrorModel {
411 > uri: URI;
412 > version: number;
413 > eol: string;
414 > getValue(): string;
415 >
416 > getLinesContent(): string[];
417 > getLineCount(): number;
418 > getLineContent(lineNumber: number): string;
419 > getLineWords(lineNumber: number, wordDefinition: RegExp): IWordAtPosition[];
420 > words(wordDefinition: RegExp): Iterable<string>;
421 > getWordUntilPosition(position: IPosition, wordDefinition: RegExp): IWordAtPosition;
422 > getValueInRange(range: IRange): string;
423 > getWordAtPosition(position: IPosition, wordDefinition: RegExp): Range | null;
424 > offsetAt(position: IPosition): number;
425 > positionAt(offset: number): IPosition;
426 > findMatches(regex: RegExp): RegExpMatchArray[];
427 > }
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/editor/common/diff/legacyLinesDiffComputer.ts 173 covered LOC · 28 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- legacyLinesDiffComputer.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 '../../../base/common/charCode.js';
7 > import { IDiffChange, ISequence, LcsDiff, IDiffResult } from '../../../base/common/diff/diff.js';
8 > import { ILinesDiffComputer, ILinesDiffComputerOptions, LinesDiff } from './linesDiffComputer.js';
9 > import { RangeMapping, DetailedLineRangeMapping } from './rangeMapping.js';
10 > import * as strings from '../../../base/common/strings.js';
11 > import { Range } from '../core/range.js';
12 > import { assertFn, checkAdjacentItems } from '../../../base/common/assert.js';
13 > import { LineRange } from '../core/ranges/lineRange.js';
14 >
15 > const MINIMUM_MATCHING_CHARACTER_LENGTH = 3;
16 >
17 > export class LegacyLinesDiffComputer implements ILinesDiffComputer {
18 > computeDiff(originalLines: string[], modifiedLines: string[], options: ILinesDiffComputerOptions): LinesDiff {
19 const diffComputer = new DiffComputer(originalLines, modifiedLines, {
20 maxComputationTime: options.maxComputationTimeMs,
79 return new LinesDiff(changes, [], result.quitEarly);
80 }
82 >
83 > export interface IDiffComputationResult {
84 > quitEarly: boolean;
85 > identical: boolean;
86 >
87 > /**
88 > * The changes as (legacy) line change array.
89 > * @deprecated Use `changes2` instead.
90 > */
91 > changes: ILineChange[];
92 >
93 > /**
94 > * The changes as (modern) line range mapping array.
95 > */
96 > changes2: readonly DetailedLineRangeMapping[];
97 > }
98 >
99 > /**
100 > * A change
101 > */
102 > export interface IChange {
103 > readonly originalStartLineNumber: number;
104 > readonly originalEndLineNumber: number;
105 > readonly modifiedStartLineNumber: number;
106 > readonly modifiedEndLineNumber: number;
107 > }
108 >
109 > /**
110 > * A character level change.
111 > */
112 > export interface ICharChange extends IChange {
113 > readonly originalStartColumn: number;
114 > readonly originalEndColumn: number;
115 > readonly modifiedStartColumn: number;
116 > readonly modifiedEndColumn: number;
117 > }
118 >
119 > /**
120 > * A line change
121 > */
122 > export interface ILineChange extends IChange {
123 > readonly charChanges: ICharChange[] | undefined;
124 > }
125 >
126 > export interface IDiffComputerResult {
127 > quitEarly: boolean;
128 > changes: ILineChange[];
129 > }
130 >
131 function computeDiff(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: () => boolean, pretty: boolean): IDiffResult {
132 const diffAlgo = new LcsDiff(originalSequence, modifiedSequence, continueProcessingPredicate);
133 return diffAlgo.ComputeDiff(pretty);
134 }
136 > class LineSequence implements ISequence {
137 >
138 > public readonly lines: string[];
139 > private readonly _startColumns: number[];
140 > private readonly _endColumns: number[];
141 >
142 > constructor(lines: string[]) {
143 const startColumns: number[] = [];
144 const endColumns: number[] = [];
151 this._endColumns = endColumns;
152 }
154 > public getElements(): Int32Array | number[] | string[] {
155 const elements: string[] = [];
156 for (let i = 0, len = this.lines.length; i < len; i++) {
159 return elements;
160 }
162 > public getStrictElement(index: number): string {
163 return this.lines[index];
164 }
166 > public getStartLineNumber(i: number): number {
167 return i + 1;
168 }
170 > public getEndLineNumber(i: number): number {
171 return i + 1;
172 }
174 > public createCharSequence(shouldIgnoreTrimWhitespace: boolean, startIndex: number, endIndex: number): CharSequence {
175 const charCodes: number[] = [];
176 const lineNumbers: number[] = [];
197 return new CharSequence(charCodes, lineNumbers, columns);
198 }
200 >
201 > class CharSequence implements ISequence {
202 >
203 > private readonly _charCodes: number[];
204 > private readonly _lineNumbers: number[];
205 > private readonly _columns: number[];
206 >
207 > constructor(charCodes: number[], lineNumbers: number[], columns: number[]) {
208 this._charCodes = charCodes;
209 this._lineNumbers = lineNumbers;
210 this._columns = columns;
211 }
213 > public toString() {
214 return (
215 '[' + this._charCodes.map((s, idx) => (s === CharCode.LineFeed ? '\\n' : String.fromCharCode(s)) + `-(${this._lineNumbers[idx]},${this._columns[idx]})`).join(', ') + ']'
216 );
217 }
219 > private _assertIndex(index: number, arr: number[]): void {
220 if (index < 0 || index >= arr.length) {
221 throw new Error(`Illegal index`);
222 }
223 }
225 > public getElements(): Int32Array | number[] | string[] {
226 return this._charCodes;
227 }
229 > public getStartLineNumber(i: number): number {
230 if (i > 0 && i === this._lineNumbers.length) {
231 // the start line number of the element after the last element
237 return this._lineNumbers[i];
238 }
240 > public getEndLineNumber(i: number): number {
241 if (i === -1) {
242 // the end line number of the element before the first element
251 return this._lineNumbers[i];
252 }
254 > public getStartColumn(i: number): number {
255 if (i > 0 && i === this._columns.length) {
256 // the start column of the element after the last element
261 return this._columns[i];
262 }
264 > public getEndColumn(i: number): number {
265 if (i === -1) {
266 // the end column of the element before the first element
275 return this._columns[i] + 1;
276 }
278 >
279 > class CharChange implements ICharChange {
280 >
281 > public originalStartLineNumber: number;
282 > public originalStartColumn: number;
283 > public originalEndLineNumber: number;
284 > public originalEndColumn: number;
285 >
286 > public modifiedStartLineNumber: number;
287 > public modifiedStartColumn: number;
288 > public modifiedEndLineNumber: number;
289 > public modifiedEndColumn: number;
290 >
291 > constructor(
292 originalStartLineNumber: number,
293 originalStartColumn: number,
308 this.modifiedEndColumn = modifiedEndColumn;
309 }
311 > public static createFromDiffChange(diffChange: IDiffChange, originalCharSequence: CharSequence, modifiedCharSequence: CharSequence): CharChange {
312 const originalStartLineNumber = originalCharSequence.getStartLineNumber(diffChange.originalStart);
313 const originalStartColumn = originalCharSequence.getStartColumn(diffChange.originalStart);
325 );
326 }
328 >
329 function postProcessCharChanges(rawChanges: IDiffChange[]): IDiffChange[] {
330 if (rawChanges.length <= 1) {
356 return result;
357 }
359 > class LineChange implements ILineChange {
360 > public originalStartLineNumber: number;
361 > public originalEndLineNumber: number;
362 > public modifiedStartLineNumber: number;
363 > public modifiedEndLineNumber: number;
364 > public charChanges: CharChange[] | undefined;
365 >
366 > constructor(
367 originalStartLineNumber: number,
368 originalEndLineNumber: number,
377 this.charChanges = charChanges;
378 }
380 > public static createFromDiffResult(shouldIgnoreTrimWhitespace: boolean, diffChange: IDiffChange, originalLineSequence: LineSequence, modifiedLineSequence: LineSequence, continueCharDiff: () => boolean, shouldComputeCharChanges: boolean, shouldPostProcessCharChanges: boolean): LineChange {
381 let originalStartLineNumber: number;
382 let originalEndLineNumber: number;
422 return new LineChange(originalStartLineNumber, originalEndLineNumber, modifiedStartLineNumber, modifiedEndLineNumber, charChanges);
423 }
425 >
426 > export interface IDiffComputerOpts {
427 > shouldComputeCharChanges: boolean;
428 > shouldPostProcessCharChanges: boolean;
429 > shouldIgnoreTrimWhitespace: boolean;
430 > shouldMakePrettyDiff: boolean;
431 > maxComputationTime: number;
432 > }
433 >
434 > export class DiffComputer {
435 >
436 > private readonly shouldComputeCharChanges: boolean;
437 > private readonly shouldPostProcessCharChanges: boolean;
438 > private readonly shouldIgnoreTrimWhitespace: boolean;
439 > private readonly shouldMakePrettyDiff: boolean;
440 > private readonly originalLines: string[];
441 > private readonly modifiedLines: string[];
442 > private readonly original: LineSequence;
443 > private readonly modified: LineSequence;
444 > private readonly continueLineDiff: () => boolean;
445 > private readonly continueCharDiff: () => boolean;
446 >
447 > constructor(originalLines: string[], modifiedLines: string[], opts: IDiffComputerOpts) {
448 this.shouldComputeCharChanges = opts.shouldComputeCharChanges;
449 this.shouldPostProcessCharChanges = opts.shouldPostProcessCharChanges;
458 this.continueCharDiff = createContinueProcessingPredicate(opts.maxComputationTime === 0 ? 0 : Math.min(opts.maxComputationTime, 5000)); // never run after 5s for character changes...
459 }
461 > public computeDiff(): IDiffComputerResult {
462
463 if (this.original.lines.length === 1 && this.original.lines[0].length === 0) {
596 };
597 }
599 > private _pushTrimWhitespaceCharChange(
600 result: LineChange[],
601 originalLineNumber: number, originalStartColumn: number, originalEndColumn: number,
620 ));
621 }
623 > private _mergeTrimWhitespaceCharChange(
624 result: LineChange[],
625 originalLineNumber: number, originalStartColumn: number, originalEndColumn: number,
662 return false;
663 }
665 >
666 function getFirstNonBlankColumn(txt: string, defaultValue: number): number {
667 const r = strings.firstNonWhitespaceIndex(txt);
671 return r + 1;
672 }
674 function getLastNonBlankColumn(txt: string, defaultValue: number): number {
675 const r = strings.lastNonWhitespaceIndex(txt);
679 return r + 2;
680 }
682 function createContinueProcessingPredicate(maximumRuntime: number): () => boolean {
683 if (maximumRuntime === 0) {
src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm.ts 168 covered LOC · 44 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- diffAlgorithm.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 { forEachAdjacent } from '../../../../../base/common/arrays.js';
7 > import { BugIndicatingError } from '../../../../../base/common/errors.js';
8 > import { OffsetRange } from '../../../core/ranges/offsetRange.js';
9 >
10 > /**
11 > * Represents a synchronous diff algorithm. Should be executed in a worker.
12 > */
13 > export interface IDiffAlgorithm {
14 > compute(sequence1: ISequence, sequence2: ISequence, timeout?: ITimeout): DiffAlgorithmResult;
15 > }
16 >
17 > export class DiffAlgorithmResult {
18 > static trivial(seq1: ISequence, seq2: ISequence): DiffAlgorithmResult {
19 > return new DiffAlgorithmResult([new SequenceDiff(OffsetRange.ofLength(seq1.length), OffsetRange.ofLength(seq2.length))], false);
20 > }
21 >
22 > static trivialTimedOut(seq1: ISequence, seq2: ISequence): DiffAlgorithmResult {
23 return new DiffAlgorithmResult([new SequenceDiff(OffsetRange.ofLength(seq1.length), OffsetRange.ofLength(seq2.length))], true);
24 }
26 > constructor(
27 > public readonly diffs: SequenceDiff[], diffAlgorithm.ts
28 > /**
29 > * Indicates if the time out was reached.
30 > * In that case, the diffs might be an approximation and the user should be asked to rerun the diff with more time.
31 > */
32 > public readonly hitTimeout: boolean,
33 > ) { }
35 >
36 > export class SequenceDiff {
37 > public static invert(sequenceDiffs: SequenceDiff[], doc1Length: number): SequenceDiff[] {
38 > const result: SequenceDiff[] = [];
39 > forEachAdjacent(sequenceDiffs, (a, b) => {
40 > result.push(SequenceDiff.fromOffsetPairs(
41 > a ? a.getEndExclusives() : OffsetPair.zero,
42 > b ? b.getStarts() : new OffsetPair(doc1Length, (a ? a.seq2Range.endExclusive - a.seq1Range.endExclusive : 0) + doc1Length)
43 > ));
44 > });
45 > return result;
46 > }
47 >
48 > public static fromOffsetPairs(start: OffsetPair, endExclusive: OffsetPair): SequenceDiff {
49 > return new SequenceDiff( diffAlgorithm.ts
50 > new OffsetRange(start.offset1, endExclusive.offset1),
51 > new OffsetRange(start.offset2, endExclusive.offset2),
52 > );
53 > }
55 > public static assertSorted(sequenceDiffs: SequenceDiff[]): void {
56 let last: SequenceDiff | undefined = undefined;
57 for (const cur of sequenceDiffs) {
64 }
65 }
67 > constructor(
68 > public readonly seq1Range: OffsetRange, diffAlgorithm.ts
69 > public readonly seq2Range: OffsetRange,
70 > ) { }
72 > public swap(): SequenceDiff {
73 > return new SequenceDiff(this.seq2Range, this.seq1Range); diffAlgorithm.ts
74 > }
76 > public toString(): string {
77 return `${this.seq1Range} <-> ${this.seq2Range}`;
78 }
80 > public join(other: SequenceDiff): SequenceDiff {
81 > return new SequenceDiff(this.seq1Range.join(other.seq1Range), this.seq2Range.join(other.seq2Range)); diffAlgorithm.ts
82 > }
84 > public delta(offset: number): SequenceDiff {
85 > if (offset === 0) { diffAlgorithm.ts
86 > return this; diffAlgorithm.ts
87 > }
88 > return new SequenceDiff(this.seq1Range.delta(offset), this.seq2Range.delta(offset)); diffAlgorithm.ts
91 > public deltaStart(offset: number): SequenceDiff {
92 > if (offset === 0) { diffAlgorithm.ts
93 return this;
94 }
95 > return new SequenceDiff(this.seq1Range.deltaStart(offset), this.seq2Range.deltaStart(offset)); diffAlgorithm.ts
96 > }
98 > public deltaEnd(offset: number): SequenceDiff {
99 > if (offset === 0) { diffAlgorithm.ts
100 return this;
101 }
102 > return new SequenceDiff(this.seq1Range.deltaEnd(offset), this.seq2Range.deltaEnd(offset)); diffAlgorithm.ts
103 > }
105 > public intersectsOrTouches(other: SequenceDiff): boolean {
106 return this.seq1Range.intersectsOrTouches(other.seq1Range) || this.seq2Range.intersectsOrTouches(other.seq2Range);
107 }
109 > public intersect(other: SequenceDiff): SequenceDiff | undefined {
110 > const i1 = this.seq1Range.intersect(other.seq1Range); diffAlgorithm.ts
111 > const i2 = this.seq2Range.intersect(other.seq2Range);
112 > if (!i1 || !i2) {
113 return undefined;
114 }
115 > return new SequenceDiff(i1, i2); diffAlgorithm.ts
116 > }
118 > public getStarts(): OffsetPair {
119 > return new OffsetPair(this.seq1Range.start, this.seq2Range.start); diffAlgorithm.ts
120 > }
122 > public getEndExclusives(): OffsetPair {
123 > return new OffsetPair(this.seq1Range.endExclusive, this.seq2Range.endExclusive); diffAlgorithm.ts
124 > }
126 >
127 > export class OffsetPair {
128 > public static readonly zero = new OffsetPair(0, 0);
129 > public static readonly max = new OffsetPair(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
130 >
131 > constructor(
132 > public readonly offset1: number,
133 > public readonly offset2: number,
134 > ) {
135 > }
136 >
137 > public toString(): string {
138 return `${this.offset1} <-> ${this.offset2}`;
139 }
141 > public delta(offset: number): OffsetPair {
142 > if (offset === 0) { diffAlgorithm.ts
143 return this;
144 }
145 > return new OffsetPair(this.offset1 + offset, this.offset2 + offset); diffAlgorithm.ts
146 > }
148 > public equals(other: OffsetPair): boolean {
149 > return this.offset1 === other.offset1 && this.offset2 === other.offset2; diffAlgorithm.ts
150 > }
152 >
153 > export interface ISequence {
154 > getElement(offset: number): number;
155 > get length(): number;
156 >
157 > /**
158 > * The higher the score, the better that offset can be used to split the sequence.
159 > * Is used to optimize insertions.
160 > * Must not be negative.
161 > */
162 > getBoundaryScore?(length: number): number;
163 >
164 > /**
165 > * For line sequences, getElement returns a number representing trimmed lines.
166 > * This however checks equality for the original lines.
167 > * It prevents shifting to less matching lines.
168 > */
169 > isStronglyEqual(offset1: number, offset2: number): boolean;
170 > }
171 >
172 > export interface ITimeout {
173 > isValid(): boolean;
174 > }
175 >
176 > export class InfiniteTimeout implements ITimeout {
177 > public static instance = new InfiniteTimeout();
178 >
179 > isValid(): boolean {
180 > return true; diffAlgorithm.ts
181 > }
183 >
184 > export class DateTimeout implements ITimeout {
185 > private readonly startTime = Date.now();
186 > private valid = true;
187 >
188 > constructor(private timeout: number) {
189 if (timeout <= 0) {
190 throw new BugIndicatingError('timeout must be positive');
191 }
192 }
194 > // Recommendation: Set a log-point `{this.disable()}` in the body
195 > public isValid(): boolean {
196 const valid = Date.now() - this.startTime < this.timeout;
197 if (!valid && this.valid) {
200 return this.valid;
201 }
203 > public disable() {
204 this.timeout = Number.MAX_SAFE_INTEGER;
205 this.isValid = () => true;
206 this.valid = true;
207 }
src/vs/editor/common/core/ranges/lineRange.ts 162 covered LOC · 44 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lineRange.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 '../../../../base/common/errors.js';
7 > import { OffsetRange } from './offsetRange.js';
8 > import { IRange, Range } from '../range.js';
9 > import { findFirstIdxMonotonousOrArrLen, findLastIdxMonotonous, findLastMonotonous } from '../../../../base/common/arraysFind.js';
10 > import { Comparator, compareBy, numberComparator } from '../../../../base/common/arrays.js';
11 >
12 > /**
13 > * A range of lines (1-based).
14 > */
15 > export class LineRange {
16 > public static ofLength(startLineNumber: number, length: number): LineRange {
17 return new LineRange(startLineNumber, startLineNumber + length);
18 }
20 > public static fromRange(range: IRange): LineRange {
21 return new LineRange(range.startLineNumber, range.endLineNumber);
22 }
24 > public static fromRangeInclusive(range: IRange): LineRange {
25 return new LineRange(range.startLineNumber, range.endLineNumber + 1);
26 }
28 > public static readonly compareByStart: Comparator<LineRange> = compareBy(l => l.startLineNumber, numberComparator);
29 >
30 > public static subtract(a: LineRange, b: LineRange | undefined): LineRange[] {
31 if (!b) {
32 return [a];
45 }
46 }
48 > /**
49 > * @param lineRanges An array of arrays of of sorted line ranges.
50 > */
51 > public static joinMany(lineRanges: readonly (readonly LineRange[])[]): readonly LineRange[] {
52 if (lineRanges.length === 0) {
53 return [];
59 return result.ranges;
60 }
62 > public static join(lineRanges: LineRange[]): LineRange {
63 if (lineRanges.length === 0) {
64 throw new BugIndicatingError('lineRanges cannot be empty');
72 return new LineRange(startLineNumber, endLineNumberExclusive);
73 }
75 > /**
76 > * @internal
77 > */
78 > public static deserialize(lineRange: ISerializedLineRange): LineRange {
79 return new LineRange(lineRange[0], lineRange[1]);
80 }
82 > /**
83 > * The start line number.
84 > */
85 > public readonly startLineNumber: number;
86 >
87 > /**
88 > * The end line number (exclusive).
89 > */
90 > public readonly endLineNumberExclusive: number;
91 >
92 > constructor(
93 > startLineNumber: number, lineRange.ts
94 > endLineNumberExclusive: number,
95 > ) {
96 > if (startLineNumber > endLineNumberExclusive) {
97 throw new BugIndicatingError(`startLineNumber ${startLineNumber} cannot be after endLineNumberExclusive ${endLineNumberExclusive}`);
98 }
99 > this.startLineNumber = startLineNumber; lineRange.ts
100 > this.endLineNumberExclusive = endLineNumberExclusive;
101 > }
102 > lineRange.ts
103 > /**
104 > * Indicates if this line range contains the given line number.
105 > */
106 > public contains(lineNumber: number): boolean {
107 return this.startLineNumber <= lineNumber && lineNumber < this.endLineNumberExclusive;
108 }
109 > lineRange.ts
110 > public containsRange(range: LineRange): boolean {
111 return this.startLineNumber <= range.startLineNumber && range.endLineNumberExclusive <= this.endLineNumberExclusive;
112 }
113 > lineRange.ts
114 > /**
115 > * Indicates if this line range is empty.
116 > */
117 > get isEmpty(): boolean {
118 return this.startLineNumber === this.endLineNumberExclusive;
119 }
120 > lineRange.ts
121 > /**
122 > * Moves this line range by the given offset of line numbers.
123 > */
124 > public delta(offset: number): LineRange {
125 return new LineRange(this.startLineNumber + offset, this.endLineNumberExclusive + offset);
126 }
127 > lineRange.ts
128 > public deltaLength(offset: number): LineRange {
129 return new LineRange(this.startLineNumber, this.endLineNumberExclusive + offset);
130 }
131 > lineRange.ts
132 > /**
133 > * The number of lines this line range spans.
134 > */
135 > public get length(): number {
136 return this.endLineNumberExclusive - this.startLineNumber;
137 }
138 > lineRange.ts
139 > /**
140 > * Creates a line range that combines this and the given line range.
141 > */
142 > public join(other: LineRange): LineRange {
143 > return new LineRange( lineRange.ts
144 > Math.min(this.startLineNumber, other.startLineNumber),
145 > Math.max(this.endLineNumberExclusive, other.endLineNumberExclusive)
146 > );
147 > }
148 > lineRange.ts
149 > public toString(): string {
150 return `[${this.startLineNumber},${this.endLineNumberExclusive})`;
151 }
152 > lineRange.ts
153 > /**
154 > * The resulting range is empty if the ranges do not intersect, but touch.
155 > * If the ranges don't even touch, the result is undefined.
156 > */
157 > public intersect(other: LineRange): LineRange | undefined {
158 const startLineNumber = Math.max(this.startLineNumber, other.startLineNumber);
159 const endLineNumberExclusive = Math.min(this.endLineNumberExclusive, other.endLineNumberExclusive);
163 return undefined;
164 }
165 > lineRange.ts
166 > public intersectsStrict(other: LineRange): boolean {
167 return this.startLineNumber < other.endLineNumberExclusive && other.startLineNumber < this.endLineNumberExclusive;
168 }
169 > lineRange.ts
170 > public intersectsOrTouches(other: LineRange): boolean {
171 > return this.startLineNumber <= other.endLineNumberExclusive && other.startLineNumber <= this.endLineNumberExclusive; lineRange.ts
172 > }
173 > lineRange.ts
174 > public equals(b: LineRange): boolean {
175 return this.startLineNumber === b.startLineNumber && this.endLineNumberExclusive === b.endLineNumberExclusive;
176 }
177 > lineRange.ts
178 > public toInclusiveRange(): Range | null {
179 if (this.isEmpty) {
180 return null;
182 return new Range(this.startLineNumber, 1, this.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER);
183 }
184 > lineRange.ts
185 > /**
186 > * @deprecated Using this function is discouraged because it might lead to bugs: The end position is not guaranteed to be a valid position!
187 > */
188 > public toExclusiveRange(): Range {
189 return new Range(this.startLineNumber, 1, this.endLineNumberExclusive, 1);
190 }
191 > lineRange.ts
192 > public mapToLineArray<T>(f: (lineNumber: number) => T): T[] {
193 const result: T[] = [];
194 for (let lineNumber = this.startLineNumber; lineNumber < this.endLineNumberExclusive; lineNumber++) {
197 return result;
198 }
199 > lineRange.ts
200 > public forEach(f: (lineNumber: number) => void): void {
201 for (let lineNumber = this.startLineNumber; lineNumber < this.endLineNumberExclusive; lineNumber++) {
202 f(lineNumber);
203 }
204 }
205 > lineRange.ts
206 > /**
207 > * @internal
208 > */
209 > public serialize(): ISerializedLineRange {
210 return [this.startLineNumber, this.endLineNumberExclusive];
211 }
212 > lineRange.ts
213 > /**
214 > * Converts this 1-based line range to a 0-based offset range (subtracts 1!).
215 > * @internal
216 > */
217 > public toOffsetRange(): OffsetRange {
218 return new OffsetRange(this.startLineNumber - 1, this.endLineNumberExclusive - 1);
219 }
220 > lineRange.ts
221 > public distanceToRange(other: LineRange): number {
222 if (this.endLineNumberExclusive <= other.startLineNumber) {
223 return other.startLineNumber - this.endLineNumberExclusive;
228 return 0;
229 }
230 > lineRange.ts
231 > public distanceToLine(lineNumber: number): number {
232 if (this.contains(lineNumber)) {
233 return 0;
238 return lineNumber - this.endLineNumberExclusive;
239 }
240 > lineRange.ts
241 > public addMargin(marginTop: number, marginBottom: number): LineRange {
242 return new LineRange(
243 this.startLineNumber - marginTop,
245 );
246 }
247 > } lineRange.ts
248 >
249 > export type ISerializedLineRange = [startLineNumber: number, endLineNumberExclusive: number];
250 >
251 >
252 > export class LineRangeSet {
253 > constructor(
254 /**
255 * Sorted by start line number.
259 ) {
260 }
261 > lineRange.ts
262 > get ranges(): readonly LineRange[] {
263 return this._normalizedRanges;
264 }
265 > lineRange.ts
266 > addRange(range: LineRange): void {
267 if (range.length === 0) {
268 return;
290 }
291 }
292 > lineRange.ts
293 > contains(lineNumber: number): boolean {
294 const rangeThatStartsBeforeEnd = findLastMonotonous(this._normalizedRanges, r => r.startLineNumber <= lineNumber);
295 return !!rangeThatStartsBeforeEnd && rangeThatStartsBeforeEnd.endLineNumberExclusive > lineNumber;
296 }
297 > lineRange.ts
298 > intersects(range: LineRange): boolean {
299 const rangeThatStartsBeforeEnd = findLastMonotonous(this._normalizedRanges, r => r.startLineNumber < range.endLineNumberExclusive);
300 return !!rangeThatStartsBeforeEnd && rangeThatStartsBeforeEnd.endLineNumberExclusive > range.startLineNumber;
301 }
302 > lineRange.ts
303 > getUnion(other: LineRangeSet): LineRangeSet {
304 if (this._normalizedRanges.length === 0) {
305 return other;
351 return new LineRangeSet(result);
352 }
353 > lineRange.ts
354 > /**
355 > * Subtracts all ranges in this set from `range` and returns the result.
356 > */
357 > subtractFrom(range: LineRange): LineRangeSet {
358 // idx of first element that touches range or that is after range
359 const joinRangeStartIdx = findFirstIdxMonotonousOrArrLen(this._normalizedRanges, r => r.endLineNumberExclusive >= range.startLineNumber);
380 return new LineRangeSet(result);
381 }
382 > lineRange.ts
383 > toString() {
384 return this._normalizedRanges.map(r => r.toString()).join(', ');
385 }
386 > lineRange.ts
387 > getIntersection(other: LineRangeSet): LineRangeSet {
388 const result: LineRange[] = [];
389
408 return new LineRangeSet(result);
409 }
410 > lineRange.ts
411 > getWithDelta(value: number): LineRangeSet {
412 return new LineRangeSet(this._normalizedRanges.map(r => r.delta(value)));
413 }
414 > } lineRange.ts
src/vs/base/common/buffer.ts 158 covered LOC · 42 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- buffer.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 { Lazy } from './lazy.js';
7 > import * as streams from './stream.js';
8 >
9 > interface NodeBuffer {
10 > allocUnsafe(size: number): Uint8Array;
11 > isBuffer(obj: unknown): obj is NodeBuffer;
12 > from(arrayBuffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8Array;
13 > from(data: string): Uint8Array;
14 > }
15 >
16 > declare const Buffer: NodeBuffer;
17 >
18 > const hasBuffer = (typeof Buffer !== 'undefined');
19 > const indexOfTable = new Lazy(() => new Uint8Array(256));
20 >
21 > let textEncoder: { encode: (input: string) => Uint8Array } | null;
22 > let textDecoder: { decode: (input: Uint8Array) => string } | null;
23 >
24 > export class VSBuffer {
25 >
26 > /**
27 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
28 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
29 > */
30 > static alloc(byteLength: number): VSBuffer {
31 if (hasBuffer) {
32 return new VSBuffer(Buffer.allocUnsafe(byteLength));
35 }
36 }
37 > buffer.ts
38 > /**
39 > * When running in a nodejs context, if `actual` is not a nodejs Buffer, the backing store for
40 > * the returned `VSBuffer` instance might use a nodejs Buffer allocated from node's Buffer pool,
41 > * which is not transferrable.
42 > */
43 > static wrap(actual: Uint8Array): VSBuffer {
44 if (hasBuffer && !(Buffer.isBuffer(actual))) {
45 // https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length
49 return new VSBuffer(actual);
50 }
51 > buffer.ts
52 > /**
53 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
54 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
55 > */
56 > static fromString(source: string, options?: { dontUseNodeBuffer?: boolean }): VSBuffer {
57 const dontUseNodeBuffer = options?.dontUseNodeBuffer || false;
58 if (!dontUseNodeBuffer && hasBuffer) {
65 }
66 }
67 > buffer.ts
68 > /**
69 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
70 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
71 > */
72 > static fromByteArray(source: number[]): VSBuffer {
73 const result = VSBuffer.alloc(source.length);
74 for (let i = 0, len = source.length; i < len; i++) {
77 return result;
78 }
79 > buffer.ts
80 > /**
81 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
82 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
83 > */
84 > static concat(buffers: VSBuffer[], totalLength?: number): VSBuffer {
85 if (typeof totalLength === 'undefined') {
86 totalLength = 0;
100 return ret;
101 }
102 > buffer.ts
103 > static isNativeBuffer(buffer: unknown): boolean {
104 return hasBuffer && Buffer.isBuffer(buffer);
105 }
106 > buffer.ts
107 > readonly buffer: Uint8Array;
108 > readonly byteLength: number;
109 >
110 > private constructor(buffer: Uint8Array) {
111 this.buffer = buffer;
112 this.byteLength = this.buffer.byteLength;
113 }
114 > buffer.ts
115 > /**
116 > * When running in a nodejs context, the backing store for the returned `VSBuffer` instance
117 > * might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
118 > */
119 > clone(): VSBuffer {
120 const result = VSBuffer.alloc(this.byteLength);
121 result.set(this);
122 return result;
123 }
124 > buffer.ts
125 > toString(): string {
126 if (hasBuffer) {
127 return this.buffer.toString();
133 }
134 }
135 > buffer.ts
136 > slice(start?: number, end?: number): VSBuffer {
137 // IMPORTANT: use subarray instead of slice because TypedArray#slice
138 // creates shallow copy and NodeBuffer#slice doesn't. The use of subarray
140 return new VSBuffer(this.buffer.subarray(start, end));
141 }
142 > buffer.ts
143 > set(array: VSBuffer, offset?: number): void;
144 > set(array: Uint8Array, offset?: number): void;
145 > set(array: ArrayBuffer, offset?: number): void;
146 > set(array: ArrayBufferView, offset?: number): void;
147 > set(array: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView, offset?: number): void;
148 > set(array: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView, offset?: number): void {
149 if (array instanceof VSBuffer) {
150 this.buffer.set(array.buffer, offset);
159 }
160 }
161 > buffer.ts
162 > readUInt32BE(offset: number): number {
163 return readUInt32BE(this.buffer, offset);
164 }
165 > buffer.ts
166 > writeUInt32BE(value: number, offset: number): void {
167 writeUInt32BE(this.buffer, value, offset);
168 }
169 > buffer.ts
170 > readUInt32LE(offset: number): number {
171 return readUInt32LE(this.buffer, offset);
172 }
173 > buffer.ts
174 > writeUInt32LE(value: number, offset: number): void {
175 writeUInt32LE(this.buffer, value, offset);
176 }
177 > buffer.ts
178 > readUInt8(offset: number): number {
179 return readUInt8(this.buffer, offset);
180 }
181 > buffer.ts
182 > writeUInt8(value: number, offset: number): void {
183 writeUInt8(this.buffer, value, offset);
184 }
185 > buffer.ts
186 > indexOf(subarray: VSBuffer | Uint8Array, offset = 0) {
187 return binaryIndexOf(this.buffer, subarray instanceof VSBuffer ? subarray.buffer : subarray, offset);
188 }
189 > buffer.ts
190 > equals(other: VSBuffer): boolean {
191 if (this === other) {
192 return true;
199 return this.buffer.every((value, index) => value === other.buffer[index]);
200 }
201 > } buffer.ts
202 >
203 > /**
204 > * Like String.indexOf, but works on Uint8Arrays.
205 > * Uses the boyer-moore-horspool algorithm to be reasonably speedy.
206 > */
207 > export function binaryIndexOf(haystack: Uint8Array, needle: Uint8Array, offset = 0): number {
208 const needleLen = needle.byteLength;
209 const haystackLen = haystack.byteLength;
248 return result;
249 }
250 > buffer.ts
251 > export function readUInt16LE(source: Uint8Array, offset: number): number {
252 return (
253 ((source[offset + 0] << 0) >>> 0) |
255 );
256 }
257 > buffer.ts
258 > export function writeUInt16LE(destination: Uint8Array, value: number, offset: number): void {
259 destination[offset + 0] = (value & 0b11111111);
260 value = value >>> 8;
261 destination[offset + 1] = (value & 0b11111111);
262 }
263 > buffer.ts
264 > export function readUInt32BE(source: Uint8Array, offset: number): number {
265 return (
266 source[offset] * 2 ** 24
270 );
271 }
272 > buffer.ts
273 > export function writeUInt32BE(destination: Uint8Array, value: number, offset: number): void {
274 destination[offset + 3] = value;
275 value = value >>> 8;
280 destination[offset] = value;
281 }
282 > buffer.ts
283 > export function readUInt32LE(source: Uint8Array, offset: number): number {
284 return (
285 ((source[offset + 0] << 0) >>> 0) |
289 );
290 }
291 > buffer.ts
292 > export function writeUInt32LE(destination: Uint8Array, value: number, offset: number): void {
293 destination[offset + 0] = (value & 0b11111111);
294 value = value >>> 8;
299 destination[offset + 3] = (value & 0b11111111);
300 }
301 > buffer.ts
302 > export function readUInt8(source: Uint8Array, offset: number): number {
303 return source[offset];
304 }
305 > buffer.ts
306 > export function writeUInt8(destination: Uint8Array, value: number, offset: number): void {
307 destination[offset] = value;
308 }
309 > buffer.ts
310 > export interface VSBufferReadable extends streams.Readable<VSBuffer> { }
311 >
312 > export interface VSBufferReadableStream extends streams.ReadableStream<VSBuffer> { }
313 >
314 > export interface VSBufferWriteableStream extends streams.WriteableStream<VSBuffer> { }
315 >
316 > export interface VSBufferReadableBufferedStream extends streams.ReadableBufferedStream<VSBuffer> { }
317 >
318 > export function readableToBuffer(readable: VSBufferReadable): VSBuffer {
319 return streams.consumeReadable<VSBuffer>(readable, chunks => VSBuffer.concat(chunks));
320 }
321 > buffer.ts
322 > export function bufferToReadable(buffer: VSBuffer): VSBufferReadable {
323 return streams.toReadable<VSBuffer>(buffer);
324 }
325 > buffer.ts
326 > export function streamToBuffer(stream: streams.ReadableStream<VSBuffer>): Promise<VSBuffer> {
327 return streams.consumeStream<VSBuffer>(stream, chunks => VSBuffer.concat(chunks));
328 }
329 > buffer.ts
330 export async function bufferedStreamToBuffer(bufferedStream: streams.ReadableBufferedStream<VSBuffer>): Promise<VSBuffer> {
331 if (bufferedStream.ended) {
342 ]);
343 }
344 > buffer.ts
345 > export function bufferToStream(buffer: VSBuffer): streams.ReadableStream<VSBuffer> {
346 return streams.toStream<VSBuffer>(buffer, chunks => VSBuffer.concat(chunks));
347 }
348 > buffer.ts
349 > export function streamToBufferReadableStream(stream: streams.ReadableStreamEvents<Uint8Array | string>): streams.ReadableStream<VSBuffer> {
350 return streams.transform<Uint8Array | string, VSBuffer>(stream, { data: data => typeof data === 'string' ? VSBuffer.fromString(data) : VSBuffer.wrap(data) }, chunks => VSBuffer.concat(chunks));
351 }
352 > buffer.ts
353 > export function newWriteableBufferStream(options?: streams.WriteableStreamOptions): streams.WriteableStream<VSBuffer> {
354 return streams.newWriteableStream<VSBuffer>(chunks => VSBuffer.concat(chunks), options);
355 }
356 > buffer.ts
357 > export function prefixedBufferReadable(prefix: VSBuffer, readable: VSBufferReadable): VSBufferReadable {
358 return streams.prefixedReadable(prefix, readable, chunks => VSBuffer.concat(chunks));
359 }
360 > buffer.ts
361 > export function prefixedBufferStream(prefix: VSBuffer, stream: VSBufferReadableStream): VSBufferReadableStream {
362 return streams.prefixedStream(prefix, stream, chunks => VSBuffer.concat(chunks));
363 }
364 > buffer.ts
365 > /** Decodes base64 to a uint8 array. URL-encoded and unpadded base64 is allowed. */
366 > export function decodeBase64(encoded: string) {
367 let building = 0;
368 let remainder = 0;
424 return VSBuffer.wrap(buffer).slice(0, unpadded);
425 }
426 > buffer.ts
427 > const base64Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
428 > const base64UrlSafeAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
429 >
430 > /** Encodes a buffer to a base64 string. */
431 > export function encodeBase64({ buffer }: VSBuffer, padded = true, urlSafe = false) {
432 const dictionary = urlSafe ? base64UrlSafeAlphabet : base64Alphabet;
433 let output = '';
463 return output;
464 }
465 > buffer.ts
466 > const hexChars = '0123456789abcdef';
467 > export function encodeHex({ buffer }: VSBuffer): string {
468 let result = '';
469 for (let i = 0; i < buffer.length; i++) {
474 return result;
475 }
476 > buffer.ts
477 > export function decodeHex(hex: string): VSBuffer {
478 if (hex.length % 2 !== 0) {
479 throw new SyntaxError('Hex string must have an even length');
485 return VSBuffer.wrap(out);
486 }
487 > buffer.ts
488 function decodeHexChar(str: string, position: number) {
489 const s = str.charCodeAt(position);
src/vs/editor/common/core/ranges/offsetRange.ts 158 covered LOC · 52 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- offsetRange.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 '../../../../base/common/errors.js';
7 >
8 > export interface IOffsetRange {
9 > readonly start: number;
10 > readonly endExclusive: number;
11 > }
12 >
13 > /**
14 > * A range of offsets (0-based).
15 > */
16 > export class OffsetRange implements IOffsetRange {
17 > public static fromTo(start: number, endExclusive: number): OffsetRange {
18 > return new OffsetRange(start, endExclusive);
19 > }
20 >
21 > public static equals(r1: IOffsetRange, r2: IOffsetRange): boolean {
22 return r1.start === r2.start && r1.endExclusive === r2.endExclusive;
23 }
25 > public static addRange(range: OffsetRange, sortedRanges: OffsetRange[]): void {
26 let i = 0;
27 while (i < sortedRanges.length && sortedRanges[i].endExclusive < range.start) {
40 }
41 }
43 > public static tryCreate(start: number, endExclusive: number): OffsetRange | undefined {
44 if (start > endExclusive) {
45 return undefined;
47 return new OffsetRange(start, endExclusive);
48 }
50 > public static ofLength(length: number): OffsetRange {
51 > return new OffsetRange(0, length); offsetRange.ts
52 > }
54 > public static ofStartAndLength(start: number, length: number): OffsetRange {
55 return new OffsetRange(start, start + length);
56 }
58 > public static emptyAt(offset: number): OffsetRange {
59 return new OffsetRange(offset, offset);
60 }
62 > constructor(public readonly start: number, public readonly endExclusive: number) {
63 > if (start > endExclusive) { offsetRange.ts
64 throw new BugIndicatingError(`Invalid range: ${this.toString()}`);
65 }
68 > get isEmpty(): boolean {
69 > return this.start === this.endExclusive; offsetRange.ts
70 > }
72 > public delta(offset: number): OffsetRange {
73 > return new OffsetRange(this.start + offset, this.endExclusive + offset); offsetRange.ts
74 > }
76 > public deltaStart(offset: number): OffsetRange {
77 > return new OffsetRange(this.start + offset, this.endExclusive); offsetRange.ts
78 > }
80 > public deltaEnd(offset: number): OffsetRange {
81 > return new OffsetRange(this.start, this.endExclusive + offset); offsetRange.ts
82 > }
84 > public get length(): number {
85 > return this.endExclusive - this.start; offsetRange.ts
86 > }
88 > public toString() {
89 return `[${this.start}, ${this.endExclusive})`;
90 }
92 > public equals(other: OffsetRange): boolean {
93 return this.start === other.start && this.endExclusive === other.endExclusive;
94 }
96 > public containsRange(other: OffsetRange): boolean {
97 return this.start <= other.start && other.endExclusive <= this.endExclusive;
98 }
100 > public contains(offset: number): boolean {
101 return this.start <= offset && offset < this.endExclusive;
102 }
104 > /**
105 > * for all numbers n: range1.contains(n) or range2.contains(n) => range1.join(range2).contains(n)
106 > * The joined range is the smallest range that contains both ranges.
107 > */
108 > public join(other: OffsetRange): OffsetRange {
109 > return new OffsetRange(Math.min(this.start, other.start), Math.max(this.endExclusive, other.endExclusive)); offsetRange.ts
110 > }
112 > /**
113 > * for all numbers n: range1.contains(n) and range2.contains(n) <=> range1.intersect(range2).contains(n)
114 > *
115 > * The resulting range is empty if the ranges do not intersect, but touch.
116 > * If the ranges don't even touch, the result is undefined.
117 > */
118 > public intersect(other: OffsetRange): OffsetRange | undefined {
119 > const start = Math.max(this.start, other.start); offsetRange.ts
120 > const end = Math.min(this.endExclusive, other.endExclusive);
121 > if (start <= end) {
122 > return new OffsetRange(start, end);
123 > }
124 return undefined;
125 > } offsetRange.ts
127 > public intersectionLength(range: OffsetRange): number {
128 const start = Math.max(this.start, range.start);
129 const end = Math.min(this.endExclusive, range.endExclusive);
130 return Math.max(0, end - start);
131 }
133 > /**
134 > * `a.intersects(b)` iff there exists a number n so that `a.contains(n)` and `b.contains(n)`.
135 > * Warning: If one range is empty, this method returns always false.
136 > */
137 > public intersects(other: OffsetRange): boolean {
138 > const start = Math.max(this.start, other.start); offsetRange.ts
139 > const end = Math.min(this.endExclusive, other.endExclusive);
140 > return start < end;
141 > }
143 > public intersectsOrTouches(other: OffsetRange): boolean {
144 const start = Math.max(this.start, other.start);
145 const end = Math.min(this.endExclusive, other.endExclusive);
146 return start <= end;
147 }
149 > public isBefore(other: OffsetRange): boolean {
150 return this.endExclusive <= other.start;
151 }
153 > public isAfter(other: OffsetRange): boolean {
154 return this.start >= other.endExclusive;
155 }
157 > public slice<T>(arr: readonly T[]): T[] {
158 return arr.slice(this.start, this.endExclusive);
159 }
161 > public substring(str: string): string {
162 return str.substring(this.start, this.endExclusive);
163 }
165 > /**
166 > * Returns the given value if it is contained in this instance, otherwise the closest value that is contained.
167 > * The range must not be empty.
168 > */
169 > public clip(value: number): number {
170 if (this.isEmpty) {
171 throw new BugIndicatingError(`Invalid clipping range: ${this.toString()}`);
173 return Math.max(this.start, Math.min(this.endExclusive - 1, value));
174 }
176 > /**
177 > * Returns `r := value + k * length` such that `r` is contained in this range.
178 > * The range must not be empty.
179 > *
180 > * E.g. `[5, 10).clipCyclic(10) === 5`, `[5, 10).clipCyclic(11) === 6` and `[5, 10).clipCyclic(4) === 9`.
181 > */
182 > public clipCyclic(value: number): number {
183 if (this.isEmpty) {
184 throw new BugIndicatingError(`Invalid clipping range: ${this.toString()}`);
192 return value;
193 }
195 > public map<T>(f: (offset: number) => T): T[] {
196 const result: T[] = [];
197 for (let i = this.start; i < this.endExclusive; i++) {
200 return result;
201 }
203 > public forEach(f: (offset: number) => void): void {
204 for (let i = this.start; i < this.endExclusive; i++) {
205 f(i);
206 }
207 }
209 > /**
210 > * this: [ 5, 10), range: [10, 15) => [5, 15)]
211 > * Throws if the ranges are not touching.
212 > */
213 > public joinRightTouching(range: OffsetRange): OffsetRange {
214 if (this.endExclusive !== range.start) {
215 throw new BugIndicatingError(`Invalid join: ${this.toString()} and ${range.toString()}`);
217 return new OffsetRange(this.start, range.endExclusive);
218 }
220 > public withMargin(margin: number): OffsetRange;
221 > public withMargin(marginStart: number, marginEnd: number): OffsetRange;
222 > public withMargin(marginStart: number, marginEnd?: number): OffsetRange {
223 if (marginEnd === undefined) {
224 marginEnd = marginStart;
226 return new OffsetRange(this.start - marginStart, this.endExclusive + marginEnd);
227 }
228 > } offsetRange.ts
229 >
230 > export class OffsetRangeSet {
231 private readonly _sortedRanges: OffsetRange[] = [];
233 > public get ranges(): OffsetRange[] {
234 return [...this._sortedRanges];
235 }
237 > public addRange(range: OffsetRange): void {
238 let i = 0;
239 while (i < this._sortedRanges.length && this._sortedRanges[i].endExclusive < range.start) {
252 }
253 }
255 > public toString(): string {
256 return this._sortedRanges.map(r => r.toString()).join(', ');
257 }
259 > /**
260 > * Returns if there is a value that is contained in this instance and the given range.
261 > */
262 > public intersectsStrict(other: OffsetRange): boolean {
263 // TODO use binary search
264 let i = 0;
268 return i < this._sortedRanges.length && this._sortedRanges[i].start < other.endExclusive;
269 }
271 > public intersectWithRange(other: OffsetRange): OffsetRangeSet {
272 // TODO use binary search + slice
273 const result = new OffsetRangeSet();
280 return result;
281 }
283 > public intersectWithRangeLength(other: OffsetRange): number {
284 return this.intersectWithRange(other).length;
285 }
287 > public get length(): number {
288 return this._sortedRanges.reduce((prev, cur) => prev + cur.length, 0);
289 }
290 > } offsetRange.ts
src/vs/editor/common/core/edits/edit.ts 144 covered LOC · 30 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- edit.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 { sumBy } from '../../../../base/common/arrays.js';
7 > import { BugIndicatingError } from '../../../../base/common/errors.js';
8 > import { OffsetRange } from '../ranges/offsetRange.js';
9 >
10 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
11 > export abstract class BaseEdit<T extends BaseReplacement<T> = BaseReplacement<any>, TEdit extends BaseEdit<T, TEdit> = BaseEdit<T, any>> {
12 > constructor(
13 > public readonly replacements: readonly T[],
14 > ) {
15 > let lastEndEx = -1;
16 > for (const replacement of replacements) {
17 if (!(replacement.replaceRange.start >= lastEndEx)) {
18 throw new BugIndicatingError(`Edits must be disjoint and sorted. Found ${replacement} after ${lastEndEx}`);
20 lastEndEx = replacement.replaceRange.endExclusive;
21 }
22 > } edit.ts
23 >
24 > protected abstract _createNew(replacements: readonly T[]): TEdit;
25 >
26 > /**
27 > * Returns true if and only if this edit and the given edit are structurally equal.
28 > * Note that this does not mean that the edits have the same effect on a given input!
29 > * See `.normalize()` or `.normalizeOnBase(base)` for that.
30 > */
31 > public equals(other: TEdit): boolean {
32 if (this.replacements.length !== other.replacements.length) {
33 return false;
40 return true;
41 }
42 > edit.ts
43 > public toString() {
44 const edits = this.replacements.map(e => e.toString()).join(', ');
45 return `[${edits}]`;
46 }
47 > edit.ts
48 > /**
49 > * Normalizes the edit by removing empty replacements and joining touching replacements (if the replacements allow joining).
50 > * Two edits have an equal normalized edit if and only if they have the same effect on any input.
51 > *
52 > * ![](https://raw.githubusercontent.com/microsoft/vscode/refs/heads/main/src/vs/editor/common/core/edits/docs/BaseEdit_normalize.drawio.png)
53 > *
54 > * Invariant:
55 > * ```
56 > * (forall base: TEdit.apply(base).equals(other.apply(base))) <-> this.normalize().equals(other.normalize())
57 > * ```
58 > * and
59 > * ```
60 > * forall base: TEdit.apply(base).equals(this.normalize().apply(base))
61 > * ```
62 > *
63 > */
64 > public normalize(): TEdit {
65 const newReplacements: T[] = [];
66 let lastReplacement: T | undefined;
88 return this._createNew(newReplacements);
89 }
90 > edit.ts
91 > /**
92 > * Combines two edits into one with the same effect.
93 > *
94 > * ![](https://raw.githubusercontent.com/microsoft/vscode/refs/heads/main/src/vs/editor/common/core/edits/docs/BaseEdit_compose.drawio.png)
95 > *
96 > * Invariant:
97 > * ```
98 > * other.apply(this.apply(s0)) = this.compose(other).apply(s0)
99 > * ```
100 > */
101 > public compose(other: TEdit): TEdit {
102 const edits1 = this.normalize();
103 const edits2 = other.normalize();
184 return this._createNew(result).normalize();
185 }
186 > edit.ts
187 > public decomposeSplit(shouldBeInE1: (repl: T) => boolean): { e1: TEdit; e2: TEdit } {
188 const e1: T[] = [];
189 const e2: T[] = [];
200 return { e1: this._createNew(e1), e2: this._createNew(e2) };
201 }
202 > edit.ts
203 > /**
204 > * Returns the range of each replacement in the applied value.
205 > */
206 > public getNewRanges(): OffsetRange[] {
207 const ranges: OffsetRange[] = [];
208 let offset = 0;
213 return ranges;
214 }
215 > edit.ts
216 > public getJoinedReplaceRange(): OffsetRange | undefined {
217 if (this.replacements.length === 0) {
218 return undefined;
220 return this.replacements[0].replaceRange.join(this.replacements.at(-1)!.replaceRange);
221 }
222 > edit.ts
223 > public isEmpty(): boolean {
224 return this.replacements.length === 0;
225 }
226 > edit.ts
227 > public getLengthDelta(): number {
228 return sumBy(this.replacements, (replacement) => replacement.getLengthDelta());
229 }
230 > edit.ts
231 > public getNewDataLength(dataLength: number): number {
232 return dataLength + this.getLengthDelta();
233 }
234 > edit.ts
235 > public applyToOffset(originalOffset: number): number {
236 let accumulatedDelta = 0;
237 for (const r of this.replacements) {
248 return originalOffset + accumulatedDelta;
249 }
250 > edit.ts
251 > public applyToOffsetRange(originalRange: OffsetRange): OffsetRange {
252 return new OffsetRange(
253 this.applyToOffset(originalRange.start),
255 );
256 }
257 > edit.ts
258 > public applyInverseToOffset(postEditsOffset: number): number {
259 let accumulatedDelta = 0;
260 for (const edit of this.replacements) {
272 return postEditsOffset - accumulatedDelta;
273 }
274 > edit.ts
275 > /**
276 > * Return undefined if the originalOffset is within an edit
277 > */
278 > public applyToOffsetOrUndefined(originalOffset: number): number | undefined {
279 let accumulatedDelta = 0;
280 for (const edit of this.replacements) {
291 return originalOffset + accumulatedDelta;
292 }
293 > edit.ts
294 > /**
295 > * Return undefined if the originalRange is within an edit
296 > */
297 > public applyToOffsetRangeOrUndefined(originalRange: OffsetRange): OffsetRange | undefined {
298 const start = this.applyToOffsetOrUndefined(originalRange.start);
299 if (start === undefined) {
306 return new OffsetRange(start, end);
307 }
308 > } edit.ts
309 >
310 > export abstract class BaseReplacement<TSelf extends BaseReplacement<TSelf>> {
311 > constructor(
312 /**
313 * The range to be replaced.
315 public readonly replaceRange: OffsetRange,
316 ) { }
317 > edit.ts
318 > public abstract getNewLength(): number;
319 >
320 > /**
321 > * Precondition: TEdit.range.endExclusive === other.range.start
322 > */
323 > public abstract tryJoinTouching(other: TSelf): TSelf | undefined;
324 >
325 > public abstract slice(newReplaceRange: OffsetRange, rangeInReplacement?: OffsetRange): TSelf;
326 >
327 > public delta(offset: number): TSelf {
328 return this.slice(this.replaceRange.delta(offset), new OffsetRange(0, this.getNewLength()));
329 }
330 > edit.ts
331 > public getLengthDelta(): number {
332 return this.getNewLength() - this.replaceRange.length;
333 }
334 > edit.ts
335 > abstract equals(other: TSelf): boolean;
336 >
337 > toString(): string {
338 return `{ ${this.replaceRange.toString()} -> ${this.getNewLength()} }`;
339 }
340 > edit.ts
341 > get isEmpty() {
342 return this.getNewLength() === 0 && this.replaceRange.length === 0;
343 }
344 > edit.ts
345 > getRangeAfterReplace(): OffsetRange {
346 return new OffsetRange(this.replaceRange.start, this.replaceRange.start + this.getNewLength());
347 }
348 > } edit.ts
349 >
350 > export type AnyEdit = BaseEdit<AnyReplacement, AnyEdit>;
351 > export type AnyReplacement = BaseReplacement<AnyReplacement>;
352 >
353 > export class Edit<T extends BaseReplacement<T>> extends BaseEdit<T, Edit<T>> {
354 > /**
355 > * Represents a set of edits to a string.
356 > * All these edits are applied at once.
357 > */
358 > public static readonly empty = new Edit<never>([]);
359 >
360 > public static create<T extends BaseReplacement<T>>(replacements: readonly T[]): Edit<T> {
361 return new Edit(replacements);
362 }
363 > edit.ts
364 > public static single<T extends BaseReplacement<T>>(replacement: T): Edit<T> {
365 return new Edit([replacement]);
366 }
367 > edit.ts
368 > protected override _createNew(replacements: readonly T[]): Edit<T> {
369 return new Edit(replacements);
370 }
371 > } edit.ts
372 >
373 > export class AnnotationReplacement<TAnnotation> extends BaseReplacement<AnnotationReplacement<TAnnotation>> {
374 > constructor(
375 range: OffsetRange,
376 public readonly newLength: number,
379 super(range);
380 }
381 > edit.ts
382 > override equals(other: AnnotationReplacement<TAnnotation>): boolean {
383 return this.replaceRange.equals(other.replaceRange) && this.newLength === other.newLength && this.annotation === other.annotation;
384 }
385 > edit.ts
386 > getNewLength(): number { return this.newLength; }
387 >
388 > tryJoinTouching(other: AnnotationReplacement<TAnnotation>): AnnotationReplacement<TAnnotation> | undefined {
389 if (this.annotation !== other.annotation) {
390 return undefined;
392 return new AnnotationReplacement<TAnnotation>(this.replaceRange.joinRightTouching(other.replaceRange), this.newLength + other.newLength, this.annotation);
393 }
394 > edit.ts
395 > slice(range: OffsetRange, rangeInReplacement?: OffsetRange): AnnotationReplacement<TAnnotation> {
396 return new AnnotationReplacement<TAnnotation>(range, rangeInReplacement ? rangeInReplacement.length : this.newLength, this.annotation);
397 }
398 > } edit.ts
src/vs/editor/common/core/selection.ts 141 covered LOC · 16 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- selection.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 { IPosition, Position } from './position.js';
7 > import { Range } from './range.js';
8 >
9 > /**
10 > * A selection in the editor.
11 > * The selection is a range that has an orientation.
12 > */
13 > export interface ISelection {
14 > /**
15 > * The line number on which the selection has started.
16 > */
17 > readonly selectionStartLineNumber: number;
18 > /**
19 > * The column on `selectionStartLineNumber` where the selection has started.
20 > */
21 > readonly selectionStartColumn: number;
22 > /**
23 > * The line number on which the selection has ended.
24 > */
25 > readonly positionLineNumber: number;
26 > /**
27 > * The column on `positionLineNumber` where the selection has ended.
28 > */
29 > readonly positionColumn: number;
30 > }
31 >
32 > /**
33 > * The direction of a selection.
34 > */
35 > export const enum SelectionDirection {
36 > /**
37 > * The selection starts above where it ends.
38 > */
39 > LTR,
40 > /**
41 > * The selection starts below where it ends.
42 > */
43 > RTL
44 > }
45 >
46 > /**
47 > * A selection in the editor.
48 > * The selection is a range that has an orientation.
49 > */
50 > export class Selection extends Range {
51 > /**
52 > * The line number on which the selection has started.
53 > */
54 > public readonly selectionStartLineNumber: number;
55 > /**
56 > * The column on `selectionStartLineNumber` where the selection has started.
57 > */
58 > public readonly selectionStartColumn: number;
59 > /**
60 > * The line number on which the selection has ended.
61 > */
62 > public readonly positionLineNumber: number;
63 > /**
64 > * The column on `positionLineNumber` where the selection has ended.
65 > */
66 > public readonly positionColumn: number;
67 >
68 > constructor(selectionStartLineNumber: number, selectionStartColumn: number, positionLineNumber: number, positionColumn: number) {
69 super(selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn);
70 this.selectionStartLineNumber = selectionStartLineNumber;
73 this.positionColumn = positionColumn;
74 }
76 > /**
77 > * Transform to a human-readable representation.
78 > */
79 > public override toString(): string {
80 return '[' + this.selectionStartLineNumber + ',' + this.selectionStartColumn + ' -> ' + this.positionLineNumber + ',' + this.positionColumn + ']';
81 }
83 > /**
84 > * Test if equals other selection.
85 > */
86 > public equalsSelection(other: ISelection): boolean {
87 return (
88 Selection.selectionsEqual(this, other)
89 );
90 }
92 > /**
93 > * Test if the two selections are equal.
94 > */
95 > public static selectionsEqual(a: ISelection, b: ISelection): boolean {
96 return (
97 a.selectionStartLineNumber === b.selectionStartLineNumber &&
101 );
102 }
103 > selection.ts
104 > /**
105 > * Get directions (LTR or RTL).
106 > */
107 > public getDirection(): SelectionDirection {
108 if (this.selectionStartLineNumber === this.startLineNumber && this.selectionStartColumn === this.startColumn) {
109 return SelectionDirection.LTR;
111 return SelectionDirection.RTL;
112 }
113 > selection.ts
114 > /**
115 > * Create a new selection with a different `positionLineNumber` and `positionColumn`.
116 > */
117 > public override setEndPosition(endLineNumber: number, endColumn: number): Selection {
118 if (this.getDirection() === SelectionDirection.LTR) {
119 return new Selection(this.startLineNumber, this.startColumn, endLineNumber, endColumn);
121 return new Selection(endLineNumber, endColumn, this.startLineNumber, this.startColumn);
122 }
123 > selection.ts
124 > /**
125 > * Get the position at `positionLineNumber` and `positionColumn`.
126 > */
127 > public getPosition(): Position {
128 return new Position(this.positionLineNumber, this.positionColumn);
129 }
130 > selection.ts
131 > /**
132 > * Get the position at the start of the selection.
133 > */
134 > public getSelectionStart(): Position {
135 return new Position(this.selectionStartLineNumber, this.selectionStartColumn);
136 }
137 > selection.ts
138 > /**
139 > * Create a new selection with a different `selectionStartLineNumber` and `selectionStartColumn`.
140 > */
141 > public override setStartPosition(startLineNumber: number, startColumn: number): Selection {
142 if (this.getDirection() === SelectionDirection.LTR) {
143 return new Selection(startLineNumber, startColumn, this.endLineNumber, this.endColumn);
145 return new Selection(this.endLineNumber, this.endColumn, startLineNumber, startColumn);
146 }
147 > selection.ts
148 > // ----
149 >
150 > /**
151 > * Create a `Selection` from one or two positions
152 > */
153 > public static override fromPositions(start: IPosition, end: IPosition = start): Selection {
154 return new Selection(start.lineNumber, start.column, end.lineNumber, end.column);
155 }
156 > selection.ts
157 > /**
158 > * Creates a `Selection` from a range, given a direction.
159 > */
160 > public static fromRange(range: Range, direction: SelectionDirection): Selection {
161 if (direction === SelectionDirection.LTR) {
162 return new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
165 }
166 }
167 > selection.ts
168 > /**
169 > * Create a `Selection` from an `ISelection`.
170 > */
171 > public static liftSelection(sel: ISelection): Selection {
172 return new Selection(sel.selectionStartLineNumber, sel.selectionStartColumn, sel.positionLineNumber, sel.positionColumn);
173 }
174 > selection.ts
175 > /**
176 > * `a` equals `b`.
177 > */
178 > public static selectionsArrEqual(a: ISelection[], b: ISelection[]): boolean {
179 if (a && !b || !a && b) {
180 return false;
193 return true;
194 }
195 > selection.ts
196 > /**
197 > * Test if `obj` is an `ISelection`.
198 > */
199 > public static isISelection(obj: unknown): obj is ISelection {
200 return (
201 !!obj
206 );
207 }
208 > selection.ts
209 > /**
210 > * Create with a direction.
211 > */
212 > public static createWithDirection(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, direction: SelectionDirection): Selection {
213
214 if (direction === SelectionDirection.LTR) {
218 return new Selection(endLineNumber, endColumn, startLineNumber, startColumn);
219 }
220 > } selection.ts
src/vs/editor/common/core/position.ts 130 covered LOC · 24 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- position.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 > * A position in the editor. This interface is suitable for serialization.
8 > */
9 > export interface IPosition {
10 > /**
11 > * line number (starts at 1)
12 > */
13 > readonly lineNumber: number;
14 > /**
15 > * column (the first character in a line is between column 1 and column 2)
16 > */
17 > readonly column: number;
18 > }
19 >
20 > /**
21 > * A position in the editor.
22 > */
23 > export class Position {
24 > /**
25 > * line number (starts at 1)
26 > */
27 > public readonly lineNumber: number;
28 > /**
29 > * column (the first character in a line is between column 1 and column 2)
30 > */
31 > public readonly column: number;
32 >
33 > constructor(lineNumber: number, column: number) {
34 > this.lineNumber = lineNumber; position.ts
35 > this.column = column;
36 > }
38 > /**
39 > * Create a new position from this position.
40 > *
41 > * @param newLineNumber new line number
42 > * @param newColumn new column
43 > */
44 > with(newLineNumber: number = this.lineNumber, newColumn: number = this.column): Position {
45 if (newLineNumber === this.lineNumber && newColumn === this.column) {
46 return this;
49 }
50 }
52 > /**
53 > * Derive a new position from this position.
54 > *
55 > * @param deltaLineNumber line number delta
56 > * @param deltaColumn column delta
57 > */
58 > delta(deltaLineNumber: number = 0, deltaColumn: number = 0): Position {
59 return this.with(Math.max(1, this.lineNumber + deltaLineNumber), Math.max(1, this.column + deltaColumn));
60 }
62 > /**
63 > * Test if this position equals other position
64 > */
65 > public equals(other: IPosition): boolean {
66 return Position.equals(this, other);
67 }
69 > /**
70 > * Test if position `a` equals position `b`
71 > */
72 > public static equals(a: IPosition | null, b: IPosition | null): boolean {
73 if (!a && !b) {
74 return true;
81 );
82 }
84 > /**
85 > * Test if this position is before other position.
86 > * If the two positions are equal, the result will be false.
87 > */
88 > public isBefore(other: IPosition): boolean {
89 > return Position.isBefore(this, other); position.ts
90 > }
92 > /**
93 > * Test if position `a` is before position `b`.
94 > * If the two positions are equal, the result will be false.
95 > */
96 > public static isBefore(a: IPosition, b: IPosition): boolean {
97 > if (a.lineNumber < b.lineNumber) { position.ts
98 return true;
99 }
100 > if (b.lineNumber < a.lineNumber) { position.ts
101 > return false; position.ts
102 > }
103 > return a.column < b.column; position.ts
104 > } position.ts
105 > position.ts
106 > /**
107 > * Test if this position is before other position.
108 > * If the two positions are equal, the result will be true.
109 > */
110 > public isBeforeOrEqual(other: IPosition): boolean {
111 return Position.isBeforeOrEqual(this, other);
112 }
113 > position.ts
114 > /**
115 > * Test if position `a` is before position `b`.
116 > * If the two positions are equal, the result will be true.
117 > */
118 > public static isBeforeOrEqual(a: IPosition, b: IPosition): boolean {
119 if (a.lineNumber < b.lineNumber) {
120 return true;
125 return a.column <= b.column;
126 }
127 > position.ts
128 > /**
129 > * A function that compares positions, useful for sorting
130 > */
131 > public static compare(a: IPosition, b: IPosition): number {
132 const aLineNumber = a.lineNumber | 0;
133 const bLineNumber = b.lineNumber | 0;
141 return aLineNumber - bLineNumber;
142 }
143 > position.ts
144 > /**
145 > * Clone this position.
146 > */
147 > public clone(): Position {
148 return new Position(this.lineNumber, this.column);
149 }
150 > position.ts
151 > /**
152 > * Convert to a human-readable representation.
153 > */
154 > public toString(): string {
155 return '(' + this.lineNumber + ',' + this.column + ')';
156 }
157 > position.ts
158 > // ---
159 >
160 > /**
161 > * Create a `Position` from an `IPosition`.
162 > */
163 > public static lift(pos: IPosition): Position {
164 return new Position(pos.lineNumber, pos.column);
165 }
166 > position.ts
167 > /**
168 > * Test if `obj` is an `IPosition`.
169 > */
170 > public static isIPosition(obj: unknown): obj is IPosition {
171 > return ( position.ts
172 > !!obj
173 > && (typeof (obj as IPosition).lineNumber === 'number')
174 > && (typeof (obj as IPosition).column === 'number')
175 > );
176 > }
177 > position.ts
178 > public toJSON(): IPosition {
179 return {
180 lineNumber: this.lineNumber,
src/vs/editor/common/encodedTokenAttributes.ts 128 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- encodedTokenAttributes.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 > * Open ended enum at runtime
8 > */
9 > export const enum LanguageId {
10 > Null = 0,
11 > PlainText = 1
12 > }
13 >
14 > /**
15 > * A font style. Values are 2^x such that a bit mask can be used.
16 > */
17 > export const enum FontStyle {
18 > NotSet = -1,
19 > None = 0,
20 > Italic = 1,
21 > Bold = 2,
22 > Underline = 4,
23 > Strikethrough = 8,
24 > }
25 >
26 > /**
27 > * Open ended enum at runtime
28 > */
29 > export const enum ColorId {
30 > None = 0,
31 > DefaultForeground = 1,
32 > DefaultBackground = 2
33 > }
34 >
35 > /**
36 > * A standard token type.
37 > */
38 > export const enum StandardTokenType {
39 > Other = 0,
40 > Comment = 1,
41 > String = 2,
42 > RegEx = 3
43 > }
44 >
45 > /**
46 > * Helpers to manage the "collapsed" metadata of an entire StackElement stack.
47 > * The following assumptions have been made:
48 > * - languageId < 256 => needs 8 bits
49 > * - unique color count < 512 => needs 9 bits
50 > *
51 > * The binary format is:
52 > * - -------------------------------------------
53 > * 3322 2222 2222 1111 1111 1100 0000 0000
54 > * 1098 7654 3210 9876 5432 1098 7654 3210
55 > * - -------------------------------------------
56 > * xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
57 > * bbbb bbbb ffff ffff fFFF FBTT LLLL LLLL
58 > * - -------------------------------------------
59 > * - L = LanguageId (8 bits)
60 > * - T = StandardTokenType (2 bits)
61 > * - B = Balanced bracket (1 bit)
62 > * - F = FontStyle (4 bits)
63 > * - f = foreground color (9 bits)
64 > * - b = background color (8 bits)
65 > *
66 > */
67 > export const enum MetadataConsts {
68 > LANGUAGEID_MASK /* */ = 0b00000000_00000000_00000000_11111111,
69 > TOKEN_TYPE_MASK /* */ = 0b00000000_00000000_00000011_00000000,
70 > BALANCED_BRACKETS_MASK /* */ = 0b00000000_00000000_00000100_00000000,
71 > FONT_STYLE_MASK /* */ = 0b00000000_00000000_01111000_00000000,
72 > FOREGROUND_MASK /* */ = 0b00000000_11111111_10000000_00000000,
73 > BACKGROUND_MASK /* */ = 0b11111111_00000000_00000000_00000000,
74 >
75 > ITALIC_MASK /* */ = 0b00000000_00000000_00001000_00000000,
76 > BOLD_MASK /* */ = 0b00000000_00000000_00010000_00000000,
77 > UNDERLINE_MASK /* */ = 0b00000000_00000000_00100000_00000000,
78 > STRIKETHROUGH_MASK /* */ = 0b00000000_00000000_01000000_00000000,
79 >
80 > // Semantic tokens cannot set the language id, so we can
81 > // use the first 8 bits for control purposes
82 > SEMANTIC_USE_ITALIC /* */ = 0b00000000_00000000_00000000_00000001,
83 > SEMANTIC_USE_BOLD /* */ = 0b00000000_00000000_00000000_00000010,
84 > SEMANTIC_USE_UNDERLINE /* */ = 0b00000000_00000000_00000000_00000100,
85 > SEMANTIC_USE_STRIKETHROUGH /* */ = 0b00000000_00000000_00000000_00001000,
86 > SEMANTIC_USE_FOREGROUND /* */ = 0b00000000_00000000_00000000_00010000,
87 > SEMANTIC_USE_BACKGROUND /* */ = 0b00000000_00000000_00000000_00100000,
88 >
89 > LANGUAGEID_OFFSET = 0,
90 > TOKEN_TYPE_OFFSET = 8,
91 > BALANCED_BRACKETS_OFFSET = 10,
92 > FONT_STYLE_OFFSET = 11,
93 > FOREGROUND_OFFSET = 15,
94 > BACKGROUND_OFFSET = 24
95 > }
96 >
97 > /**
98 > */
99 > export class TokenMetadata {
100 >
101 > public static getLanguageId(metadata: number): LanguageId {
102 return (metadata & MetadataConsts.LANGUAGEID_MASK) >>> MetadataConsts.LANGUAGEID_OFFSET;
103 }
105 > public static getTokenType(metadata: number): StandardTokenType {
106 return (metadata & MetadataConsts.TOKEN_TYPE_MASK) >>> MetadataConsts.TOKEN_TYPE_OFFSET;
107 }
109 > public static containsBalancedBrackets(metadata: number): boolean {
110 return (metadata & MetadataConsts.BALANCED_BRACKETS_MASK) !== 0;
111 }
113 > public static getFontStyle(metadata: number): FontStyle {
114 return (metadata & MetadataConsts.FONT_STYLE_MASK) >>> MetadataConsts.FONT_STYLE_OFFSET;
115 }
117 > public static getForeground(metadata: number): ColorId {
118 return (metadata & MetadataConsts.FOREGROUND_MASK) >>> MetadataConsts.FOREGROUND_OFFSET;
119 }
121 > public static getBackground(metadata: number): ColorId {
122 return (metadata & MetadataConsts.BACKGROUND_MASK) >>> MetadataConsts.BACKGROUND_OFFSET;
123 }
125 > public static getClassNameFromMetadata(metadata: number): string {
126 const foreground = this.getForeground(metadata);
127 let className = 'mtk' + foreground;
143 return className;
144 }
146 > public static getInlineStyleFromMetadata(metadata: number, colorMap: string[]): string {
147 const foreground = this.getForeground(metadata);
148 const fontStyle = this.getFontStyle(metadata);
168 return result;
169 }
171 > public static getPresentationFromMetadata(metadata: number): ITokenPresentation {
172 const foreground = this.getForeground(metadata);
173 const fontStyle = this.getFontStyle(metadata);
181 };
182 }
184 >
185 > /**
186 > */
187 > export interface ITokenPresentation {
188 > foreground: ColorId;
189 > italic: boolean;
190 > bold: boolean;
191 > underline: boolean;
192 > strikethrough: boolean;
193 > }
src/vs/editor/common/core/edits/textEdit.ts 127 covered LOC · 36 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textEdit.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, equals } from '../../../../base/common/arrays.js';
7 > import { assertFn, checkAdjacentItems } from '../../../../base/common/assert.js';
8 > import { BugIndicatingError } from '../../../../base/common/errors.js';
9 > import { commonPrefixLength, commonSuffixLength } from '../../../../base/common/strings.js';
10 > import { ISingleEditOperation } from '../editOperation.js';
11 > import { BaseStringEdit, StringReplacement } from './stringEdit.js';
12 > import { Position } from '../position.js';
13 > import { Range } from '../range.js';
14 > import { TextLength } from '../text/textLength.js';
15 > import { AbstractText, StringText } from '../text/abstractText.js';
16 > import { IEquatable } from '../../../../base/common/equals.js';
17 >
18 > export class TextEdit {
19 > public static fromStringEdit(edit: BaseStringEdit, initialState: AbstractText): TextEdit {
20 > const edits = edit.replacements.map(e => TextReplacement.fromStringReplacement(e, initialState));
21 > return new TextEdit(edits);
22 > }
23 >
24 > public static replace(originalRange: Range, newText: string): TextEdit {
25 return new TextEdit([new TextReplacement(originalRange, newText)]);
26 }
28 > public static delete(range: Range): TextEdit {
29 return new TextEdit([new TextReplacement(range, '')]);
30 }
32 > public static insert(position: Position, newText: string): TextEdit {
33 return new TextEdit([new TextReplacement(Range.fromPositions(position, position), newText)]);
34 }
36 > public static fromParallelReplacementsUnsorted(replacements: readonly TextReplacement[]): TextEdit {
37 const r = replacements.slice().sort(compareBy(i => i.range, Range.compareRangesUsingStarts));
38 return new TextEdit(r);
39 }
41 > constructor(
42 public readonly replacements: readonly TextReplacement[]
43 ) {
44 assertFn(() => checkAdjacentItems(replacements, (a, b) => a.range.getEndPosition().isBeforeOrEqual(b.range.getStartPosition())));
45 }
47 > /**
48 > * Joins touching edits and removes empty edits.
49 > */
50 > normalize(): TextEdit {
51 const replacements: TextReplacement[] = [];
52 for (const r of this.replacements) {
60 return new TextEdit(replacements);
61 }
63 > mapPosition(position: Position): Position | Range {
64 let lineDelta = 0;
65 let curLine = 0;
101 return new Position(position.lineNumber + lineDelta, position.column + (position.lineNumber + lineDelta === curLine ? columnDeltaInCurLine : 0));
102 }
103 > textEdit.ts
104 > mapRange(range: Range): Range {
105 function getStart(p: Position | Range) {
106 return p instanceof Position ? p : p.getStartPosition();
116 return rangeFromPositions(start, end);
117 }
118 > textEdit.ts
119 > // TODO: `doc` is not needed for this!
120 > inverseMapPosition(positionAfterEdit: Position, doc: AbstractText): Position | Range {
121 const reversed = this.inverse(doc);
122 return reversed.mapPosition(positionAfterEdit);
123 }
124 > textEdit.ts
125 > inverseMapRange(range: Range, doc: AbstractText): Range {
126 const reversed = this.inverse(doc);
127 return reversed.mapRange(range);
128 }
129 > textEdit.ts
130 > apply(text: AbstractText): string {
131 let result = '';
132 let lastEditEnd = new Position(1, 1);
149 return result;
150 }
151 > textEdit.ts
152 > applyToString(str: string): string {
153 const strText = new StringText(str);
154 return this.apply(strText);
155 }
156 > textEdit.ts
157 > inverse(doc: AbstractText): TextEdit {
158 const ranges = this.getNewRanges();
159 return new TextEdit(this.replacements.map((e, idx) => new TextReplacement(ranges[idx], doc.getValueOfRange(e.range))));
160 }
161 > textEdit.ts
162 > getNewRanges(): Range[] {
163 const newRanges: Range[] = [];
164 let previousEditEndLineNumber = 0;
179 return newRanges;
180 }
181 > textEdit.ts
182 > toReplacement(text: AbstractText): TextReplacement {
183 if (this.replacements.length === 0) { throw new BugIndicatingError(); }
184 if (this.replacements.length === 1) { return this.replacements[0]; }
201 return new TextReplacement(Range.fromPositions(startPos, endPos), newText);
202 }
203 > textEdit.ts
204 > equals(other: TextEdit): boolean {
205 return equals(this.replacements, other.replacements, (a, b) => a.equals(b));
206 }
207 > textEdit.ts
208 > /**
209 > * Combines two edits into one with the same effect.
210 > * WARNING: This is written by AI, but well tested. I do not understand the implementation myself.
211 > *
212 > * Invariant:
213 > * ```
214 > * other.applyToString(this.applyToString(s0)) = this.compose(other).applyToString(s0)
215 > * ```
216 > */
217 > compose(other: TextEdit): TextEdit {
218 const edits1 = this.normalize();
219 const edits2 = other.normalize();
579 return new TextEdit(resultReplacements).normalize();
580 }
581 > textEdit.ts
582 > toString(text: AbstractText | string | undefined): string {
583 if (text === undefined) {
584 return this.replacements.map(edit => edit.toString()).join('\n');
641 }).join('\n');
642 }
643 > } textEdit.ts
644 >
645 > export class TextReplacement implements IEquatable<TextReplacement> {
646 > public static joinReplacements(replacements: TextReplacement[], initialValue: AbstractText): TextReplacement {
647 > if (replacements.length === 0) { throw new BugIndicatingError(); }
648 > if (replacements.length === 1) { return replacements[0]; }
649 > textEdit.ts
650 > const startPos = replacements[0].range.getStartPosition();
651 > const endPos = replacements[replacements.length - 1].range.getEndPosition();
652 >
653 > let newText = '';
654 >
655 > for (let i = 0; i < replacements.length; i++) {
656 > const curEdit = replacements[i];
657 > newText += curEdit.text;
658 > if (i < replacements.length - 1) {
659 > const nextEdit = replacements[i + 1];
660 > const gapRange = Range.fromPositions(curEdit.range.getEndPosition(), nextEdit.range.getStartPosition());
661 > const gapText = initialValue.getValueOfRange(gapRange);
662 > newText += gapText;
663 > }
664 > }
665 > return new TextReplacement(Range.fromPositions(startPos, endPos), newText);
666 > } textEdit.ts
667 >
668 > public static fromStringReplacement(replacement: StringReplacement, initialState: AbstractText): TextReplacement {
669 return new TextReplacement(initialState.getTransformer().getRange(replacement.replaceRange), replacement.newText);
670 }
671 > textEdit.ts
672 > public static delete(range: Range): TextReplacement {
673 return new TextReplacement(range, '');
674 }
675 > textEdit.ts
676 > constructor(
677 public readonly range: Range,
678 public readonly text: string,
679 ) {
680 }
681 > textEdit.ts
682 > get isEmpty(): boolean {
683 return this.range.isEmpty() && this.text.length === 0;
684 }
685 > textEdit.ts
686 > static equals(first: TextReplacement, second: TextReplacement) {
687 return first.range.equalsRange(second.range) && first.text === second.text;
688 }
689 > textEdit.ts
690 > public toSingleEditOperation(): ISingleEditOperation {
691 return {
692 range: this.range,
694 };
695 }
696 > textEdit.ts
697 > public toEdit(): TextEdit {
698 return new TextEdit([this]);
699 }
700 > textEdit.ts
701 > public equals(other: TextReplacement): boolean {
702 return TextReplacement.equals(this, other);
703 }
704 > textEdit.ts
705 > public extendToCoverRange(range: Range, initialValue: AbstractText): TextReplacement {
706 if (this.range.containsRange(range)) { return this; }
707
712 return new TextReplacement(newRange, newText);
713 }
714 > textEdit.ts
715 > public extendToFullLine(initialValue: AbstractText): TextReplacement {
716 const newRange = new Range(
717 this.range.startLineNumber,
722 return this.extendToCoverRange(newRange, initialValue);
723 }
724 > textEdit.ts
725 > public removeCommonPrefixAndSuffix(text: AbstractText): TextReplacement {
726 const prefix = this.removeCommonPrefix(text);
727 const suffix = prefix.removeCommonSuffix(text);
728 return suffix;
729 }
730 > textEdit.ts
731 > public removeCommonPrefix(text: AbstractText): TextReplacement {
732 const normalizedOriginalText = text.getValueOfRange(this.range).replaceAll('\r\n', '\n');
733 const normalizedModifiedText = this.text.replaceAll('\r\n', '\n');
741 return new TextReplacement(range, newText);
742 }
743 > textEdit.ts
744 > public removeCommonSuffix(text: AbstractText): TextReplacement {
745 const normalizedOriginalText = text.getValueOfRange(this.range).replaceAll('\r\n', '\n');
746 const normalizedModifiedText = this.text.replaceAll('\r\n', '\n');
754 return new TextReplacement(range, newText);
755 }
756 > textEdit.ts
757 > public isEffectiveDeletion(text: AbstractText): boolean {
758 let newText = this.text.replaceAll('\r\n', '\n');
759 let existingText = text.getValueOfRange(this.range).replaceAll('\r\n', '\n');
767 return newText === '';
768 }
769 > textEdit.ts
770 > public toString(): string {
771 const start = this.range.getStartPosition();
772 const end = this.range.getEndPosition();
773 return `(${start.lineNumber},${start.column} -> ${end.lineNumber},${end.column}): "${this.text}"`;
774 }
775 > } textEdit.ts
776 >
777 function rangeFromPositions(start: Position, end: Position): Range {
778 if (start.lineNumber === end.lineNumber && start.column === Number.MAX_SAFE_INTEGER) {
src/vs/base/common/arraysFind.ts 125 covered LOC · 26 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); arraysFind.ts
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; arraysFind.ts
71 > let j = endIdxEx;
72 > while (i < j) {
73 > const k = Math.floor((i + j) / 2);
74 > if (predicate(array[k])) {
75 > i = k + 1;
76 > } else {
77 > j = k; arraysFind.ts
78 > }
79 > } arraysFind.ts
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); arraysFind.ts
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; arraysFind.ts
102 > let j = endIdxEx;
103 > while (i < j) {
104 > const k = Math.floor((i + j) / 2);
105 > if (predicate(array[k])) {
106 > j = k; arraysFind.ts
107 > } else { arraysFind.ts
108 > i = k + 1; arraysFind.ts
109 > }
110 > } arraysFind.ts
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/editor/common/diff/defaultLinesDiffComputer/algorithms/dynamicProgrammingDiffing.ts 105 covered LOC · 16 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- dynamicProgrammingDiffing.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 { OffsetRange } from '../../../core/ranges/offsetRange.js';
7 > import { IDiffAlgorithm, SequenceDiff, ISequence, ITimeout, InfiniteTimeout, DiffAlgorithmResult } from './diffAlgorithm.js';
8 > import { Array2D } from '../utils.js';
9 >
10 > /**
11 > * A O(MN) diffing algorithm that supports a score function.
12 > * The algorithm can be improved by processing the 2d array diagonally.
13 > */
14 > export class DynamicProgrammingDiffing implements IDiffAlgorithm {
15 > compute(sequence1: ISequence, sequence2: ISequence, timeout: ITimeout = InfiniteTimeout.instance, equalityScore?: (offset1: number, offset2: number) => number): DiffAlgorithmResult {
16 > if (sequence1.length === 0 || sequence2.length === 0) { dynamicProgrammingDiffing.ts
17 > return DiffAlgorithmResult.trivial(sequence1, sequence2); dynamicProgrammingDiffing.ts
18 > }
20 > /**
21 > * lcsLengths.get(i, j): Length of the longest common subsequence of sequence1.substring(0, i + 1) and sequence2.substring(0, j + 1).
22 > */
23 > const lcsLengths = new Array2D<number>(sequence1.length, sequence2.length);
24 > const directions = new Array2D<number>(sequence1.length, sequence2.length);
25 > const lengths = new Array2D<number>(sequence1.length, sequence2.length);
26 >
27 > // ==== Initializing lcsLengths ====
28 > for (let s1 = 0; s1 < sequence1.length; s1++) {
29 > for (let s2 = 0; s2 < sequence2.length; s2++) {
30 > if (!timeout.isValid()) {
31 return DiffAlgorithmResult.trivialTimedOut(sequence1, sequence2);
32 }
34 > const horizontalLen = s1 === 0 ? 0 : lcsLengths.get(s1 - 1, s2);
35 > const verticalLen = s2 === 0 ? 0 : lcsLengths.get(s1, s2 - 1);
36 >
37 > let extendedSeqScore: number;
38 > if (sequence1.getElement(s1) === sequence2.getElement(s2)) {
39 > if (s1 === 0 || s2 === 0) {
40 > extendedSeqScore = 0;
41 > } else {
42 > extendedSeqScore = lcsLengths.get(s1 - 1, s2 - 1);
43 > }
44 > if (s1 > 0 && s2 > 0 && directions.get(s1 - 1, s2 - 1) === 3) {
45 > // Prefer consecutive diagonals
46 > extendedSeqScore += lengths.get(s1 - 1, s2 - 1);
47 > }
48 > extendedSeqScore += (equalityScore ? equalityScore(s1, s2) : 1);
49 > } else {
50 > extendedSeqScore = -1;
51 > }
52 >
53 > const newValue = Math.max(horizontalLen, verticalLen, extendedSeqScore);
54 >
55 > if (newValue === extendedSeqScore) {
56 > // Prefer diagonals
57 > const prevLen = s1 > 0 && s2 > 0 ? lengths.get(s1 - 1, s2 - 1) : 0;
58 > lengths.set(s1, s2, prevLen + 1);
59 > directions.set(s1, s2, 3);
60 > } else if (newValue === horizontalLen) {
61 > lengths.set(s1, s2, 0);
62 > directions.set(s1, s2, 1);
63 > } else if (newValue === verticalLen) {
64 > lengths.set(s1, s2, 0); dynamicProgrammingDiffing.ts
65 > directions.set(s1, s2, 2);
66 > }
68 > lcsLengths.set(s1, s2, newValue);
69 > }
70 > }
71 >
72 > // ==== Backtracking ====
73 > const result: SequenceDiff[] = [];
74 > let lastAligningPosS1: number = sequence1.length;
75 > let lastAligningPosS2: number = sequence2.length;
76 >
77 > function reportDecreasingAligningPositions(s1: number, s2: number): void {
78 > if (s1 + 1 !== lastAligningPosS1 || s2 + 1 !== lastAligningPosS2) {
79 > result.push(new SequenceDiff( dynamicProgrammingDiffing.ts
80 > new OffsetRange(s1 + 1, lastAligningPosS1),
81 > new OffsetRange(s2 + 1, lastAligningPosS2),
82 > ));
83 > }
84 > lastAligningPosS1 = s1; dynamicProgrammingDiffing.ts
85 > lastAligningPosS2 = s2;
86 > }
87 >
88 > let s1 = sequence1.length - 1;
89 > let s2 = sequence2.length - 1;
90 > while (s1 >= 0 && s2 >= 0) {
91 > if (directions.get(s1, s2) === 3) {
92 > reportDecreasingAligningPositions(s1, s2);
93 > s1--;
94 > s2--;
95 > } else {
96 > if (directions.get(s1, s2) === 1) { dynamicProgrammingDiffing.ts
100 > }
103 > reportDecreasingAligningPositions(-1, -1);
104 > result.reverse();
105 > return new DiffAlgorithmResult(result, false);
106 > }
src/vs/editor/common/model/prefixSumComputer.ts 103 covered LOC · 20 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- prefixSumComputer.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 { arrayInsert } from '../../../base/common/arrays.js';
7 > import { toUint32 } from '../../../base/common/uint.js';
8 >
9 > export class PrefixSumComputer {
10 >
11 > /**
12 > * values[i] is the value at index i
13 > */
14 > private values: Uint32Array;
15 >
16 > /**
17 > * prefixSum[i] = SUM(heights[j]), 0 <= j <= i
18 > */
19 > private prefixSum: Uint32Array;
20 >
21 > /**
22 > * prefixSum[i], 0 <= i <= prefixSumValidIndex can be trusted
23 > */
24 > private readonly prefixSumValidIndex: Int32Array;
25 >
26 > constructor(values: Uint32Array) {
27 this.values = values;
28 this.prefixSum = new Uint32Array(values.length);
30 this.prefixSumValidIndex[0] = -1;
31 }
33 > public getCount(): number {
34 return this.values.length;
35 }
37 > public insertValues(insertIndex: number, insertValues: Uint32Array): boolean {
38 insertIndex = toUint32(insertIndex);
39 const oldValues = this.values;
60 return true;
61 }
63 > public setValue(index: number, value: number): boolean {
64 index = toUint32(index);
65 value = toUint32(value);
74 return true;
75 }
77 > public removeValues(startIndex: number, count: number): boolean {
78 startIndex = toUint32(startIndex);
79 count = toUint32(count);
108 return true;
109 }
111 > public getTotalSum(): number {
112 if (this.values.length === 0) {
113 return 0;
115 return this._getPrefixSum(this.values.length - 1);
116 }
118 > /**
119 > * Returns the sum of the first `index + 1` many items.
120 > * @returns `SUM(0 <= j <= index, values[j])`.
121 > */
122 > public getPrefixSum(index: number): number {
123 if (index < 0) {
124 return 0;
128 return this._getPrefixSum(index);
129 }
131 > private _getPrefixSum(index: number): number {
132 if (index <= this.prefixSumValidIndex[0]) {
133 return this.prefixSum[index];
150 return this.prefixSum[index];
151 }
153 > public getIndexOf(sum: number): PrefixSumIndexOfResult {
154 sum = Math.floor(sum);
155
180 return new PrefixSumIndexOfResult(mid, sum - midStart);
181 }
183 >
184 > /**
185 > * {@link getIndexOf} has an amortized runtime complexity of O(1).
186 > *
187 > * ({@link PrefixSumComputer.getIndexOf} is just O(log n))
188 > */
189 > export class ConstantTimePrefixSumComputer {
190 > private _values: number[];
191 > private _isValid: boolean;
192 > private _validEndIndex: number;
193 >
194 > /**
195 > * _prefixSum[i] = SUM(values[j]), 0 <= j <= i
196 > */
197 > private _prefixSum: number[];
198 >
199 > /**
200 > * _indexBySum[sum] = idx => _prefixSum[idx - 1] <= sum < _prefixSum[idx]
201 > */
202 > private _indexBySum: number[];
203 >
204 > constructor(values: number[]) {
205 this._values = values;
206 this._isValid = false;
209 this._indexBySum = [];
210 }
212 > /**
213 > * @returns SUM(0 <= j < values.length, values[j])
214 > */
215 > public getTotalSum(): number {
216 this._ensureValid();
217 return this._indexBySum.length;
218 }
220 > /**
221 > * Returns the sum of the first `count` many items.
222 > * @returns `SUM(0 <= j < count, values[j])`.
223 > */
224 > public getPrefixSum(count: number): number {
225 this._ensureValid();
226 if (count === 0) {
229 return this._prefixSum[count - 1];
230 }
232 > /**
233 > * @returns `result`, such that `getPrefixSum(result.index) + result.remainder = sum`
234 > */
235 > public getIndexOf(sum: number): PrefixSumIndexOfResult {
236 this._ensureValid();
237 const idx = this._indexBySum[sum];
245 return new PrefixSumIndexOfResult(idx, sum - viewLinesAbove);
246 }
248 > public removeValues(start: number, deleteCount: number): void {
249 this._values.splice(start, deleteCount);
250 this._invalidate(start);
251 }
253 > public insertValues(insertIndex: number, insertArr: number[]): void {
254 this._values = arrayInsert(this._values, insertIndex, insertArr);
255 this._invalidate(insertIndex);
256 }
258 > private _invalidate(index: number): void {
259 this._isValid = false;
260 this._validEndIndex = Math.min(this._validEndIndex, index - 1);
261 }
263 > private _ensureValid(): void {
264 if (this._isValid) {
265 return;
284 this._validEndIndex = this._values.length - 1;
285 }
287 > public setValue(index: number, value: number): void {
288 if (this._values[index] === value) {
289 // no change
293 this._invalidate(index);
294 }
296 >
297 >
298 > export class PrefixSumIndexOfResult {
299 > _prefixSumIndexOfResultBrand: void = undefined;
300 >
301 > constructor(
302 public readonly index: number,
303 public readonly remainder: number
src/vs/editor/common/model/mirrorTextModel.ts 99 covered LOC · 12 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mirrorTextModel.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 { splitLines } from '../../../base/common/strings.js';
7 > import { URI } from '../../../base/common/uri.js';
8 > import { Position } from '../core/position.js';
9 > import { IRange } from '../core/range.js';
10 > import { PrefixSumComputer } from './prefixSumComputer.js';
11 >
12 > export interface IModelContentChange {
13 > /**
14 > * The old range that got replaced.
15 > */
16 > readonly range: IRange;
17 > /**
18 > * The offset of the range that got replaced.
19 > */
20 > readonly rangeOffset: number;
21 > /**
22 > * The length of the range that got replaced.
23 > */
24 > readonly rangeLength: number;
25 > /**
26 > * The new text for the range.
27 > */
28 > readonly text: string;
29 > }
30 >
31 > export interface IModelChangedEvent {
32 > /**
33 > * The actual changes.
34 > */
35 > readonly changes: IModelContentChange[];
36 > /**
37 > * The (new) end-of-line character.
38 > */
39 > readonly eol: string;
40 > /**
41 > * The new version id the model has transitioned to.
42 > */
43 > readonly versionId: number;
44 > /**
45 > * Flag that indicates that this event was generated while undoing.
46 > */
47 > readonly isUndoing: boolean;
48 > /**
49 > * Flag that indicates that this event was generated while redoing.
50 > */
51 > readonly isRedoing: boolean;
52 > }
53 >
54 > export interface IMirrorTextModel {
55 > readonly version: number;
56 > }
57 >
58 > export class MirrorTextModel implements IMirrorTextModel {
59 >
60 > protected _uri: URI;
61 > protected _lines: string[];
62 > protected _eol: string;
63 > protected _versionId: number;
64 > protected _lineStarts: PrefixSumComputer | null;
65 > private _cachedTextValue: string | null;
66 >
67 > constructor(uri: URI, lines: string[], eol: string, versionId: number) {
68 > this._uri = uri; mirrorTextModel.ts
69 > this._lines = lines;
70 > this._eol = eol;
71 > this._versionId = versionId;
72 > this._lineStarts = null;
73 > this._cachedTextValue = null;
74 > }
76 > dispose(): void {
77 this._lines.length = 0;
78 }
80 > get version(): number {
81 return this._versionId;
82 }
84 > getText(): string {
85 > if (this._cachedTextValue === null) { mirrorTextModel.ts
86 > this._cachedTextValue = this._lines.join(this._eol);
87 > }
88 > return this._cachedTextValue;
89 > }
91 > onEvents(e: IModelChangedEvent): void {
92 if (e.eol && e.eol !== this._eol) {
93 this._eol = e.eol;
105 this._cachedTextValue = null;
106 }
108 > protected _ensureLineStarts(): void {
109 if (!this._lineStarts) {
110 const eolLength = this._eol.length;
117 }
118 }
120 > /**
121 > * All changes to a line's text go through this method
122 > */
123 > private _setLineText(lineIndex: number, newValue: string): void {
124 this._lines[lineIndex] = newValue;
125 if (this._lineStarts) {
128 }
129 }
131 > private _acceptDeleteRange(range: IRange): void {
132
133 if (range.startLineNumber === range.endLineNumber) {
157 }
158 }
160 > private _acceptInsertText(position: Position, insertText: string): void {
161 if (insertText.length === 0) {
162 // Nothing to insert
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/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/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/editor/common/model/textModelSearch.ts 88 covered LOC · 26 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelSearch.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 '../../../base/common/charCode.js';
7 > import * as strings from '../../../base/common/strings.js';
8 > import { WordCharacterClass, WordCharacterClassifier, getMapForWordSeparators } from '../core/wordCharacterClassifier.js';
9 > import { Position } from '../core/position.js';
10 > import { Range } from '../core/range.js';
11 > import { EndOfLinePreference, FindMatch, SearchData } from '../model.js';
12 > import { TextModel } from './textModel.js';
13 >
14 > const LIMIT_FIND_COUNT = 999;
15 >
16 > export class SearchParams {
17 > public readonly searchString: string;
18 > public readonly isRegex: boolean;
19 > public readonly matchCase: boolean;
20 > public readonly wordSeparators: string | null;
21 >
22 > constructor(searchString: string, isRegex: boolean, matchCase: boolean, wordSeparators: string | null) {
23 this.searchString = searchString;
24 this.isRegex = isRegex;
26 this.wordSeparators = wordSeparators;
27 }
29 > public parseSearchRequest(): SearchData | null {
30 if (this.searchString === '') {
31 return null;
65 return new SearchData(regex, this.wordSeparators ? getMapForWordSeparators(this.wordSeparators, []) : null, canUseSimpleSearch ? this.searchString : null);
66 }
68 >
69 > export function isMultilineRegexSource(searchString: string): boolean {
70 if (!searchString || searchString.length === 0) {
71 return false;
98 return false;
99 }
101 > export function createFindMatch(range: Range, rawMatches: RegExpExecArray, captureMatches: boolean): FindMatch {
102 if (!captureMatches) {
103 return new FindMatch(range, null);
109 return new FindMatch(range, matches);
110 }
112 > class LineFeedCounter {
113 >
114 > private readonly _lineFeedsOffsets: number[];
115 >
116 > constructor(text: string) {
117 const lineFeedsOffsets: number[] = [];
118 let lineFeedsOffsetsLen = 0;
124 this._lineFeedsOffsets = lineFeedsOffsets;
125 }
127 > public findLineFeedCountBeforeOffset(offset: number): number {
128 const lineFeedsOffsets = this._lineFeedsOffsets;
129 let min = 0;
157 return min + 1;
158 }
160 >
161 > export class TextModelSearch {
162 >
163 > public static findMatches(model: TextModel, searchParams: SearchParams, searchRange: Range, captureMatches: boolean, limitResultCount: number): FindMatch[] {
164 const searchData = searchParams.parseSearchRequest();
165 if (!searchData) {
172 return this._doFindMatchesLineByLine(model, searchRange, searchData, captureMatches, limitResultCount);
173 }
175 > /**
176 > * Multiline search always executes on the lines concatenated with \n.
177 > * We must therefore compensate for the count of \n in case the model is CRLF
178 > */
179 > private static _getMultilineMatchRange(model: TextModel, deltaOffset: number, text: string, lfCounter: LineFeedCounter | null, matchIndex: number, match0: string): Range {
180 let startOffset: number;
181 let lineFeedCountBeforeMatch = 0;
200 return new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
201 }
203 > private static _doFindMatchesMultiline(model: TextModel, searchRange: Range, searcher: Searcher, captureMatches: boolean, limitResultCount: number): FindMatch[] {
204 const deltaOffset = model.getOffsetAt(searchRange.getStartPosition());
205 // We always execute multiline search over the lines joined with \n
223 return result;
224 }
226 > private static _doFindMatchesLineByLine(model: TextModel, searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {
227 const result: FindMatch[] = [];
228 let resultLen = 0;
252 return result;
253 }
255 > private static _findMatchesInLine(searchData: SearchData, text: string, lineNumber: number, deltaOffset: number, resultLen: number, result: FindMatch[], captureMatches: boolean, limitResultCount: number): number {
256 const wordSeparators = searchData.wordSeparators;
257 if (!captureMatches && searchData.simpleSearch) {
287 return resultLen;
288 }
290 > public static findNextMatch(model: TextModel, searchParams: SearchParams, searchStart: Position, captureMatches: boolean): FindMatch | null {
291 const searchData = searchParams.parseSearchRequest();
292 if (!searchData) {
301 return this._doFindNextMatchLineByLine(model, searchStart, searcher, captureMatches);
302 }
304 > private static _doFindNextMatchMultiline(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {
305 const searchTextStart = new Position(searchStart.lineNumber, 1);
306 const deltaOffset = model.getOffsetAt(searchTextStart);
328 return null;
329 }
331 > private static _doFindNextMatchLineByLine(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {
332 const lineCount = model.getLineCount();
333 const startLineNumber = searchStart.lineNumber;
351 return null;
352 }
354 > private static _findFirstMatchInLine(searcher: Searcher, text: string, lineNumber: number, fromColumn: number, captureMatches: boolean): FindMatch | null {
355 // Set regex to search from column
356 searcher.reset(fromColumn - 1);
365 return null;
366 }
368 > public static findPreviousMatch(model: TextModel, searchParams: SearchParams, searchStart: Position, captureMatches: boolean): FindMatch | null {
369 const searchData = searchParams.parseSearchRequest();
370 if (!searchData) {
379 return this._doFindPreviousMatchLineByLine(model, searchStart, searcher, captureMatches);
380 }
382 > private static _doFindPreviousMatchMultiline(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {
383 const matches = this._doFindMatchesMultiline(model, new Range(1, 1, searchStart.lineNumber, searchStart.column), searcher, captureMatches, 10 * LIMIT_FIND_COUNT);
384 if (matches.length > 0) {
394 return null;
395 }
397 > private static _doFindPreviousMatchLineByLine(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {
398 const lineCount = model.getLineCount();
399 const startLineNumber = searchStart.lineNumber;
417 return null;
418 }
420 > private static _findLastMatchInLine(searcher: Searcher, text: string, lineNumber: number, captureMatches: boolean): FindMatch | null {
421 let bestResult: FindMatch | null = null;
422 let m: RegExpExecArray | null;
427 return bestResult;
428 }
430 >
431 function leftIsWordBounday(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {
432 if (matchStartIndex === 0) {
456 return false;
457 }
459 function rightIsWordBounday(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {
460 if (matchStartIndex + matchLength === textLength) {
484 return false;
485 }
487 > export function isValidMatch(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {
488 return (
489 leftIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength)
491 );
492 }
494 > export class Searcher {
495 > public readonly _wordSeparators: WordCharacterClassifier | null;
496 > private readonly _searchRegex: RegExp;
497 > private _prevMatchStartIndex: number;
498 > private _prevMatchLength: number;
499 >
500 > constructor(wordSeparators: WordCharacterClassifier | null, searchRegex: RegExp,) {
501 this._wordSeparators = wordSeparators;
502 this._searchRegex = searchRegex;
504 this._prevMatchLength = 0;
505 }
507 > public reset(lastIndex: number): void {
508 this._searchRegex.lastIndex = lastIndex;
509 this._prevMatchStartIndex = -1;
510 this._prevMatchLength = 0;
511 }
513 > public next(text: string): RegExpExecArray | null {
514 const textLength = text.length;
515
src/vs/editor/common/core/text/abstractText.ts 86 covered LOC · 25 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- abstractText.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 '../../../../base/common/assert.js';
7 > import { splitLines } from '../../../../base/common/strings.js';
8 > import { Position } from '../position.js';
9 > import { Range } from '../range.js';
10 > import { LineRange } from '../ranges/lineRange.js';
11 > import { OffsetRange } from '../ranges/offsetRange.js';
12 > import { TextLength } from '../text/textLength.js';
13 > import { PositionOffsetTransformer } from './positionToOffsetImpl.js';
14 >
15 > export abstract class AbstractText {
16 > abstract getValueOfRange(range: Range): string; abstractText.ts
17 > abstract readonly length: TextLength;
18 >
19 > get endPositionExclusive(): Position {
20 > return this.length.addToPosition(new Position(1, 1));
21 > }
22 >
23 > get lineRange(): LineRange {
24 return this.length.toLineRange();
25 }
27 > getValue(): string {
28 return this.getValueOfRange(this.length.toRange());
29 }
31 > getValueOfOffsetRange(range: OffsetRange): string {
32 return this.getValueOfRange(this.getTransformer().getRange(range));
33 }
35 > getLineLength(lineNumber: number): number {
36 return this.getValueOfRange(new Range(lineNumber, 1, lineNumber, Number.MAX_SAFE_INTEGER)).length;
37 }
39 > private _transformer: PositionOffsetTransformer | undefined = undefined;
41 > getTransformer(): PositionOffsetTransformer {
42 if (!this._transformer) {
43 this._transformer = new PositionOffsetTransformer(this.getValue());
45 return this._transformer;
46 }
48 > getLineAt(lineNumber: number): string {
49 return this.getValueOfRange(new Range(lineNumber, 1, lineNumber, Number.MAX_SAFE_INTEGER));
50 }
52 > getLines(): string[] {
53 const value = this.getValue();
54 return splitLines(value);
55 }
57 > getLinesOfRange(range: LineRange): string[] {
58 return range.mapToLineArray(lineNumber => this.getLineAt(lineNumber));
59 }
61 > equals(other: AbstractText): boolean {
62 if (this === other) {
63 return true;
65 return this.getValue() === other.getValue();
66 }
68 >
69 > export class LineBasedText extends AbstractText {
70 > constructor(
71 > private readonly _getLineContent: (lineNumber: number) => string, abstractText.ts
72 > private readonly _lineCount: number
73 > ) {
74 > assert(_lineCount >= 1);
75 >
76 > super();
77 > }
79 > override getValueOfRange(range: Range): string {
80 if (range.startLineNumber === range.endLineNumber) {
81 return this._getLineContent(range.startLineNumber).substring(range.startColumn - 1, range.endColumn - 1);
88 return result;
89 }
91 > override getLineLength(lineNumber: number): number {
92 > return this._getLineContent(lineNumber).length; abstractText.ts
93 > }
95 > get length(): TextLength {
96 > const lastLine = this._getLineContent(this._lineCount); abstractText.ts
97 > return new TextLength(this._lineCount - 1, lastLine.length);
98 > }
100 >
101 > export class ArrayText extends LineBasedText {
102 > constructor(lines: string[]) {
103 > super( abstractText.ts
104 > lineNumber => lines[lineNumber - 1],
105 > lines.length
106 > );
107 > }
108 > } abstractText.ts
109 >
110 > export class StringText extends AbstractText {
111 > private readonly _t;
112 >
113 > constructor(public readonly value: string) {
114 super();
115 this._t = new PositionOffsetTransformer(this.value);
116 }
118 > getValueOfRange(range: Range): string {
119 return this._t.getOffsetRange(range).substring(this.value);
120 }
122 > get length(): TextLength {
123 return this._t.textLength;
124 }
126 > // Override the getTransformer method to return the cached transformer
127 > override getTransformer() {
128 return this._t;
129 }
130 > } abstractText.ts
src/vs/editor/common/languages/linkComputer.ts 82 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- linkComputer.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 '../../../base/common/charCode.js';
7 > import { CharacterClassifier } from '../core/characterClassifier.js';
8 > import { ILink } from '../languages.js';
9 >
10 > export interface ILinkComputerTarget {
11 > getLineCount(): number;
12 > getLineContent(lineNumber: number): string;
13 > }
14 >
15 > export const enum State {
16 > Invalid = 0,
17 > Start = 1,
18 > H = 2,
19 > HT = 3,
20 > HTT = 4,
21 > HTTP = 5,
22 > F = 6,
23 > FI = 7,
24 > FIL = 8,
25 > BeforeColon = 9,
26 > AfterColon = 10,
27 > AlmostThere = 11,
28 > End = 12,
29 > Accept = 13,
30 > LastKnownState = 14 // marker, custom states may follow
31 > }
32 >
33 > export type Edge = [State, number, State];
34 >
35 > class Uint8Matrix {
36 >
37 > private readonly _data: Uint8Array;
38 > public readonly rows: number;
39 > public readonly cols: number;
40 >
41 > constructor(rows: number, cols: number, defaultValue: number) {
42 const data = new Uint8Array(rows * cols);
43 for (let i = 0, len = rows * cols; i < len; i++) {
49 this.cols = cols;
50 }
52 > public get(row: number, col: number): number {
53 return this._data[row * this.cols + col];
54 }
56 > public set(row: number, col: number, value: number): void {
57 this._data[row * this.cols + col] = value;
58 }
60 >
61 > export class StateMachine {
62 >
63 > private readonly _states: Uint8Matrix;
64 > private readonly _maxCharCode: number;
65 >
66 > constructor(edges: Edge[]) {
67 let maxCharCode = 0;
68 let maxState = State.Invalid;
92 this._maxCharCode = maxCharCode;
93 }
95 > public nextState(currentState: State, chCode: number): State {
96 if (chCode < 0 || chCode >= this._maxCharCode) {
97 return State.Invalid;
99 return this._states.get(currentState, chCode);
100 }
101 > } linkComputer.ts
102 >
103 > // State machine for http:// or https:// or file://
104 > let _stateMachine: StateMachine | null = null;
105 function getStateMachine(): StateMachine {
106 if (_stateMachine === null) {
142 return _stateMachine;
143 }
145 >
146 > const enum CharacterClass {
147 > None = 0,
148 > ForceTermination = 1,
149 > CannotEndIn = 2
150 > }
151 >
152 > let _classifier: CharacterClassifier<CharacterClass> | null = null;
153 function getClassifier(): CharacterClassifier<CharacterClass> {
154 if (_classifier === null) {
168 return _classifier;
169 }
171 > export class LinkComputer {
172 >
173 > private static _createLink(classifier: CharacterClassifier<CharacterClass>, line: string, lineNumber: number, linkBeginIndex: number, linkEndIndex: number): ILink {
174 // Do not allow to end link in certain characters...
175 let lastIncludedCharIndex = linkEndIndex - 1;
210 };
211 }
213 > public static computeLinks(model: ILinkComputerTarget, stateMachine: StateMachine = getStateMachine()): ILink[] {
214 const classifier = getClassifier();
215
336 return result;
337 }
338 > } linkComputer.ts
339 >
340 > /**
341 > * Returns an array of all links contains in the provided
342 > * document. *Note* that this operation is computational
343 > * expensive and should not run in the UI thread.
344 > */
345 > export function computeLinks(model: ILinkComputerTarget | null): ILink[] {
346 if (!model || typeof model.getLineCount !== 'function' || typeof model.getLineContent !== 'function') {
347 // Unknown caller!
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/hash.ts 74 covered LOC · 17 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- hash.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 { encodeHex, VSBuffer } from './buffer.js';
7 > import * as strings from './strings.js';
8 >
9 > type NotSyncHashable = ArrayBufferLike | ArrayBufferView;
10 >
11 > /**
12 > * Return a hash value for an object.
13 > *
14 > * Note that this should not be used for binary data types. Instead,
15 > * prefer {@link hashAsync}.
16 > */
17 > export function hash<T>(obj: T extends NotSyncHashable ? never : T): number {
18 return doHash(obj, 0);
19 }
20 > hash.ts
21 > export function doHash(obj: unknown, hashVal: number): number {
22 switch (typeof obj) {
23 case 'object':
40 }
41 }
42 > hash.ts
43 > export function numberHash(val: number, initialHashVal: number): number {
44 return (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32
45 }
46 > hash.ts
47 function booleanHash(b: boolean, initialHashVal: number): number {
48 return numberHash(b ? 433 : 863, initialHashVal);
49 }
50 > hash.ts
51 > export function stringHash(s: string, hashVal: number) {
52 hashVal = numberHash(149417, hashVal);
53 for (let i = 0, length = s.length; i < length; i++) {
56 return hashVal;
57 }
58 > hash.ts
59 function arrayHash(arr: unknown[], initialHashVal: number): number {
60 initialHashVal = numberHash(104579, initialHashVal);
61 return arr.reduce<number>((hashVal, item) => doHash(item, hashVal), initialHashVal);
62 }
63 > hash.ts
64 function objectHash(obj: object, initialHashVal: number): number {
65 initialHashVal = numberHash(181387, initialHashVal);
69 }, initialHashVal);
70 }
71 > hash.ts
72 >
73 >
74 > /** Hashes the input as SHA-1, returning a hex-encoded string. */
75 > export const hashAsync = (input: string | ArrayBufferView | VSBuffer) => {
76 // Note: I would very much like to expose a streaming interface for hashing
77 // generally, but this is not available in web crypto yet, see
96 return crypto.subtle.digest('sha-1', buff as ArrayBufferView<ArrayBuffer>).then(toHexString); // CodeQL [SM04514] we use sha1 here for validating old stored client state, not for security
97 };
98 > hash.ts
99 > const enum SHA1Constant {
100 > BLOCK_SIZE = 64, // 512 / 8
101 > UNICODE_REPLACEMENT = 0xFFFD,
102 > }
103 >
104 function leftRotate(value: number, bits: number, totalBits: number = 32): number {
105 // delta + bits = totalBits
112 return ((value << bits) | ((mask & value) >>> delta)) >>> 0;
113 }
114 > hash.ts
115 > function toHexString(buffer: ArrayBuffer): string;
116 > function toHexString(value: number, bitsize?: number): string;
117 function toHexString(bufferOrValue: ArrayBuffer | number, bitsize: number = 32): string {
118 if (bufferOrValue instanceof ArrayBuffer) {
122 return (bufferOrValue >>> 0).toString(16).padStart(bitsize / 4, '0');
123 }
124 > hash.ts
125 > /**
126 > * A SHA1 implementation that works with strings and does not allocate.
127 > *
128 > * Prefer to use {@link hashAsync} in async contexts
129 > */
130 > export class StringSHA1 {
131 > private static _bigBlock32 = new DataView(new ArrayBuffer(320)); // 80 * 4 = 320
132 >
133 > private _h0 = 0x67452301;
134 > private _h1 = 0xEFCDAB89;
135 > private _h2 = 0x98BADCFE;
136 > private _h3 = 0x10325476;
137 > private _h4 = 0xC3D2E1F0;
138 >
139 > private readonly _buff: Uint8Array;
140 > private readonly _buffDV: DataView;
141 > private _buffLen: number;
142 > private _totalLen: number;
143 > private _leftoverHighSurrogate: number;
144 > private _finished: boolean;
145 >
146 > constructor() {
147 this._buff = new Uint8Array(SHA1Constant.BLOCK_SIZE + 3 /* to fit any utf-8 */);
148 this._buffDV = new DataView(this._buff.buffer);
152 this._finished = false;
153 }
154 > hash.ts
155 > public update(str: string): void {
156 const strLen = str.length;
157 if (strLen === 0) {
208 this._leftoverHighSurrogate = leftoverHighSurrogate;
209 }
210 > hash.ts
211 > private _push(buff: Uint8Array, buffLen: number, codePoint: number): number {
212 if (codePoint < 0x0080) {
213 buff[buffLen++] = codePoint;
238 return buffLen;
239 }
240 > hash.ts
241 > public digest(): string {
242 if (!this._finished) {
243 this._finished = true;
253 return toHexString(this._h0) + toHexString(this._h1) + toHexString(this._h2) + toHexString(this._h3) + toHexString(this._h4);
254 }
255 > hash.ts
256 > private _wrapUp(): void {
257 this._buff[this._buffLen++] = 0x80;
258 this._buff.subarray(this._buffLen).fill(0);
271 this._step();
272 }
273 > hash.ts
274 > private _step(): void {
275 const bigBlock32 = StringSHA1._bigBlock32;
276 const data = this._buffDV;
322 this._h4 = (this._h4 + e) & 0xffffffff;
323 }
324 > } hash.ts
src/vs/editor/common/core/text/positionToOffsetImpl.ts 73 covered LOC · 20 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- positionToOffsetImpl.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 { findLastIdxMonotonous } from '../../../../base/common/arraysFind.js';
7 > import { StringEdit, StringReplacement } from '../edits/stringEdit.js';
8 > import { OffsetRange } from '../ranges/offsetRange.js';
9 > import { Position } from '../position.js';
10 > import { Range } from '../range.js';
11 > import type { TextReplacement, TextEdit } from '../edits/textEdit.js';
12 > import type { TextLength } from '../text/textLength.js';
13 >
14 > export abstract class PositionOffsetTransformerBase {
15 > abstract getOffset(position: Position): number;
16 >
17 > getOffsetRange(range: Range): OffsetRange {
18 return new OffsetRange(
19 this.getOffset(range.getStartPosition()),
21 );
22 }
24 > abstract getPosition(offset: number): Position;
25 >
26 > getRange(offsetRange: OffsetRange): Range {
27 return Range.fromPositions(
28 this.getPosition(offsetRange.start),
30 );
31 }
33 > getStringEdit(edit: TextEdit): StringEdit {
34 const edits = edit.replacements.map(e => this.getStringReplacement(e));
35 return new Deps.deps.StringEdit(edits);
36 }
38 > getStringReplacement(edit: TextReplacement): StringReplacement {
39 return new Deps.deps.StringReplacement(this.getOffsetRange(edit.range), edit.text);
40 }
42 > getTextReplacement(edit: StringReplacement): TextReplacement {
43 return new Deps.deps.TextReplacement(this.getRange(edit.replaceRange), edit.newText);
44 }
46 > getTextEdit(edit: StringEdit): TextEdit {
47 const edits = edit.replacements.map(e => this.getTextReplacement(e));
48 return new Deps.deps.TextEdit(edits);
49 }
51 >
52 > interface IDeps {
53 > StringEdit: typeof StringEdit;
54 > StringReplacement: typeof StringReplacement;
55 > TextReplacement: typeof TextReplacement;
56 > TextEdit: typeof TextEdit;
57 > TextLength: typeof TextLength;
58 > }
59 >
60 > class Deps {
61 > static _deps: IDeps | undefined = undefined;
62 > static get deps(): IDeps {
63 if (!this._deps) {
64 throw new Error('Dependencies not set. Call _setDependencies first.');
66 return this._deps;
67 }
69 >
70 > /** This is to break circular module dependencies. */
71 > export function _setPositionOffsetTransformerDependencies(deps: IDeps): void {
72 > Deps._deps = deps; positionToOffsetImpl.ts
73 > }
75 > export class PositionOffsetTransformer extends PositionOffsetTransformerBase {
76 > private _lineStartOffsetByLineIdx: number[] | undefined;
77 > private _lineEndOffsetByLineIdx: number[] | undefined;
78 >
79 > constructor(public readonly text: string) {
80 super();
81 }
83 > private get lineStartOffsetByLineIdx(): number[] {
84 if (!this._lineStartOffsetByLineIdx) {
85 this._computeLineOffsets();
87 return this._lineStartOffsetByLineIdx!;
88 }
90 > private get lineEndOffsetByLineIdx(): number[] {
91 if (!this._lineEndOffsetByLineIdx) {
92 this._computeLineOffsets();
94 return this._lineEndOffsetByLineIdx!;
95 }
97 > private _computeLineOffsets(): void {
98 this._lineStartOffsetByLineIdx = [];
99 this._lineEndOffsetByLineIdx = [];
112 this._lineEndOffsetByLineIdx.push(this.text.length);
113 }
115 > override getOffset(position: Position): number {
116 const valPos = this._validatePosition(position);
117 return this.lineStartOffsetByLineIdx[valPos.lineNumber - 1] + valPos.column - 1;
118 }
120 > private _validatePosition(position: Position): Position {
121 if (position.lineNumber < 1) {
122 return new Position(1, 1);
136 return position;
137 }
139 > override getPosition(offset: number): Position {
140 const idx = findLastIdxMonotonous(this.lineStartOffsetByLineIdx, i => i <= offset);
141 const lineNumber = idx + 1;
143 return new Position(lineNumber, column);
144 }
146 > getTextLength(offsetRange: OffsetRange): TextLength {
147 return Deps.deps.TextLength.ofRange(this.getRange(offsetRange));
148 }
150 > get textLength(): TextLength {
151 const lineIdx = this.lineStartOffsetByLineIdx.length - 1;
152 return new Deps.deps.TextLength(lineIdx, this.text.length - this.lineStartOffsetByLineIdx[lineIdx]);
153 }
155 > getLineLength(lineNumber: number): number {
156 return this.lineEndOffsetByLineIdx[lineNumber - 1] - this.lineStartOffsetByLineIdx[lineNumber - 1];
157 }
src/vs/editor/common/core/wordHelper.ts 70 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- wordHelper.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 { Iterable } from '../../../base/common/iterator.js';
7 > import { toDisposable } from '../../../base/common/lifecycle.js';
8 > import { LinkedList } from '../../../base/common/linkedList.js';
9 >
10 > export const USUAL_WORD_SEPARATORS = '`~!@#$%^&*()-=+[{]}\\|;:\'",.<>/?';
11 >
12 > /**
13 > * Word inside a model.
14 > */
15 > export interface IWordAtPosition {
16 > /**
17 > * The word.
18 > */
19 > readonly word: string;
20 > /**
21 > * The column where the word starts.
22 > */
23 > readonly startColumn: number;
24 > /**
25 > * The column where the word ends.
26 > */
27 > readonly endColumn: number;
28 > }
29 >
30 > /**
31 > * Create a word definition regular expression based on default word separators.
32 > * Optionally provide allowed separators that should be included in words.
33 > *
34 > * The default would look like this:
35 > * /(-?\d*\.\d\w*)|([^\`\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g
36 > */
37 > function createWordRegExp(allowInWords: string = ''): RegExp {
38 > let source = '(-?\\d*\\.\\d\\w*)|([^';
39 > for (const sep of USUAL_WORD_SEPARATORS) {
40 > if (allowInWords.indexOf(sep) >= 0) {
41 continue;
42 }
43 > source += '\\' + sep; wordHelper.ts
44 > }
45 > source += '\\s]+)';
46 > return new RegExp(source, 'g');
47 > }
48 >
49 > // catches numbers (including floating numbers) in the first group, and alphanum in the second
50 > export const DEFAULT_WORD_REGEXP = createWordRegExp();
51 >
52 > export function ensureValidWordDefinition(wordDefinition?: RegExp | null): RegExp {
53 let result: RegExp = DEFAULT_WORD_REGEXP;
54
75 return result;
76 }
78 >
79 > export interface IGetWordAtTextConfig {
80 > maxLen: number;
81 > windowSize: number;
82 > timeBudget: number;
83 > }
84 >
85 >
86 > const _defaultConfig = new LinkedList<IGetWordAtTextConfig>();
87 > _defaultConfig.unshift({
88 > maxLen: 1000,
89 > windowSize: 15,
90 > timeBudget: 150
91 > });
92 >
93 > export function setDefaultGetWordAtTextConfig(value: IGetWordAtTextConfig) {
94 const rm = _defaultConfig.unshift(value);
95 return toDisposable(rm);
96 }
98 > export function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number, config?: IGetWordAtTextConfig): IWordAtPosition | null {
99 // Ensure the regex has the 'g' flag, otherwise this will loop forever
100 wordDefinition = ensureValidWordDefinition(wordDefinition);
161 return null;
162 }
164 function _findRegexMatchEnclosingPosition(wordDefinition: RegExp, text: string, pos: number, stopPos: number): RegExpExecArray | null {
165 let match: RegExpExecArray | null;
src/vs/base/common/objects.ts 65 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- objects.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 { isTypedArray, isObject, isUndefinedOrNull } from './types.js';
7 >
8 > export function deepClone<T>(obj: T): T {
9 if (!obj || typeof obj !== 'object') {
10 return obj;
19 return result;
20 }
21 > objects.ts
22 > export function deepFreeze<T>(obj: T): T {
23 if (!obj || typeof obj !== 'object') {
24 return obj;
39 return obj;
40 }
41 > objects.ts
42 > const _hasOwnProperty = Object.prototype.hasOwnProperty;
43 >
44 >
45 > export function cloneAndChange(obj: any, changer: (orig: any) => any): any {
46 return _cloneAndChange(obj, changer, new Set());
47 }
48 > objects.ts
49 function _cloneAndChange(obj: any, changer: (orig: any) => any, seen: Set<any>): any {
50 if (isUndefinedOrNull(obj)) {
82 return obj;
83 }
84 > objects.ts
85 > /**
86 > * Copies all properties of source into destination. The optional parameter "overwrite" allows to control
87 > * if existing properties on the destination should be overwritten or not. Defaults to true (overwrite).
88 > */
89 > export function mixin(destination: any, source: any, overwrite: boolean = true): any {
90 if (!isObject(destination)) {
91 return source;
109 return destination;
110 }
111 > objects.ts
112 > export function equals(one: any, other: any): boolean {
113 if (one === other) {
114 return true;
162 return true;
163 }
164 > objects.ts
165 > /**
166 > * Calls `JSON.Stringify` with a replacer to break apart any circular references.
167 > * This prevents `JSON`.stringify` from throwing the exception
168 > * "Uncaught TypeError: Converting circular structure to JSON"
169 > */
170 > export function safeStringify(obj: any): string {
171 const seen = new Set<any>();
172 return JSON.stringify(obj, (key, value) => {
184 });
185 }
186 > objects.ts
187 > /**
188 > * Like `JSON.stringify`, but with deterministic ordering of object keys so that
189 > * structurally equal inputs always produce the same string. Useful for cache
190 > * keys derived from arbitrary object payloads.
191 > *
192 > * - Object keys are sorted at every level of nesting.
193 > * - Properties whose value is `undefined` are omitted (matching `JSON.stringify`).
194 > * - Circular references are replaced with the string `"[Circular]"` to avoid
195 > * throwing.
196 > * - A top-level `undefined` returns the string `'undefined'`; any other
197 > * stringification failure returns the empty string.
198 > */
199 > export function stableStringify(value: unknown): string {
200 if (value === undefined) {
201 return 'undefined';
207 }
208 }
209 > objects.ts
210 function _stableStringify(value: unknown, seen: WeakSet<object>): string {
211 if (value === null || typeof value !== 'object') {
230 return '{' + parts.join(',') + '}';
231 }
232 > objects.ts
233 > type obj = { [key: string]: any };
234 > /**
235 > * Returns an object that has keys for each value that is different in the base object. Keys
236 > * that do not exist in the target but in the base object are not considered.
237 > *
238 > * Note: This is not a deep-diffing method, so the values are strictly taken into the resulting
239 > * object if they differ.
240 > *
241 > * @param base the object to diff against
242 > * @param obj the object to use for diffing
243 > */
244 > export function distinct(base: obj, target: obj): obj {
245 const result = Object.create(null);
246
261 return result;
262 }
263 > objects.ts
264 > export function getCaseInsensitive(target: obj, key: string): unknown {
265 const lowercaseKey = key.toLowerCase();
266 const equivalentKey = Object.keys(target).find(k => k.toLowerCase() === lowercaseKey);
267 return equivalentKey ? target[equivalentKey] : target[key];
268 }
269 > objects.ts
270 > export function filter(obj: obj, predicate: (key: string, value: any) => boolean): obj {
271 const result = Object.create(null);
272 for (const [key, value] of Object.entries(obj)) {
277 return result;
278 }
279 > objects.ts
280 > export function mapValues<T extends {}, R>(obj: T, fn: (value: T[keyof T], key: string) => R): { [K in keyof T]: R } {
281 const result: { [key: string]: R } = {};
282 for (const [key, value] of Object.entries(obj)) {
src/vs/editor/common/services/unicodeTextModelHighlighter.ts 65 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- unicodeTextModelHighlighter.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 { IRange, Range } from '../core/range.js';
7 > import { Searcher } from '../model/textModelSearch.js';
8 > import * as strings from '../../../base/common/strings.js';
9 > import { IUnicodeHighlightsResult } from './editorWorker.js';
10 > import { assertNever } from '../../../base/common/assert.js';
11 > import { DEFAULT_WORD_REGEXP, getWordAtText } from '../core/wordHelper.js';
12 >
13 > export class UnicodeTextModelHighlighter {
14 > public static computeUnicodeHighlights(model: IUnicodeCharacterSearcherTarget, options: UnicodeHighlighterOptions, range?: IRange): IUnicodeHighlightsResult {
15 const startLine = range ? range.startLineNumber : 1;
16 const endLine = range ? range.endLineNumber : model.getLineCount();
99 };
100 }
102 > public static computeUnicodeHighlightReason(char: string, options: UnicodeHighlighterOptions): UnicodeHighlighterReason | null {
103 const codePointHighlighter = new CodePointHighlighter(options);
104
126 }
127 }
129 >
130 function buildRegExpCharClassExpr(codePoints: number[], flags?: string): string {
131 const src = `[${strings.escapeRegExpCharacters(
134 return src;
135 }
137 > export const enum UnicodeHighlighterReasonKind {
138 > Ambiguous, Invisible, NonBasicAscii
139 > }
140 >
141 > export type UnicodeHighlighterReason = {
142 > kind: UnicodeHighlighterReasonKind.Ambiguous;
143 > confusableWith: string;
144 > notAmbiguousInLocales: string[];
145 > } | {
146 > kind: UnicodeHighlighterReasonKind.Invisible;
147 > } | {
148 > kind: UnicodeHighlighterReasonKind.NonBasicAscii;
149 > };
150 >
151 > class CodePointHighlighter {
152 > private readonly allowedCodePoints: Set<number>;
153 > public readonly ambiguousCharacters: strings.AmbiguousCharacters;
154 > constructor(private readonly options: UnicodeHighlighterOptions) {
155 this.allowedCodePoints = new Set(options.allowedCodePoints);
156 this.ambiguousCharacters = strings.AmbiguousCharacters.getInstance(new Set(options.allowedLocales));
157 }
159 > public getCandidateCodePoints(): Set<number> | 'allNonBasicAscii' {
160 if (this.options.nonBasicASCII) {
161 return 'allNonBasicAscii';
184 return set;
185 }
187 > public shouldHighlightNonBasicASCII(character: string, wordContext: string | null): SimpleHighlightReason {
188 const codePoint = character.codePointAt(0)!;
189
236 return SimpleHighlightReason.None;
237 }
239 >
240 function isAllowedInvisibleCharacter(character: string): boolean {
241 return character === ' ' || character === '\n' || character === '\t';
242 }
244 > const enum SimpleHighlightReason {
245 > None,
246 > NonBasicASCII,
247 > Invisible,
248 > Ambiguous
249 > }
250 >
251 > export interface IUnicodeCharacterSearcherTarget {
252 > getLineCount(): number;
253 > getLineContent(lineNumber: number): string;
254 > }
255 >
256 > export interface UnicodeHighlighterOptions {
257 > nonBasicASCII: boolean;
258 > ambiguousCharacters: boolean;
259 > invisibleCharacters: boolean;
260 > includeComments: boolean;
261 > includeStrings: boolean;
262 > allowedCodePoints: number[];
263 > allowedLocales: string[];
264 > }
src/vs/base/common/assert.ts 64 covered LOC · 15 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) {
24 throw new Error(message ? `Assertion failed (${message})` : 'Assertion Failed');
25 }
26 }
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, assert.ts
46 > messageOrError: string | Error = 'unexpected state',
47 > ): asserts condition {
48 > if (!condition) {
49 // if error instance is provided, use it, otherwise create a new one
50 const errorToThrow = typeof messageOrError === 'string'
54 throw errorToThrow;
55 }
56 > } assert.ts
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()) { assert.ts
72 // eslint-disable-next-line no-debugger
73 debugger;
76 onUnexpectedError(new BugIndicatingError('Assertion Failed'));
77 }
78 > } assert.ts
79 > assert.ts
80 > export function checkAdjacentItems<T>(items: readonly T[], predicate: (item1: T, item2: T) => boolean): boolean {
81 > let i = 0; assert.ts
82 > while (i < items.length - 1) {
83 > const a = items[i]; assert.ts
84 > const b = items[i + 1];
85 > if (!predicate(a, b)) {
86 return false;
87 }
88 > i++; assert.ts
89 > }
90 > return true; assert.ts
91 > }
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/editor/common/tokenizationRegistry.ts 62 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tokenizationRegistry.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 { Color } from '../../base/common/color.js';
7 > import { Emitter, Event } from '../../base/common/event.js';
8 > import { Disposable, IDisposable, toDisposable } from '../../base/common/lifecycle.js';
9 > import { ITokenizationRegistry, ITokenizationSupportChangedEvent, ILazyTokenizationSupport } from './languages.js';
10 > import { ColorId } from './encodedTokenAttributes.js';
11 >
12 > export class TokenizationRegistry<TSupport> implements ITokenizationRegistry<TSupport> {
13 >
14 > private readonly _tokenizationSupports = new Map<string, TSupport>();
15 > private readonly _factories = new Map<string, TokenizationSupportFactoryData<TSupport>>();
16 >
17 > private readonly _onDidChange = new Emitter<ITokenizationSupportChangedEvent>();
18 > public readonly onDidChange: Event<ITokenizationSupportChangedEvent> = this._onDidChange.event;
19 >
20 > private _colorMap: Color[] | null;
21 >
22 > constructor() {
23 > this._colorMap = null;
24 > }
25 >
26 > public handleChange(languageIds: string[]): void {
27 this._onDidChange.fire({
28 changedLanguages: languageIds,
30 });
31 }
33 > public register(languageId: string, support: TSupport): IDisposable {
34 this._tokenizationSupports.set(languageId, support);
35 this.handleChange([languageId]);
42 });
43 }
45 > public get(languageId: string): TSupport | null {
46 return this._tokenizationSupports.get(languageId) || null;
47 }
49 > public registerFactory(languageId: string, factory: ILazyTokenizationSupport<TSupport>): IDisposable {
50 this._factories.get(languageId)?.dispose();
51 const myData = new TokenizationSupportFactoryData(this, languageId, factory);
60 });
61 }
63 > public async getOrCreate(languageId: string): Promise<TSupport | null> {
64 // check first if the support is already set
65 const tokenizationSupport = this.get(languageId);
78 return this.get(languageId);
79 }
81 > public isResolved(languageId: string): boolean {
82 const tokenizationSupport = this.get(languageId);
83 if (tokenizationSupport) {
92 return false;
93 }
95 > public setColorMap(colorMap: Color[]): void {
96 this._colorMap = colorMap;
97 this._onDidChange.fire({
100 });
101 }
103 > public getColorMap(): Color[] | null {
104 return this._colorMap;
105 }
107 > public getDefaultBackground(): Color | null {
108 if (this._colorMap && this._colorMap.length > ColorId.DefaultBackground) {
109 return this._colorMap[ColorId.DefaultBackground];
111 return null;
112 }
114 >
115 > class TokenizationSupportFactoryData<TSupport> extends Disposable {
116 >
117 > private _isDisposed: boolean = false;
118 > private _resolvePromise: Promise<void> | null = null;
119 > private _isResolved: boolean = false;
120 >
121 > public get isResolved(): boolean {
122 > return this._isResolved;
123 > }
124 >
125 > constructor(
126 private readonly _registry: TokenizationRegistry<TSupport>,
127 private readonly _languageId: string,
130 super();
131 }
133 > public override dispose(): void {
134 this._isDisposed = true;
135 super.dispose();
136 }
138 > public async resolve(): Promise<void> {
139 if (!this._resolvePromise) {
140 this._resolvePromise = this._create();
142 return this._resolvePromise;
143 }
145 > private async _create(): Promise<void> {
146 const value = await this._factory.tokenizationSupport;
147 this._isResolved = true;
src/vs/base/common/linkedList.ts 61 covered LOC · 18 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> {
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); linkedList.ts
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); linkedList.ts
59 > if (this._first === Node.Undefined) {
60 > this._first = newNode;
61 > this._last = newNode;
62 >
63 > } else if (atTheEnd) {
64 // push
65 const oldLast = this._last;
75 oldFirst.prev = newNode;
76 }
77 > this._size += 1; linkedList.ts
78 >
79 > let didRemove = false;
80 > return () => {
81 if (!didRemove) {
82 didRemove = true;
84 }
85 };
86 > } linkedList.ts
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/editor/common/core/text/textLength.ts 60 covered LOC · 21 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textLength.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 { LineRange } from '../ranges/lineRange.js';
6 > import { Position } from '../position.js';
7 > import { Range } from '../range.js';
8 > import { OffsetRange } from '../ranges/offsetRange.js';
9 >
10 > /**
11 > * Represents a non-negative length of text in terms of line and column count.
12 > */
13 > export class TextLength {
14 > public static zero = new TextLength(0, 0);
15 >
16 > public static lengthDiffNonNegative(start: TextLength, end: TextLength): TextLength {
17 if (end.isLessThan(start)) {
18 return TextLength.zero;
24 }
25 }
27 > public static betweenPositions(position1: Position, position2: Position): TextLength {
28 if (position1.lineNumber === position2.lineNumber) {
29 return new TextLength(0, position2.column - position1.column);
32 }
33 }
35 > public static fromPosition(pos: Position): TextLength {
36 return new TextLength(pos.lineNumber - 1, pos.column - 1);
37 }
39 > public static ofRange(range: Range) {
40 return TextLength.betweenPositions(range.getStartPosition(), range.getEndPosition());
41 }
43 > public static ofText(text: string): TextLength {
44 let line = 0;
45 let column = 0;
54 return new TextLength(line, column);
55 }
57 > public static ofSubstr(str: string, range: OffsetRange): TextLength {
58 return TextLength.ofText(range.substring(str));
59 }
61 > public static sum<T>(fragments: readonly T[], getLength: (f: T) => TextLength): TextLength {
62 return fragments.reduce((acc, f) => acc.add(getLength(f)), TextLength.zero);
63 }
65 > constructor(
66 > public readonly lineCount: number,
67 > public readonly columnCount: number
68 > ) { }
69 >
70 > public isZero() {
71 return this.lineCount === 0 && this.columnCount === 0;
72 }
74 > public isLessThan(other: TextLength): boolean {
75 if (this.lineCount !== other.lineCount) {
76 return this.lineCount < other.lineCount;
78 return this.columnCount < other.columnCount;
79 }
81 > public isGreaterThan(other: TextLength): boolean {
82 if (this.lineCount !== other.lineCount) {
83 return this.lineCount > other.lineCount;
85 return this.columnCount > other.columnCount;
86 }
88 > public isGreaterThanOrEqualTo(other: TextLength): boolean {
89 if (this.lineCount !== other.lineCount) {
90 return this.lineCount > other.lineCount;
92 return this.columnCount >= other.columnCount;
93 }
95 > public equals(other: TextLength): boolean {
96 return this.lineCount === other.lineCount && this.columnCount === other.columnCount;
97 }
99 > public compare(other: TextLength): number {
100 if (this.lineCount !== other.lineCount) {
101 return this.lineCount - other.lineCount;
103 return this.columnCount - other.columnCount;
104 }
106 > public add(other: TextLength): TextLength {
107 if (other.lineCount === 0) {
108 return new TextLength(this.lineCount, this.columnCount + other.columnCount);
111 }
112 }
114 > public createRange(startPosition: Position): Range {
115 if (this.lineCount === 0) {
116 return new Range(startPosition.lineNumber, startPosition.column, startPosition.lineNumber, startPosition.column + this.columnCount);
119 }
120 }
122 > public toRange(): Range {
123 return new Range(1, 1, this.lineCount + 1, this.columnCount + 1);
124 }
126 > public toLineRange(): LineRange {
127 return LineRange.ofLength(1, this.lineCount + 1);
128 }
130 > public addToPosition(position: Position): Position {
131 if (this.lineCount === 0) {
132 return new Position(position.lineNumber, position.column + this.columnCount);
135 }
136 }
138 > public addToRange(range: Range): Range {
139 return Range.fromPositions(
140 this.addToPosition(range.getStartPosition()),
142 );
143 }
145 > toString() {
146 return `${this.lineCount},${this.columnCount}`;
147 }
148 > } textLength.ts
src/vs/amdX.ts 59 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- amdX.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 { AppResourcePath, FileAccess, nodeModulesAsarPath, nodeModulesPath, Schemas, VSCODE_AUTHORITY } from './base/common/network.js';
7 > import * as platform from './base/common/platform.js';
8 > import { IProductConfiguration } from './base/common/product.js';
9 > import { URI } from './base/common/uri.js';
10 > import { generateUuid } from './base/common/uuid.js';
11 >
12 > declare const window: any;
13 > declare const document: any;
14 > declare const self: any;
15 > declare const globalThis: any;
16 >
17 > class DefineCall {
18 > constructor(
19 public readonly id: string | null | undefined,
20 public readonly dependencies: string[] | null | undefined,
21 public readonly callback: any
22 ) { }
23 > } amdX.ts
24 >
25 > enum AMDModuleImporterState {
26 > Uninitialized = 1,
27 > InitializedInternal,
28 > InitializedExternal
29 > }
30 >
31 > class AMDModuleImporter {
32 > public static INSTANCE = new AMDModuleImporter();
33 >
34 > private readonly _isWebWorker = (typeof self === 'object' && self.constructor && self.constructor.name === 'DedicatedWorkerGlobalScope');
35 > private readonly _isRenderer = typeof document === 'object';
36 >
37 > private readonly _defineCalls: DefineCall[] = [];
38 > private _state = AMDModuleImporterState.Uninitialized;
39 > private _amdPolicy: Pick<TrustedTypePolicy, 'name' | 'createScriptURL'> | undefined;
40 >
41 > constructor() { }
42 >
43 > private _initialize(): void {
44 if (this._state === AMDModuleImporterState.Uninitialized) {
45 if (globalThis.define) {
91 }
92 }
93 > amdX.ts
94 > public async load<T>(scriptSrc: string): Promise<T> {
95 this._initialize();
96
134 }
135 }
136 > amdX.ts
137 > private _rendererLoadScript(scriptSrc: string): Promise<DefineCall | undefined> {
138 return new Promise<DefineCall | undefined>((resolve, reject) => {
139 const scriptElement = document.createElement('script');
165 });
166 }
167 > amdX.ts
168 > private async _workerLoadScript(scriptSrc: string): Promise<DefineCall | undefined> {
169 if (this._amdPolicy) {
170 scriptSrc = this._amdPolicy.createScriptURL(scriptSrc) as unknown as string;
173 return this._defineCalls.pop();
174 }
175 > amdX.ts
176 > private async _nodeJSLoadScript(scriptSrc: string): Promise<DefineCall | undefined> {
177 try {
178 // `import('module')` is not remapped (only `fs` is), so it yields the real
198 }
199 }
200 > } amdX.ts
201 >
202 > const cache = new Map<string, Promise<any>>();
203 >
204 > /**
205 > * Utility for importing an AMD node module. This util supports AMD and ESM contexts and should be used while the ESM adoption
206 > * is on its way.
207 > *
208 > * e.g. pass in `vscode-textmate/release/main.js`
209 > */
210 export async function importAMDNodeModule<T>(nodeModuleName: string, pathInsideNodeModule: string, isBuilt?: boolean): Promise<T> {
211 if (isBuilt === undefined) {
233 return result;
234 }
235 > amdX.ts
236 > export function resolveAmdNodeModulePath(nodeModuleName: string, pathInsideNodeModule: string): string {
237 const product = globalThis._VSCODE_PRODUCT_JSON as unknown as IProductConfiguration;
238 const isBuilt = Boolean((product ?? globalThis.vscode?.context?.configuration()?.product)?.commit);
src/vs/editor/common/services/findSectionHeaders.ts 58 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- findSectionHeaders.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 { IRange } from '../core/range.js';
7 > import { FoldingRules } from '../languages/languageConfiguration.js';
8 > import { isMultilineRegexSource } from '../model/textModelSearch.js';
9 > import { regExpLeadsToEndlessLoop } from '../../../base/common/strings.js';
10 >
11 > export interface ISectionHeaderFinderTarget {
12 > getLineCount(): number;
13 > getLineContent(lineNumber: number): string;
14 > }
15 >
16 > export interface FindSectionHeaderOptions {
17 > foldingRules?: FoldingRules;
18 > findRegionSectionHeaders: boolean;
19 > findMarkSectionHeaders: boolean;
20 > markSectionHeaderRegex: string;
21 > }
22 >
23 > export interface SectionHeader {
24 > /**
25 > * The location of the header text in the text model.
26 > */
27 > range: IRange;
28 > /**
29 > * The section header text.
30 > */
31 > text: string;
32 > /**
33 > * Whether the section header includes a separator line.
34 > */
35 > hasSeparatorLine: boolean;
36 > /**
37 > * This section should be omitted before rendering if it's not in a comment.
38 > */
39 > shouldBeInComments: boolean;
40 > }
41 >
42 > const trimDashesRegex = /^-+|-+$/g;
43 >
44 > const CHUNK_SIZE = 100;
45 > const MAX_SECTION_LINES = 5;
46 >
47 > /**
48 > * Find section headers in the model.
49 > *
50 > * @param model the text model to search in
51 > * @param options options to search with
52 > * @returns an array of section headers
53 > */
54 > export function findSectionHeaders(model: ISectionHeaderFinderTarget, options: FindSectionHeaderOptions): SectionHeader[] {
55 let headers: SectionHeader[] = [];
56 if (options.findRegionSectionHeaders && options.foldingRules?.markers) {
64 return headers;
65 }
67 function collectRegionHeaders(model: ISectionHeaderFinderTarget, options: FindSectionHeaderOptions): SectionHeader[] {
68 const regionHeaders: SectionHeader[] = [];
87 return regionHeaders;
88 }
90 > export function collectMarkHeaders(model: ISectionHeaderFinderTarget, options: FindSectionHeaderOptions): SectionHeader[] {
91 const markHeaders: SectionHeader[] = [];
92 const endLineNumber = model.getLineCount();
173 return markHeaders;
174 }
176 function getHeaderText(text: string): { text: string; hasSeparatorLine: boolean } {
177 text = text.trim();
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/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/editor/common/core/characterClassifier.ts 51 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- characterClassifier.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 { toUint8 } from '../../../base/common/uint.js';
7 >
8 > /**
9 > * A fast character classifier that uses a compact array for ASCII values.
10 > */
11 > export class CharacterClassifier<T extends number> {
12 > /**
13 > * Maintain a compact (fully initialized ASCII map for quickly classifying ASCII characters - used more often in code).
14 > */
15 > protected readonly _asciiMap: Uint8Array;
16 >
17 > /**
18 > * The entire map (sparse array).
19 > */
20 > protected readonly _map: Map<number, number>;
21 >
22 > protected readonly _defaultValue: number;
23 >
24 > constructor(_defaultValue: T) {
25 const defaultValue = toUint8(_defaultValue);
26
29 this._map = new Map<number, number>();
30 }
32 > private static _createAsciiMap(defaultValue: number): Uint8Array {
33 const asciiMap = new Uint8Array(256);
34 asciiMap.fill(defaultValue);
35 return asciiMap;
36 }
38 > public set(charCode: number, _value: T): void {
39 const value = toUint8(_value);
40
45 }
46 }
48 > public get(charCode: number): T {
49 if (charCode >= 0 && charCode < 256) {
50 return <T>this._asciiMap[charCode];
53 }
54 }
56 > public clear() {
57 this._asciiMap.fill(this._defaultValue);
58 this._map.clear();
59 }
61 >
62 > const enum Boolean {
63 > False = 0,
64 > True = 1
65 > }
66 >
67 > export class CharacterSet {
68 >
69 > private readonly _actual: CharacterClassifier<Boolean>;
70 >
71 > constructor() {
72 this._actual = new CharacterClassifier<Boolean>(Boolean.False);
73 }
75 > public add(charCode: number): void {
76 this._actual.set(charCode, Boolean.True);
77 }
79 > public has(charCode: number): boolean {
80 return (this._actual.get(charCode) === Boolean.True);
81 }
83 > public clear(): void {
84 return this._actual.clear();
85 }
src/vs/editor/common/diff/linesDiffComputer.ts 51 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- linesDiffComputer.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 { DetailedLineRangeMapping, LineRangeMapping } from './rangeMapping.js';
7 >
8 > export interface ILinesDiffComputer {
9 > computeDiff(originalLines: string[], modifiedLines: string[], options: ILinesDiffComputerOptions): LinesDiff;
10 > }
11 >
12 > export interface ILinesDiffComputerOptions {
13 > readonly ignoreTrimWhitespace: boolean;
14 > readonly maxComputationTimeMs: number;
15 > readonly computeMoves: boolean;
16 > readonly extendToSubwords?: boolean;
17 > }
18 >
19 > export class LinesDiff {
20 > constructor(
21 > readonly changes: readonly DetailedLineRangeMapping[], linesDiffComputer.ts
22 >
23 > /**
24 > * Sorted by original line ranges.
25 > * The original line ranges and the modified line ranges must be disjoint (but can be touching).
26 > */
27 > readonly moves: readonly MovedText[],
28 >
29 > /**
30 > * Indicates if the time out was reached.
31 > * In that case, the diffs might be an approximation and the user should be asked to rerun the diff with more time.
32 > */
33 > readonly hitTimeout: boolean,
34 > ) {
35 > }
37 >
38 > export class MovedText {
39 > public readonly lineRangeMapping: LineRangeMapping;
40 >
41 > /**
42 > * The diff from the original text to the moved text.
43 > * Must be contained in the original/modified line range.
44 > * Can be empty if the text didn't change (only moved).
45 > */
46 > public readonly changes: readonly DetailedLineRangeMapping[];
47 >
48 > constructor(
49 lineRangeMapping: LineRangeMapping,
50 changes: readonly DetailedLineRangeMapping[],
53 this.changes = changes;
54 }
56 > public flip(): MovedText {
57 return new MovedText(this.lineRangeMapping.flip(), this.changes.map(c => c.flip()));
58 }
src/vs/base/common/diff/diffChange.ts 50 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- diffChange.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 > * Represents information about a specific difference between two sequences.
8 > */
9 > export class DiffChange {
10 >
11 > /**
12 > * The position of the first element in the original sequence which
13 > * this change affects.
14 > */
15 > public originalStart: number;
16 >
17 > /**
18 > * The number of elements from the original sequence which were
19 > * affected.
20 > */
21 > public originalLength: number;
22 >
23 > /**
24 > * The position of the first element in the modified sequence which
25 > * this change affects.
26 > */
27 > public modifiedStart: number;
28 >
29 > /**
30 > * The number of elements from the modified sequence which were
31 > * affected (added).
32 > */
33 > public modifiedLength: number;
34 >
35 > /**
36 > * Constructs a new DiffChange with the given sequence information
37 > * and content.
38 > */
39 > constructor(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number) {
40 //Debug.Assert(originalLength > 0 || modifiedLength > 0, "originalLength and modifiedLength cannot both be <= 0");
41 this.originalStart = originalStart;
44 this.modifiedLength = modifiedLength;
45 }
47 > /**
48 > * The end point (exclusive) of the change in the original sequence.
49 > */
50 > public getOriginalEnd() {
51 return this.originalStart + this.originalLength;
52 }
54 > /**
55 > * The end point (exclusive) of the change in the modified sequence.
56 > */
57 > public getModifiedEnd() {
58 return this.modifiedStart + this.modifiedLength;
59 }
60 > } diffChange.ts
src/vs/base/common/date.ts 46 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- date.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 { localize } from '../../nls.js';
7 > import { Lazy } from './lazy.js';
8 > import { LANGUAGE_DEFAULT } from './platform.js';
9 >
10 > const minute = 60;
11 > const hour = minute * 60;
12 > const day = hour * 24;
13 > const week = day * 7;
14 > const month = day * 30;
15 > const year = day * 365;
16 >
17 > /**
18 > * Create a localized difference of the time between now and the specified date.
19 > * @param date The date to generate the difference from.
20 > * @param appendAgoLabel Whether to append the " ago" to the end.
21 > * @param useFullTimeWords Whether to use full words (eg. seconds) instead of
22 > * shortened (eg. secs).
23 > * @param disallowNow Whether to disallow the string "now" when the difference
24 > * is less than 30 seconds.
25 > */
26 > export function fromNow(date: number | Date, appendAgoLabel?: boolean, useFullTimeWords?: boolean, disallowNow?: boolean): string {
27 if (typeof date === 'undefined') {
28 return localize('date.fromNow.unknown', 'unknown');
205 }
206 }
207 > date.ts
208 > export function fromNowByDay(date: number | Date, appendAgoLabel?: boolean, useFullTimeWords?: boolean): string {
209 if (typeof date !== 'number') {
210 date = date.getTime();
226 return fromNow(date, appendAgoLabel, useFullTimeWords);
227 }
228 > date.ts
229 > /**
230 > * Gets a readable duration with intelligent/lossy precision. For example "40ms" or "3.040s")
231 > * @param ms The duration to get in milliseconds.
232 > * @param useFullTimeWords Whether to use full words (eg. seconds) instead of
233 > * shortened (eg. secs).
234 > */
235 > export function getDurationString(ms: number, useFullTimeWords?: boolean) {
236 const seconds = Math.abs(ms / 1000);
237 if (seconds < 1) {
257 return localize('duration.d', '{0} days', Math.round(ms / (1000 * day)));
258 }
259 > date.ts
260 > export function toLocalISOString(date: Date): string {
261 return date.getFullYear() +
262 '-' + String(date.getMonth() + 1).padStart(2, '0') +
268 'Z';
269 }
270 > date.ts
271 > export const safeIntl = {
272 > DateTimeFormat(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): Lazy<Intl.DateTimeFormat> {
273 return new Lazy(() => {
274 try {
279 });
280 },
281 > Collator(locales?: Intl.LocalesArgument, options?: Intl.CollatorOptions): Lazy<Intl.Collator> { date.ts
282 return new Lazy(() => {
283 try {
288 });
289 },
290 > Segmenter(locales?: Intl.LocalesArgument, options?: Intl.SegmenterOptions): Lazy<Intl.Segmenter> { date.ts
291 return new Lazy(() => {
292 try {
297 });
298 },
299 > Locale(tag: Intl.Locale | string, options?: Intl.LocaleOptions): Lazy<Intl.Locale> { date.ts
300 return new Lazy(() => {
301 try {
306 });
307 },
308 > NumberFormat(locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions): Lazy<Intl.NumberFormat> { date.ts
309 return new Lazy(() => {
310 try {
src/vs/editor/common/core/wordCharacterClassifier.ts 44 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- wordCharacterClassifier.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 '../../../base/common/charCode.js';
7 > import { safeIntl } from '../../../base/common/date.js';
8 > import { Lazy } from '../../../base/common/lazy.js';
9 > import { LRUCache } from '../../../base/common/map.js';
10 > import { CharacterClassifier } from './characterClassifier.js';
11 >
12 > export const enum WordCharacterClass {
13 > Regular = 0,
14 > Whitespace = 1,
15 > WordSeparator = 2
16 > }
17 >
18 > export class WordCharacterClassifier extends CharacterClassifier<WordCharacterClass> {
19 >
20 > public readonly intlSegmenterLocales: Intl.UnicodeBCP47LocaleIdentifier[];
21 > private readonly _segmenter: Lazy<Intl.Segmenter> | null = null;
22 > private _cachedLine: string | null = null;
23 > private _cachedSegments: IntlWordSegmentData[] = [];
24 >
25 > constructor(wordSeparators: string, intlSegmenterLocales: Intl.UnicodeBCP47LocaleIdentifier[]) {
26 super(WordCharacterClass.Regular);
27 this.intlSegmenterLocales = intlSegmenterLocales;
39 this.set(CharCode.Tab, WordCharacterClass.Whitespace);
40 }
42 > public findPrevIntlWordBeforeOrAtOffset(line: string, offset: number): IntlWordSegmentData | null {
43 let candidate: IntlWordSegmentData | null = null;
44 for (const segment of this._getIntlSegmenterWordsOnLine(line)) {
50 return candidate;
51 }
53 > public findNextIntlWordAtOrAfterOffset(lineContent: string, offset: number): IntlWordSegmentData | null {
54 for (const segment of this._getIntlSegmenterWordsOnLine(lineContent)) {
55 if (segment.index < offset) {
60 return null;
61 }
63 > private _getIntlSegmenterWordsOnLine(line: string): IntlWordSegmentData[] {
64 if (!this._segmenter) {
65 return [];
77 return this._cachedSegments;
78 }
80 > private _filterWordSegments(segments: Intl.Segments): IntlWordSegmentData[] {
81 const result: IntlWordSegmentData[] = [];
82 for (const segment of segments) {
87 return result;
88 }
90 > private _isWordLike(segment: Intl.SegmentData): segment is IntlWordSegmentData {
91 if (segment.isWordLike) {
92 return true;
94 return false;
95 }
97 >
98 > export interface IntlWordSegmentData extends Intl.SegmentData {
99 > isWordLike: true;
100 > }
101 >
102 > const wordClassifierCache = new LRUCache<string, WordCharacterClassifier>(10);
103 >
104 > export function getMapForWordSeparators(wordSeparators: string, intlSegmenterLocales: Intl.UnicodeBCP47LocaleIdentifier[]): WordCharacterClassifier {
105 const key = `${wordSeparators}/${intlSegmenterLocales.join(',')}`;
106 let result = wordClassifierCache.get(key)!;
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/editor/common/diff/defaultLinesDiffComputer/utils.ts 40 covered LOC · 12 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 { CharCode } from '../../../../base/common/charCode.js';
7 > import { LineRange } from '../../core/ranges/lineRange.js';
8 > import { DetailedLineRangeMapping } from '../rangeMapping.js';
9 >
10 > export class Array2D<T> {
11 > private readonly array: T[] = [];
12 >
13 > constructor(public readonly width: number, public readonly height: number) {
14 > this.array = new Array<T>(width * height); utils.ts
15 > }
16 > utils.ts
17 > get(x: number, y: number): T {
18 > return this.array[x + y * this.width]; utils.ts
19 > }
20 > utils.ts
21 > set(x: number, y: number, value: T): void {
22 > this.array[x + y * this.width] = value; utils.ts
23 > }
24 > } utils.ts
25 >
26 > export function isSpace(charCode: number): boolean {
27 > return charCode === CharCode.Space || charCode === CharCode.Tab; utils.ts
28 > }
29 > utils.ts
30 > export class LineRangeFragment {
31 > private static chrKeys = new Map<string, number>();
32 >
33 > private static getKey(chr: string): number {
34 let key = this.chrKeys.get(chr);
35 if (key === undefined) {
39 return key;
40 }
41 > utils.ts
42 > private readonly totalCount: number;
43 > private readonly histogram: number[] = [];
44 > constructor(
45 public readonly range: LineRange,
46 public readonly lines: string[],
63 this.totalCount = counter;
64 }
65 > utils.ts
66 > public computeSimilarity(other: LineRangeFragment): number {
67 let sumDifferences = 0;
68 const maxLength = Math.max(this.histogram.length, other.histogram.length);
72 return 1 - (sumDifferences / (this.totalCount + other.totalCount));
73 }
74 > } utils.ts
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/editor/common/core/editOperation.ts 38 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editOperation.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 { Position } from './position.js';
7 > import { IRange, Range } from './range.js';
8 >
9 > /**
10 > * A single edit operation, that acts as a simple replace.
11 > * i.e. Replace text at `range` with `text` in model.
12 > */
13 > export interface ISingleEditOperation {
14 > /**
15 > * The range to replace. This can be empty to emulate a simple insert.
16 > */
17 > range: IRange;
18 > /**
19 > * The text to replace with. This can be null to emulate a simple delete.
20 > */
21 > text: string | null;
22 > /**
23 > * This indicates that this operation has "insert" semantics.
24 > * i.e. forceMoveMarkers = true => if `range` is collapsed, all markers at the position will be moved.
25 > */
26 > forceMoveMarkers?: boolean;
27 > }
28 >
29 > export class EditOperation {
30 >
31 > public static insert(position: Position, text: string): ISingleEditOperation {
32 return {
33 range: new Range(position.lineNumber, position.column, position.lineNumber, position.column),
36 };
37 }
39 > public static delete(range: Range): ISingleEditOperation {
40 return {
41 range: range,
43 };
44 }
46 > public static replace(range: Range, text: string | null): ISingleEditOperation {
47 return {
48 range: range,
50 };
51 }
53 > public static replaceMove(range: Range, text: string | null): ISingleEditOperation {
54 return {
55 range: range,
src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/myersDiffAlgorithm.ts 36 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- myersDiffAlgorithm.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 { OffsetRange } from '../../../core/ranges/offsetRange.js';
7 > import { DiffAlgorithmResult, IDiffAlgorithm, ISequence, ITimeout, InfiniteTimeout, SequenceDiff } from './diffAlgorithm.js';
8 >
9 > /**
10 > * An O(ND) diff algorithm that has a quadratic space worst-case complexity.
11 > */
12 > export class MyersDiffAlgorithm implements IDiffAlgorithm {
13 > compute(seq1: ISequence, seq2: ISequence, timeout: ITimeout = InfiniteTimeout.instance): DiffAlgorithmResult {
14 // These are common special cases.
15 // The early return improves performance dramatically.
102 return new DiffAlgorithmResult(result, false);
103 }
105 >
106 > class SnakePath {
107 > constructor(
108 public readonly prev: SnakePath | null,
109 public readonly x: number,
112 ) {
113 }
115 >
116 > /**
117 > * An array that supports fast negative indices.
118 > */
119 class FastInt32Array {
120 private positiveArr: Int32Array = new Int32Array(10);
121 private negativeArr: Int32Array = new Int32Array(10);
123 > get(idx: number): number {
124 if (idx < 0) {
125 idx = -idx - 1;
129 }
130 }
132 > set(idx: number, value: number): void {
133 if (idx < 0) {
134 idx = -idx - 1;
148 }
149 }
151 >
152 > /**
153 > * An array that supports fast negative indices.
154 > */
155 class FastArrayNegativeIndices<T> {
156 private readonly positiveArr: T[] = [];
157 private readonly negativeArr: T[] = [];
159 > get(idx: number): T {
160 if (idx < 0) {
161 idx = -idx - 1;
165 }
166 }
168 > set(idx: number, value: T): void {
169 if (idx < 0) {
170 idx = -idx - 1;
src/vs/editor/common/diff/defaultLinesDiffComputer/lineSequence.ts 34 covered LOC · 12 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lineSequence.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 '../../../../base/common/charCode.js';
7 > import { OffsetRange } from '../../core/ranges/offsetRange.js';
8 > import { ISequence } from './algorithms/diffAlgorithm.js';
9 >
10 > export class LineSequence implements ISequence {
11 > constructor(
12 > private readonly trimmedHash: number[], lineSequence.ts
13 > private readonly lines: string[]
14 > ) { }
16 > getElement(offset: number): number {
17 > return this.trimmedHash[offset]; lineSequence.ts
18 > }
20 > get length(): number {
21 > return this.trimmedHash.length; lineSequence.ts
22 > }
24 > getBoundaryScore(length: number): number {
25 const indentationBefore = length === 0 ? 0 : getIndentation(this.lines[length - 1]);
26 const indentationAfter = length === this.lines.length ? 0 : getIndentation(this.lines[length]);
27 return 1000 - (indentationBefore + indentationAfter);
28 }
30 > getText(range: OffsetRange): string {
31 > return this.lines.slice(range.start, range.endExclusive).join('\n'); lineSequence.ts
32 > }
34 > isStronglyEqual(offset1: number, offset2: number): boolean {
35 > return this.lines[offset1] === this.lines[offset2]; lineSequence.ts
36 > }
38 >
39 function getIndentation(str: string): number {
40 let i = 0;
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/editor/common/languages/supports/inplaceReplaceSupport.ts 31 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- inplaceReplaceSupport.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 { IRange } from '../../core/range.js';
7 > import { IInplaceReplaceSupportResult } from '../../languages.js';
8 >
9 > export class BasicInplaceReplace {
10 >
11 > public static readonly INSTANCE = new BasicInplaceReplace();
12 >
13 > public navigateValueSet(range1: IRange, text1: string, range2: IRange, text2: string | null, up: boolean): IInplaceReplaceSupportResult | null {
14
15 if (range1 && text1) {
35 return null;
36 }
38 > private doNavigateValueSet(text: string, up: boolean): string | null {
39 const numberResult = this.numberReplace(text, up);
40 if (numberResult !== null) {
43 return this.textReplace(text, up);
44 }
46 > private numberReplace(value: string, up: boolean): string | null {
47 const precision = Math.pow(10, value.length - (value.lastIndexOf('.') + 1));
48 let n1 = Number(value);
64 return null;
65 }
67 > private readonly _defaultValueSet: string[][] = [
68 > ['true', 'false'],
69 > ['True', 'False'],
70 > ['Private', 'Public', 'Friend', 'ReadOnly', 'Partial', 'Protected', 'WriteOnly'],
71 > ['public', 'protected', 'private'],
72 > ];
73 >
74 > private textReplace(value: string, up: boolean): string | null {
75 return this.valueSetsReplace(this._defaultValueSet, value, up);
76 }
78 > private valueSetsReplace(valueSets: string[][], value: string, up: boolean): string | null {
79 let result: string | null = null;
80 for (let i = 0, len = valueSets.length; result === null && i < len; i++) {
83 return result;
84 }
86 > private valueSetReplace(valueSet: string[], value: string, up: boolean): string | null {
87 let idx = valueSet.indexOf(value);
88 if (idx >= 0) {
src/vs/editor/common/diff/externalLinesDiffComputer.ts 28 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- externalLinesDiffComputer.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 { IDiffComputer as IExternalDiffComputer, createDiffComputer as createExternalDiffComputer } from '@vscode/diff';
7 > import { resolveAmdNodeModulePath } from '../../../amdX.js';
8 > import { LineRange } from '../core/ranges/lineRange.js';
9 > import { OffsetRange } from '../core/ranges/offsetRange.js';
10 > import { StringText } from '../core/text/abstractText.js';
11 > import { ensureDependenciesAreSet } from '../core/text/positionToOffset.js';
12 > import { ILinesDiffComputer, ILinesDiffComputerOptions, LinesDiff, MovedText } from './linesDiffComputer.js';
13 > import { lineRangeMappingFromRangeMappings, LineRangeMapping, RangeMapping } from './rangeMapping.js';
14 >
15 > type ExternalDiffModule = { createDiffComputer: typeof createExternalDiffComputer };
16 >
17 > let externalModulePromise: Promise<ExternalDiffModule> | undefined;
18 > let externalDiffComputerPromise: Promise<IExternalDiffComputer> | undefined;
19 > let externalWasmDiffComputerPromise: Promise<IExternalDiffComputer> | undefined;
20 >
21 function loadExternalModule(): Promise<ExternalDiffModule> {
22 if (!externalModulePromise) {
27 return externalModulePromise;
28 }
30 function loadExternalComputer(useWasm: boolean): Promise<IExternalDiffComputer> {
31 if (useWasm) {
40 return externalDiffComputerPromise;
41 }
43 export async function getExternalLinesDiffComputer(useWasm: boolean): Promise<ILinesDiffComputer> {
44 const computer = await loadExternalComputer(useWasm);
45 return new ExternalLinesDiffComputer(computer);
46 }
48 > class ExternalLinesDiffComputer implements ILinesDiffComputer {
49 > constructor(private readonly _computer: IExternalDiffComputer) { }
50 >
51 > computeDiff(originalLines: string[], modifiedLines: string[], options: ILinesDiffComputerOptions): LinesDiff {
52 ensureDependenciesAreSet();
53
src/vs/editor/common/languages/defaultDocumentColorsComputer.ts 27 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- defaultDocumentColorsComputer.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 { Color, HSLA } from '../../../base/common/color.js';
6 > import { IPosition } from '../core/position.js';
7 > import { IRange } from '../core/range.js';
8 > import { IColor, IColorInformation } from '../languages.js';
9 >
10 > export interface IDocumentColorComputerTarget {
11 > getValue(): string;
12 > positionAt(offset: number): IPosition;
13 > findMatches(regex: RegExp): RegExpMatchArray[];
14 > }
15 >
16 function _parseCaptureGroups(captureGroups: IterableIterator<string>) {
17 const values = [];
33 };
34 }
36 function _findRange(model: IDocumentColorComputerTarget, match: RegExpMatchArray): IRange | undefined {
37 const index = match.index;
49 return range;
50 }
52 function _findHexColorInformation(range: IRange | undefined, hexValue: string) {
53 if (!range) {
63 };
64 }
66 function _findRGBColorInformation(range: IRange | undefined, matches: RegExpMatchArray[], isAlpha: boolean) {
67 if (!range || matches.length !== 1) {
76 };
77 }
79 function _findHSLColorInformation(range: IRange | undefined, matches: RegExpMatchArray[], isAlpha: boolean) {
80 if (!range || matches.length !== 1) {
90 };
91 }
93 function _findMatches(model: IDocumentColorComputerTarget | string, regex: RegExp): RegExpMatchArray[] {
94 if (typeof model === 'string') {
98 }
99 }
101 function computeColors(model: IDocumentColorComputerTarget): IColorInformation[] {
102 const result: IColorInformation[] = [];
140 return result;
141 }
143 > /**
144 > * Returns an array of all default document colors in the provided document
145 > */
146 > export function computeDefaultDocumentColors(model: IDocumentColorComputerTarget): IColorInformation[] {
147 if (!model || typeof model.getValue !== 'function' || typeof model.positionAt !== 'function') {
148 // Unknown caller!
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/uuid.ts 25 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- uuid.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 > const _UUIDPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
8 >
9 > export function isUUID(value: string): boolean {
10 return _UUIDPattern.test(value);
11 }
12 > uuid.ts
13 > export const generateUuid = (function (): () => string {
14 >
15 > // use `randomUUID` if possible
16 > if (typeof crypto.randomUUID === 'function') {
17 > // see https://developer.mozilla.org/en-US/docs/Web/API/Window/crypto
18 > // > Although crypto is available on all windows, the returned Crypto object only has one
19 > // > usable feature in insecure contexts: the getRandomValues() method.
20 > // > In general, you should use this API only in secure contexts.
21 >
22 > return crypto.randomUUID.bind(crypto);
23 > }
24
25 // prep-work
63 return result;
64 };
65 > })(); uuid.ts
66 >
67 > /** Namespace should be 3 letters, e.g. `abc-<uuid>`. */
68 > export function prefixedUuid(namespace: string): string {
69 return `${namespace}-${generateUuid()}`;
70 }
src/vs/editor/common/services/editorBaseApi.ts 25 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editorBaseApi.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 { CancellationTokenSource } from '../../../base/common/cancellation.js';
7 > import { Emitter } from '../../../base/common/event.js';
8 > import { KeyChord, KeyMod as ConstKeyMod } from '../../../base/common/keyCodes.js';
9 > import { URI } from '../../../base/common/uri.js';
10 > import { Position } from '../core/position.js';
11 > import { Range } from '../core/range.js';
12 > import { Selection } from '../core/selection.js';
13 > import { Token } from '../languages.js';
14 > import * as standaloneEnums from '../standalone/standaloneEnums.js';
15 >
16 > export class KeyMod {
17 > public static readonly CtrlCmd: number = ConstKeyMod.CtrlCmd;
18 > public static readonly Shift: number = ConstKeyMod.Shift;
19 > public static readonly Alt: number = ConstKeyMod.Alt;
20 > public static readonly WinCtrl: number = ConstKeyMod.WinCtrl;
21 >
22 > public static chord(firstPart: number, secondPart: number): number {
23 return KeyChord(firstPart, secondPart);
24 }
26 >
27 > export function createMonacoBaseAPI(): typeof monaco {
28 return {
29 editor: undefined!, // undefined override expected here
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/editor/common/diff/defaultLinesDiffComputer/computeMovedLines.ts 23 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- computeMovedLines.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 { ITimeout, SequenceDiff } from './algorithms/diffAlgorithm.js';
7 > import { DetailedLineRangeMapping, LineRangeMapping } from '../rangeMapping.js';
8 > import { pushMany, compareBy, numberComparator, reverseOrder } from '../../../../base/common/arrays.js';
9 > import { MonotonousArray, findLastMonotonous } from '../../../../base/common/arraysFind.js';
10 > import { SetMap } from '../../../../base/common/map.js';
11 > import { LineRange, LineRangeSet } from '../../core/ranges/lineRange.js';
12 > import { LinesSliceCharSequence } from './linesSliceCharSequence.js';
13 > import { LineRangeFragment, isSpace } from './utils.js';
14 > import { MyersDiffAlgorithm } from './algorithms/myersDiffAlgorithm.js';
15 > import { Range } from '../../core/range.js';
16 >
17 > export function computeMovedLines(
18 changes: DetailedLineRangeMapping[],
19 originalLines: string[],
42 return moves;
43 }
45 function countWhere<T>(arr: T[], predicate: (t: T) => boolean): number {
46 let count = 0;
52 return count;
53 }
55 function computeMovesFromSimpleDeletionsToSimpleInsertions(
56 changes: DetailedLineRangeMapping[],
95 return { moves, excludedChanges };
96 }
98 function computeUnchangedMoves(
99 changes: DetailedLineRangeMapping[],
254 return moves;
255 }
257 function areLinesSimilar(line1: string, line2: string, timeout: ITimeout): boolean {
258 if (line1.trim() === line2.trim()) { return true; }
289 return r;
290 }
292 function joinCloseConsecutiveMoves(moves: LineRangeMapping[]): LineRangeMapping[] {
293 if (moves.length === 0) {
315 return result;
316 }
318 function removeMovesInSameDiff(changes: DetailedLineRangeMapping[], moves: LineRangeMapping[]) {
319 const changesMonotonous = new MonotonousArray(changes);
src/vs/editor/common/core/text/positionToOffset.ts 22 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- positionToOffset.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 { StringEdit, StringReplacement } from '../edits/stringEdit.js';
7 > import { TextEdit, TextReplacement } from '../edits/textEdit.js';
8 > import { _setPositionOffsetTransformerDependencies } from './positionToOffsetImpl.js';
9 > import { TextLength } from './textLength.js';
10 >
11 > export { PositionOffsetTransformerBase, PositionOffsetTransformer } from './positionToOffsetImpl.js';
12 >
13 > _setPositionOffsetTransformerDependencies({
14 > StringEdit: StringEdit,
15 > StringReplacement: StringReplacement,
16 > TextReplacement: TextReplacement,
17 > TextEdit: TextEdit,
18 > TextLength: TextLength,
19 > });
20 >
21 > // TODO@hediet this is dept and needs to go. See https://github.com/microsoft/vscode/issues/251126.
22 > export function ensureDependenciesAreSet(): void {
23 // Noop
24 }
src/vs/editor/common/diff/linesDiffComputers.ts 16 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- linesDiffComputers.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 { LegacyLinesDiffComputer } from './legacyLinesDiffComputer.js';
7 > import { DefaultLinesDiffComputer } from './defaultLinesDiffComputer/defaultLinesDiffComputer.js';
8 > import { getExternalLinesDiffComputer } from './externalLinesDiffComputer.js';
9 > import { ILinesDiffComputer } from './linesDiffComputer.js';
10 >
11 > export const linesDiffComputers = {
12 > getLegacy: () => new LegacyLinesDiffComputer(),
13 > getDefault: () => new DefaultLinesDiffComputer(),
14 > getAdvancedExternal: () => getExternalLinesDiffComputer(false),
15 > getAdvancedWasm: () => getExternalLinesDiffComputer(true),
16 > } satisfies Record<string, () => ILinesDiffComputer | Promise<ILinesDiffComputer>>;
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/symbols.ts 9 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- symbols.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 > * Can be passed into the Delayed to defer using a microtask
8 > * */
9 > export const MicrotaskDelay = Symbol('MicrotaskDelay');