Atlas › Test

pieceTreeTextBuffer.test|title=prefix sum for line feed delete random bug 1: I forgot to update the lineFeedCnt when deletion is on one single piece.|occurrence=1

Exact test identity: mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test|title=prefix sum for line feed delete random bug 1: I forgot to update the lineFeedCnt when deletion is on one single piece.|occurrence=1

Package
mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/model/pieceTreeTextBuffer
Suite / test hierarchy
pieceTreeTextBuffer.test|title=prefix sum for line feed delete random bug 1: I forgot to update the lineFeedCnt when deletion is on one single piece.|occurrence=1
Test
pieceTreeTextBuffer.test|title=prefix sum for line feed delete random bug 1: I forgot to update the lineFeedCnt when deletion is on one single piece.|occurrence=1
Introduced at
pieceTreeTextBuffer.test|title=prefix sum for line feed delete random bug 1: I forgot to update the lineFeedCnt when deletion is on one single piece.|occurrence=1 Frontier kind: Test frontier
Covered ranges
4819
Covered lines
39963
Covered files
238

Covered source

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

src/vs/editor/common/config/editorOptions.ts 5717 covered LOC · 92 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editorOptions.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as arrays from '../../../base/common/arrays.js';
7 > import { IMarkdownString } from '../../../base/common/htmlContent.js';
8 > import { IJSONSchema } from '../../../base/common/jsonSchema.js';
9 > import * as objects from '../../../base/common/objects.js';
10 > import * as platform from '../../../base/common/platform.js';
11 > import { ScrollbarVisibility } from '../../../base/common/scrollable.js';
12 > import { Constants } from '../../../base/common/uint.js';
13 > import { EDITOR_FONT_DEFAULTS, FONT_VARIATION_OFF, FONT_VARIATION_TRANSLATE, FontInfo } from './fontInfo.js';
14 > import { EDITOR_MODEL_DEFAULTS } from '../core/misc/textModelDefaults.js';
15 > import { USUAL_WORD_SEPARATORS } from '../core/wordHelper.js';
16 > import * as nls from '../../../nls.js';
17 > import { AccessibilitySupport } from '../../../platform/accessibility/common/accessibility.js';
18 > import { IConfigurationPropertySchema } from '../../../platform/configuration/common/configurationRegistry.js';
19 >
20 > //#region typed options
21 >
22 > /**
23 > * Configuration options for auto closing quotes and brackets
24 > */
25 > export type EditorAutoClosingStrategy = 'always' | 'languageDefined' | 'beforeWhitespace' | 'never';
26 >
27 > /**
28 > * Configuration options for auto wrapping quotes and brackets
29 > */
30 > export type EditorAutoSurroundStrategy = 'languageDefined' | 'quotes' | 'brackets' | 'never';
31 >
32 > /**
33 > * Configuration options for typing over closing quotes or brackets
34 > */
35 > export type EditorAutoClosingEditStrategy = 'always' | 'auto' | 'never';
36 >
37 > type Unknown<T> = { [K in keyof T]: unknown };
38 >
39 > /**
40 > * Configuration options for auto indentation in the editor
41 > */
42 > export const enum EditorAutoIndentStrategy {
43 > None = 0,
44 > Keep = 1,
45 > Brackets = 2,
46 > Advanced = 3,
47 > Full = 4
48 > }
49 >
50 > /**
51 > * Configuration options for the editor.
52 > */
53 > export interface IEditorOptions {
54 > /**
55 > * This editor is used inside a diff editor.
56 > */
57 > inDiffEditor?: boolean;
58 > /**
59 > * This editor is allowed to use variable line heights.
60 > */
61 > allowVariableLineHeights?: boolean;
62 > /**
63 > * This editor is allowed to use variable font-sizes and font-families
64 > */
65 > allowVariableFonts?: boolean;
66 > /**
67 > * This editor is allowed to use variable font-sizes and font-families in accessibility mode
68 > */
69 > allowVariableFontsInAccessibilityMode?: boolean;
70 > /**
71 > * The aria label for the editor's textarea (when it is focused).
72 > */
73 > ariaLabel?: string;
74 >
75 > /**
76 > * Whether the aria-required attribute should be set on the editors textarea.
77 > */
78 > ariaRequired?: boolean;
79 > /**
80 > * Control whether a screen reader announces inline suggestion content immediately.
81 > */
82 > screenReaderAnnounceInlineSuggestion?: boolean;
83 > /**
84 > * The `tabindex` property of the editor's textarea
85 > */
86 > tabIndex?: number;
87 > /**
88 > * Render vertical lines at the specified columns.
89 > * Defaults to empty array.
90 > */
91 > rulers?: (number | IRulerOption)[];
92 > /**
93 > * Locales used for segmenting lines into words when doing word related navigations or operations.
94 > *
95 > * Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.).
96 > * Defaults to empty array
97 > */
98 > wordSegmenterLocales?: string | string[];
99 > /**
100 > * A string containing the word separators used when doing word navigation.
101 > * Defaults to `~!@#$%^&*()-=+[{]}\\|;:\'",.<>/?
102 > */
103 > wordSeparators?: string;
104 > /**
105 > * Enable Linux primary clipboard.
106 > * Defaults to true.
107 > */
108 > selectionClipboard?: boolean;
109 > /**
110 > * Control the rendering of line numbers.
111 > * If it is a function, it will be invoked when rendering a line number and the return value will be rendered.
112 > * Otherwise, if it is a truthy, line numbers will be rendered normally (equivalent of using an identity function).
113 > * Otherwise, line numbers will not be rendered.
114 > * Defaults to `on`.
115 > */
116 > lineNumbers?: LineNumbersType;
117 > /**
118 > * Controls the minimal number of visible leading and trailing lines surrounding the cursor.
119 > * Defaults to 0.
120 > */
121 > cursorSurroundingLines?: number;
122 > /**
123 > * Controls when `cursorSurroundingLines` should be enforced
124 > * Defaults to `default`, `cursorSurroundingLines` is not enforced when cursor position is changed
125 > * by mouse.
126 > */
127 > cursorSurroundingLinesStyle?: 'default' | 'all';
128 > /**
129 > * Render last line number when the file ends with a newline.
130 > * Defaults to 'on' for Windows and macOS and 'dimmed' for Linux.
131 > */
132 > renderFinalNewline?: 'on' | 'off' | 'dimmed';
133 > /**
134 > * Remove unusual line terminators like LINE SEPARATOR (LS), PARAGRAPH SEPARATOR (PS).
135 > * Defaults to 'prompt'.
136 > */
137 > unusualLineTerminators?: 'auto' | 'off' | 'prompt';
138 > /**
139 > * Should the corresponding line be selected when clicking on the line number?
140 > * Defaults to true.
141 > */
142 > selectOnLineNumbers?: boolean;
143 > /**
144 > * Control the width of line numbers, by reserving horizontal space for rendering at least an amount of digits.
145 > * Defaults to 5.
146 > */
147 > lineNumbersMinChars?: number;
148 > /**
149 > * Enable the rendering of the glyph margin.
150 > * Defaults to true in vscode and to false in monaco-editor.
151 > */
152 > glyphMargin?: boolean;
153 > /**
154 > * The width reserved for line decorations (in px).
155 > * Line decorations are placed between line numbers and the editor content.
156 > * You can pass in a string in the format floating point followed by "ch". e.g. 1.3ch.
157 > * Defaults to 10.
158 > */
159 > lineDecorationsWidth?: number | string;
160 > /**
161 > * When revealing the cursor, a virtual padding (px) is added to the cursor, turning it into a rectangle.
162 > * This virtual padding ensures that the cursor gets revealed before hitting the edge of the viewport.
163 > * Defaults to 30 (px).
164 > */
165 > revealHorizontalRightPadding?: number;
166 > /**
167 > * Render the editor selection with rounded borders.
168 > * Defaults to true.
169 > */
170 > roundedSelection?: boolean;
171 > /**
172 > * Class name to be added to the editor.
173 > */
174 > extraEditorClassName?: string;
175 > /**
176 > * Should the editor be read only. See also `domReadOnly`.
177 > * Defaults to false.
178 > */
179 > readOnly?: boolean;
180 > /**
181 > * The message to display when the editor is readonly.
182 > */
183 > readOnlyMessage?: IMarkdownString;
184 > /**
185 > * Should the textarea used for input use the DOM `readonly` attribute.
186 > * Defaults to false.
187 > */
188 > domReadOnly?: boolean;
189 > /**
190 > * Enable linked editing.
191 > * Defaults to false.
192 > */
193 > linkedEditing?: boolean;
194 > /**
195 > * deprecated, use linkedEditing instead
196 > */
197 > renameOnType?: boolean;
198 > /**
199 > * Should the editor render validation decorations.
200 > * Defaults to editable.
201 > */
202 > renderValidationDecorations?: 'editable' | 'on' | 'off';
203 > /**
204 > * Control the behavior and rendering of the scrollbars.
205 > */
206 > scrollbar?: IEditorScrollbarOptions;
207 > /**
208 > * Control the behavior of sticky scroll options
209 > */
210 > stickyScroll?: IEditorStickyScrollOptions;
211 > /**
212 > * Control the behavior and rendering of the minimap.
213 > */
214 > minimap?: IEditorMinimapOptions;
215 > /**
216 > * Control the behavior of the find widget.
217 > */
218 > find?: IEditorFindOptions;
219 > /**
220 > * Display overflow widgets as `fixed`.
221 > * Defaults to `false`.
222 > */
223 > fixedOverflowWidgets?: boolean;
224 > /**
225 > * Allow content widgets and overflow widgets to overflow the editor viewport.
226 > * Defaults to `true`.
227 > */
228 > allowOverflow?: boolean;
229 > /**
230 > * The number of vertical lanes the overview ruler should render.
231 > * Defaults to 3.
232 > */
233 > overviewRulerLanes?: number;
234 > /**
235 > * Controls if a border should be drawn around the overview ruler.
236 > * Defaults to `true`.
237 > */
238 > overviewRulerBorder?: boolean;
239 > /**
240 > * Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'.
241 > * Defaults to 'blink'.
242 > */
243 > cursorBlinking?: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid';
244 > /**
245 > * Zoom the font in the editor when using the mouse wheel in combination with holding Ctrl.
246 > * Defaults to false.
247 > */
248 > mouseWheelZoom?: boolean;
249 > /**
250 > * Control the mouse pointer style, either 'text' or 'default' or 'copy'
251 > * Defaults to 'text'
252 > */
253 > mouseStyle?: 'text' | 'default' | 'copy';
254 > /**
255 > * Enable smooth caret animation.
256 > * Defaults to 'off'.
257 > */
258 > cursorSmoothCaretAnimation?: 'off' | 'explicit' | 'on';
259 > /**
260 > * Control the cursor style in insert mode.
261 > * Defaults to 'line'.
262 > */
263 > cursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin';
264 > /**
265 > * Control the cursor style in overtype mode.
266 > * Defaults to 'block'.
267 > */
268 > overtypeCursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin';
269 > /**
270 > * Controls whether paste in overtype mode should overwrite or insert.
271 > */
272 > overtypeOnPaste?: boolean;
273 > /**
274 > * Control the width of the cursor when cursorStyle is set to 'line'
275 > */
276 > cursorWidth?: number;
277 > /**
278 > * Control the height of the cursor when cursorStyle is set to 'line'
279 > */
280 > cursorHeight?: number;
281 > /**
282 > * Enable font ligatures.
283 > * Defaults to false.
284 > */
285 > fontLigatures?: boolean | string;
286 > /**
287 > * Enable font variations.
288 > * Defaults to false.
289 > */
290 > fontVariations?: boolean | string;
291 > /**
292 > * Controls whether to use default color decorations or not using the default document color provider
293 > */
294 > defaultColorDecorators?: 'auto' | 'always' | 'never';
295 > /**
296 > * Disable the use of `transform: translate3d(0px, 0px, 0px)` for the editor margin and lines layers.
297 > * The usage of `transform: translate3d(0px, 0px, 0px)` acts as a hint for browsers to create an extra layer.
298 > * Defaults to false.
299 > */
300 > disableLayerHinting?: boolean;
301 > /**
302 > * Disable the optimizations for monospace fonts.
303 > * Defaults to false.
304 > */
305 > disableMonospaceOptimizations?: boolean;
306 > /**
307 > * Should the cursor be hidden in the overview ruler.
308 > * Defaults to false.
309 > */
310 > hideCursorInOverviewRuler?: boolean;
311 > /**
312 > * Enable that scrolling can go one screen size after the last line.
313 > * Defaults to true.
314 > */
315 > scrollBeyondLastLine?: boolean;
316 > /**
317 > * Scroll editor on middle click
318 > */
319 > scrollOnMiddleClick?: boolean;
320 > /**
321 > * Enable that scrolling can go beyond the last column by a number of columns.
322 > * Defaults to 5.
323 > */
324 > scrollBeyondLastColumn?: number;
325 > /**
326 > * Enable that the editor animates scrolling to a position.
327 > * Defaults to false.
328 > */
329 > smoothScrolling?: boolean;
330 > /**
331 > * Enable that the editor will install a ResizeObserver to check if its container dom node size has changed.
332 > * Defaults to false.
333 > */
334 > automaticLayout?: boolean;
335 > /**
336 > * Control the wrapping of the editor.
337 > * When `wordWrap` = "off", the lines will never wrap.
338 > * When `wordWrap` = "on", the lines will wrap at the viewport width.
339 > * When `wordWrap` = "wordWrapColumn", the lines will wrap at `wordWrapColumn`.
340 > * When `wordWrap` = "bounded", the lines will wrap at min(viewport width, wordWrapColumn).
341 > * Defaults to "off".
342 > */
343 > wordWrap?: 'off' | 'on' | 'wordWrapColumn' | 'bounded';
344 > /**
345 > * Override the `wordWrap` setting.
346 > */
347 > wordWrapOverride1?: 'off' | 'on' | 'inherit';
348 > /**
349 > * Override the `wordWrapOverride1` setting.
350 > */
351 > wordWrapOverride2?: 'off' | 'on' | 'inherit';
352 > /**
353 > * Control the wrapping of the editor.
354 > * When `wordWrap` = "off", the lines will never wrap.
355 > * When `wordWrap` = "on", the lines will wrap at the viewport width.
356 > * When `wordWrap` = "wordWrapColumn", the lines will wrap at `wordWrapColumn`.
357 > * When `wordWrap` = "bounded", the lines will wrap at min(viewport width, wordWrapColumn).
358 > * Defaults to 80.
359 > */
360 > wordWrapColumn?: number;
361 > /**
362 > * Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'.
363 > * Defaults to 'same' in vscode and to 'none' in monaco-editor.
364 > */
365 > wrappingIndent?: 'none' | 'same' | 'indent' | 'deepIndent';
366 > /**
367 > * Controls the wrapping strategy to use.
368 > * Defaults to 'simple'.
369 > */
370 > wrappingStrategy?: 'simple' | 'advanced';
371 > /**
372 > * Create a softwrap on every quoted "\n" literal.
373 > * Defaults to false.
374 > */
375 > wrapOnEscapedLineFeeds?: boolean;
376 > /**
377 > * Configure word wrapping characters. A break will be introduced before these characters.
378 > */
379 > wordWrapBreakBeforeCharacters?: string;
380 > /**
381 > * Configure word wrapping characters. A break will be introduced after these characters.
382 > */
383 > wordWrapBreakAfterCharacters?: string;
384 > /**
385 > * Sets whether line breaks appear wherever the text would otherwise overflow its content box.
386 > * When wordBreak = 'normal', Use the default line break rule.
387 > * When wordBreak = 'keepAll', Word breaks should not be used for Chinese/Japanese/Korean (CJK) text. Non-CJK text behavior is the same as for normal.
388 > */
389 > wordBreak?: 'normal' | 'keepAll';
390 > /**
391 > * Performance guard: Stop rendering a line after x characters.
392 > * Defaults to 10000.
393 > * Use -1 to never stop rendering
394 > */
395 > stopRenderingLineAfter?: number;
396 > /**
397 > * Configure the editor's hover.
398 > */
399 > hover?: IEditorHoverOptions;
400 > /**
401 > * Enable detecting links and making them clickable.
402 > * Defaults to true.
403 > */
404 > links?: boolean;
405 > /**
406 > * Enable inline color decorators and color picker rendering.
407 > */
408 > colorDecorators?: boolean;
409 > /**
410 > * Controls what is the condition to spawn a color picker from a color dectorator
411 > */
412 > colorDecoratorsActivatedOn?: 'clickAndHover' | 'click' | 'hover';
413 > /**
414 > * Controls the max number of color decorators that can be rendered in an editor at once.
415 > */
416 > colorDecoratorsLimit?: number;
417 > /**
418 > * Control the behaviour of comments in the editor.
419 > */
420 > comments?: IEditorCommentsOptions;
421 > /**
422 > * Enable custom contextmenu.
423 > * Defaults to true.
424 > */
425 > contextmenu?: boolean;
426 > /**
427 > * A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.
428 > * Defaults to 1.
429 > */
430 > mouseWheelScrollSensitivity?: number;
431 > /**
432 > * FastScrolling mulitplier speed when pressing `Alt`
433 > * Defaults to 5.
434 > */
435 > fastScrollSensitivity?: number;
436 > /**
437 > * Enable that the editor scrolls only the predominant axis. Prevents horizontal drift when scrolling vertically on a trackpad.
438 > * Defaults to true.
439 > */
440 > scrollPredominantAxis?: boolean;
441 > /**
442 > * Make scrolling inertial - mostly useful with touchpad on linux.
443 > */
444 > inertialScroll?: boolean;
445 > /**
446 > * Enable that the selection with the mouse and keys is doing column selection.
447 > * Defaults to false.
448 > */
449 > columnSelection?: boolean;
450 > /**
451 > * The modifier to be used to add multiple cursors with the mouse.
452 > * Defaults to 'alt'
453 > */
454 > multiCursorModifier?: 'ctrlCmd' | 'alt';
455 > /**
456 > * Merge overlapping selections.
457 > * Defaults to true
458 > */
459 > multiCursorMergeOverlapping?: boolean;
460 > /**
461 > * Configure the behaviour when pasting a text with the line count equal to the cursor count.
462 > * Defaults to 'spread'.
463 > */
464 > multiCursorPaste?: 'spread' | 'full';
465 > /**
466 > * Controls the max number of text cursors that can be in an active editor at once.
467 > */
468 > multiCursorLimit?: number;
469 > /**
470 > * Enables middle mouse button to open links and Go To Definition
471 > */
472 > mouseMiddleClickAction?: MouseMiddleClickAction;
473 > /**
474 > * Configure the editor's accessibility support.
475 > * Defaults to 'auto'. It is best to leave this to 'auto'.
476 > */
477 > accessibilitySupport?: 'auto' | 'off' | 'on';
478 > /**
479 > * Controls the number of lines in the editor that can be read out by a screen reader
480 > */
481 > accessibilityPageSize?: number;
482 > /**
483 > * Suggest options.
484 > */
485 > suggest?: ISuggestOptions;
486 > inlineSuggest?: IInlineSuggestOptions;
487 > /**
488 > * Smart select options.
489 > */
490 > smartSelect?: ISmartSelectOptions;
491 > /**
492 > *
493 > */
494 > gotoLocation?: IGotoLocationOptions;
495 > /**
496 > * Enable quick suggestions (shadow suggestions)
497 > * Defaults to true.
498 > */
499 > quickSuggestions?: boolean | QuickSuggestionsValue | IQuickSuggestionsOptions;
500 > /**
501 > * Quick suggestions show delay (in ms)
502 > * Defaults to 10 (ms)
503 > */
504 > quickSuggestionsDelay?: number;
505 > /**
506 > * Controls the spacing around the editor.
507 > */
508 > padding?: IEditorPaddingOptions;
509 > /**
510 > * Parameter hint options.
511 > */
512 > parameterHints?: IEditorParameterHintOptions;
513 > /**
514 > * Options for auto closing brackets.
515 > * Defaults to language defined behavior.
516 > */
517 > autoClosingBrackets?: EditorAutoClosingStrategy;
518 > /**
519 > * Options for auto closing comments.
520 > * Defaults to language defined behavior.
521 > */
522 > autoClosingComments?: EditorAutoClosingStrategy;
523 > /**
524 > * Options for auto closing quotes.
525 > * Defaults to language defined behavior.
526 > */
527 > autoClosingQuotes?: EditorAutoClosingStrategy;
528 > /**
529 > * Options for pressing backspace near quotes or bracket pairs.
530 > */
531 > autoClosingDelete?: EditorAutoClosingEditStrategy;
532 > /**
533 > * Options for typing over closing quotes or brackets.
534 > */
535 > autoClosingOvertype?: EditorAutoClosingEditStrategy;
536 > /**
537 > * Options for auto surrounding.
538 > * Defaults to always allowing auto surrounding.
539 > */
540 > autoSurround?: EditorAutoSurroundStrategy;
541 > /**
542 > * Controls whether the editor should automatically adjust the indentation when users type, paste, move or indent lines.
543 > * Defaults to advanced.
544 > */
545 > autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full';
546 > /**
547 > * Boolean which controls whether to autoindent on paste
548 > */
549 > autoIndentOnPaste?: boolean;
550 > /**
551 > * Boolean which controls whether to autoindent on paste within a string when autoIndentOnPaste is enabled.
552 > */
553 > autoIndentOnPasteWithinString?: boolean;
554 > /**
555 > * Emulate selection behaviour of tab characters when using spaces for indentation.
556 > * This means selection will stick to tab stops.
557 > */
558 > stickyTabStops?: boolean;
559 > /**
560 > * Enable format on type.
561 > * Defaults to false.
562 > */
563 > formatOnType?: boolean;
564 > /**
565 > * Enable format on paste.
566 > * Defaults to false.
567 > */
568 > formatOnPaste?: boolean;
569 > /**
570 > * Controls whether double-clicking next to a bracket or quote selects the content inside.
571 > * Defaults to true.
572 > */
573 > doubleClickSelectsBlock?: boolean;
574 > /**
575 > * Controls if the editor should allow to move selections via drag and drop.
576 > * Defaults to false.
577 > */
578 > dragAndDrop?: boolean;
579 > /**
580 > * Enable the suggestion box to pop-up on trigger characters.
581 > * Defaults to true.
582 > */
583 > suggestOnTriggerCharacters?: boolean;
584 > /**
585 > * Accept suggestions on ENTER.
586 > * Defaults to 'on'.
587 > */
588 > acceptSuggestionOnEnter?: 'on' | 'smart' | 'off';
589 > /**
590 > * Accept suggestions on provider defined characters.
591 > * Defaults to true.
592 > */
593 > acceptSuggestionOnCommitCharacter?: boolean;
594 > /**
595 > * Enable snippet suggestions. Default to 'true'.
596 > */
597 > snippetSuggestions?: 'top' | 'bottom' | 'inline' | 'none';
598 > /**
599 > * Copying without a selection copies the current line.
600 > */
601 > emptySelectionClipboard?: boolean;
602 > /**
603 > * Syntax highlighting is copied.
604 > */
605 > copyWithSyntaxHighlighting?: boolean;
606 > /**
607 > * The history mode for suggestions.
608 > */
609 > suggestSelection?: 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix';
610 > /**
611 > * The font size for the suggest widget.
612 > * Defaults to the editor font size.
613 > */
614 > suggestFontSize?: number;
615 > /**
616 > * The line height for the suggest widget.
617 > * Defaults to the editor line height.
618 > */
619 > suggestLineHeight?: number;
620 > /**
621 > * Enable tab completion.
622 > */
623 > tabCompletion?: 'on' | 'off' | 'onlySnippets';
624 > /**
625 > * Enable selection highlight.
626 > * Defaults to true.
627 > */
628 > selectionHighlight?: boolean;
629 > /**
630 > * Enable selection highlight for multiline selections.
631 > * Defaults to false.
632 > */
633 > selectionHighlightMultiline?: boolean;
634 > /**
635 > * Maximum length (in characters) for selection highlights.
636 > * Set to 0 to have an unlimited length.
637 > */
638 > selectionHighlightMaxLength?: number;
639 > /**
640 > * Enable semantic occurrences highlight.
641 > * Defaults to 'singleFile'.
642 > * 'off' disables occurrence highlighting
643 > * 'singleFile' triggers occurrence highlighting in the current document
644 > * 'multiFile' triggers occurrence highlighting across valid open documents
645 > */
646 > occurrencesHighlight?: 'off' | 'singleFile' | 'multiFile';
647 > /**
648 > * Controls delay for occurrences highlighting
649 > * Defaults to 250.
650 > * Minimum value is 0
651 > * Maximum value is 2000
652 > */
653 > occurrencesHighlightDelay?: number;
654 > /**
655 > * Show code lens
656 > * Defaults to true.
657 > */
658 > codeLens?: boolean;
659 > /**
660 > * Code lens font family. Defaults to editor font family.
661 > */
662 > codeLensFontFamily?: string;
663 > /**
664 > * Code lens font size. Default to 90% of the editor font size
665 > */
666 > codeLensFontSize?: number;
667 > /**
668 > * Control the behavior and rendering of the code action lightbulb.
669 > */
670 > lightbulb?: IEditorLightbulbOptions;
671 > /**
672 > * Timeout for running code actions on save.
673 > */
674 > codeActionsOnSaveTimeout?: number;
675 > /**
676 > * Enable code folding.
677 > * Defaults to true.
678 > */
679 > folding?: boolean;
680 > /**
681 > * Selects the folding strategy. 'auto' uses the strategies contributed for the current document, 'indentation' uses the indentation based folding strategy.
682 > * Defaults to 'auto'.
683 > */
684 > foldingStrategy?: 'auto' | 'indentation';
685 > /**
686 > * Enable highlight for folded regions.
687 > * Defaults to true.
688 > */
689 > foldingHighlight?: boolean;
690 > /**
691 > * Auto fold imports folding regions.
692 > * Defaults to true.
693 > */
694 > foldingImportsByDefault?: boolean;
695 > /**
696 > * Maximum number of foldable regions.
697 > * Defaults to 5000.
698 > */
699 > foldingMaximumRegions?: number;
700 > /**
701 > * Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter.
702 > * Defaults to 'mouseover'.
703 > */
704 > showFoldingControls?: 'always' | 'never' | 'mouseover';
705 > /**
706 > * Controls whether clicking on the empty content after a folded line will unfold the line.
707 > * Defaults to false.
708 > */
709 > unfoldOnClickAfterEndOfLine?: boolean;
710 > /**
711 > * Enable highlighting of matching brackets.
712 > * Defaults to 'always'.
713 > */
714 > matchBrackets?: 'never' | 'near' | 'always';
715 > /**
716 > * Enable experimental rendering using WebGPU.
717 > * Defaults to 'off'.
718 > */
719 > experimentalGpuAcceleration?: 'on' | 'off';
720 > /**
721 > * Enable experimental whitespace rendering.
722 > * Defaults to 'svg'.
723 > */
724 > experimentalWhitespaceRendering?: 'svg' | 'font' | 'off';
725 > /**
726 > * Enable rendering of whitespace.
727 > * Defaults to 'selection'.
728 > */
729 > renderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
730 > /**
731 > * Enable rendering of control characters.
732 > * Defaults to true.
733 > */
734 > renderControlCharacters?: boolean;
735 > /**
736 > * Enable rendering of current line highlight.
737 > * Defaults to all.
738 > */
739 > renderLineHighlight?: 'none' | 'gutter' | 'line' | 'all';
740 > /**
741 > * Control if the current line highlight should be rendered only the editor is focused.
742 > * Defaults to false.
743 > */
744 > renderLineHighlightOnlyWhenFocus?: boolean;
745 > /**
746 > * Inserting and deleting whitespace follows tab stops.
747 > */
748 > useTabStops?: boolean;
749 > /**
750 > * Controls whether the editor should automatically remove indentation whitespace when joining lines with Delete.
751 > * Defaults to false.
752 > */
753 > trimWhitespaceOnDelete?: boolean;
754 > /**
755 > * The font family
756 > */
757 > fontFamily?: string;
758 > /**
759 > * The font weight
760 > */
761 > fontWeight?: string;
762 > /**
763 > * The font size
764 > */
765 > fontSize?: number;
766 > /**
767 > * The line height
768 > */
769 > lineHeight?: number;
770 > /**
771 > * The letter spacing
772 > */
773 > letterSpacing?: number;
774 > /**
775 > * Controls fading out of unused variables.
776 > */
777 > showUnused?: boolean;
778 > /**
779 > * Controls whether to focus the inline editor in the peek widget by default.
780 > * Defaults to false.
781 > */
782 > peekWidgetDefaultFocus?: 'tree' | 'editor';
783 >
784 > /**
785 > * Sets a placeholder for the editor.
786 > * If set, the placeholder is shown if the editor is empty.
787 > */
788 > placeholder?: string | undefined;
789 >
790 > /**
791 > * Controls whether the definition link opens element in the peek widget.
792 > * Defaults to false.
793 > */
794 > definitionLinkOpensInPeek?: boolean;
795 > /**
796 > * Controls strikethrough deprecated variables.
797 > */
798 > showDeprecated?: boolean;
799 > /**
800 > * Controls whether suggestions allow matches in the middle of the word instead of only at the beginning
801 > */
802 > matchOnWordStartOnly?: boolean;
803 > /**
804 > * Control the behavior and rendering of the inline hints.
805 > */
806 > inlayHints?: IEditorInlayHintsOptions;
807 > /**
808 > * Control if the editor should use shadow DOM.
809 > */
810 > useShadowDOM?: boolean;
811 > /**
812 > * Controls the behavior of editor guides.
813 > */
814 > guides?: IGuidesOptions;
815 >
816 > /**
817 > * Controls the behavior of the unicode highlight feature
818 > * (by default, ambiguous and invisible characters are highlighted).
819 > */
820 > unicodeHighlight?: IUnicodeHighlightOptions;
821 >
822 > /**
823 > * Configures bracket pair colorization (disabled by default).
824 > */
825 > bracketPairColorization?: IBracketPairColorizationOptions;
826 >
827 > /**
828 > * Controls dropping into the editor from an external source.
829 > *
830 > * When enabled, this shows a preview of the drop location and triggers an `onDropIntoEditor` event.
831 > */
832 > dropIntoEditor?: IDropIntoEditorOptions;
833 >
834 > /**
835 > * Sets whether the new experimental edit context should be used instead of the text area.
836 > */
837 > editContext?: boolean;
838 >
839 > /**
840 > * Controls whether to render rich HTML screen reader content when the EditContext is enabled
841 > */
842 > renderRichScreenReaderContent?: boolean;
843 >
844 > /**
845 > * Controls support for changing how content is pasted into the editor.
846 > */
847 > pasteAs?: IPasteAsOptions;
848 >
849 > /**
850 > * Controls whether the editor / terminal receives tabs or defers them to the workbench for navigation.
851 > */
852 > tabFocusMode?: boolean;
853 >
854 > /**
855 > * Controls whether the accessibility hint should be provided to screen reader users when an inline completion is shown.
856 > */
857 > inlineCompletionsAccessibilityVerbose?: boolean;
858 > }
859 >
860 > /**
861 > * @internal
862 > * The width of the minimap gutter, in pixels.
863 > */
864 > export const MINIMAP_GUTTER_WIDTH = 8;
865 >
866 > export interface IDiffEditorBaseOptions {
867 > /**
868 > * Allow the user to resize the diff editor split view.
869 > * Defaults to true.
870 > */
871 > enableSplitViewResizing?: boolean;
872 >
873 > /**
874 > * The default ratio when rendering side-by-side editors.
875 > * Must be a number between 0 and 1, min sizes apply.
876 > * Defaults to 0.5
877 > */
878 > splitViewDefaultRatio?: number;
879 >
880 > /**
881 > * Render the differences in two side-by-side editors.
882 > * Defaults to true.
883 > */
884 > renderSideBySide?: boolean;
885 >
886 > /**
887 > * When `renderSideBySide` is enabled, `useInlineViewWhenSpaceIsLimited` is set,
888 > * and the diff editor has a width less than `renderSideBySideInlineBreakpoint`, the inline view is used.
889 > */
890 > renderSideBySideInlineBreakpoint?: number | undefined;
891 >
892 > /**
893 > * When `renderSideBySide` is enabled, `useInlineViewWhenSpaceIsLimited` is set,
894 > * and the diff editor has a width less than `renderSideBySideInlineBreakpoint`, the inline view is used.
895 > */
896 > useInlineViewWhenSpaceIsLimited?: boolean;
897 >
898 > /**
899 > * If set, the diff editor is optimized for small views.
900 > * Defaults to `false`.
901 > */
902 > compactMode?: boolean;
903 >
904 > /**
905 > * If set, the original editor's line numbers are hidden in the inline view.
906 > * Defaults to `false`.
907 > * @internal
908 > */
909 > hideOriginalLineNumbers?: boolean;
910 >
911 > /**
912 > * Timeout in milliseconds after which diff computation is cancelled.
913 > * Defaults to 5000.
914 > */
915 > maxComputationTime?: number;
916 >
917 > /**
918 > * Maximum supported file size in MB.
919 > * Defaults to 50.
920 > */
921 > maxFileSize?: number;
922 >
923 > /**
924 > * Compute the diff by ignoring leading/trailing whitespace
925 > * Defaults to true.
926 > */
927 > ignoreTrimWhitespace?: boolean;
928 >
929 > /**
930 > * Render +/- indicators for added/deleted changes.
931 > * Defaults to true.
932 > */
933 > renderIndicators?: boolean;
934 >
935 > /**
936 > * Shows icons in the glyph margin to revert changes.
937 > * Default to true.
938 > */
939 > renderMarginRevertIcon?: boolean;
940 >
941 > /**
942 > * Indicates if the gutter menu should be rendered.
943 > */
944 > renderGutterMenu?: boolean;
945 >
946 > /**
947 > * Original model should be editable?
948 > * Defaults to false.
949 > */
950 > originalEditable?: boolean;
951 >
952 > /**
953 > * Should the diff editor enable code lens?
954 > * Defaults to false.
955 > */
956 > diffCodeLens?: boolean;
957 >
958 > /**
959 > * Is the diff editor should render overview ruler
960 > * Defaults to true
961 > */
962 > renderOverviewRuler?: boolean;
963 >
964 > /**
965 > * Control the wrapping of the diff editor.
966 > */
967 > diffWordWrap?: 'off' | 'on' | 'inherit';
968 >
969 > /**
970 > * Diff Algorithm
971 > */
972 > diffAlgorithm?: 'legacy' | 'advanced' | 'advanced-external' | 'advanced-wasm';
973 >
974 > /**
975 > * Whether the diff editor aria label should be verbose.
976 > */
977 > accessibilityVerbose?: boolean;
978 >
979 > experimental?: {
980 > /**
981 > * Defaults to false.
982 > */
983 > showMoves?: boolean;
984 >
985 > showEmptyDecorations?: boolean;
986 >
987 > /**
988 > * Only applies when `renderSideBySide` is set to false.
989 > */
990 > useTrueInlineView?: boolean;
991 > };
992 >
993 > /**
994 > * Is the diff editor inside another editor
995 > * Defaults to false
996 > */
997 > isInEmbeddedEditor?: boolean;
998 >
999 > /**
1000 > * If the diff editor should only show the difference review mode.
1001 > */
1002 > onlyShowAccessibleDiffViewer?: boolean;
1003 >
1004 > hideUnchangedRegions?: {
1005 > enabled?: boolean;
1006 > revealLineCount?: number;
1007 > minimumLineCount?: number;
1008 > contextLineCount?: number;
1009 > };
1010 > }
1011 >
1012 > /**
1013 > * Configuration options for the diff editor.
1014 > */
1015 > export interface IDiffEditorOptions extends IEditorOptions, IDiffEditorBaseOptions {
1016 > }
1017 >
1018 > /**
1019 > * @internal
1020 > */
1021 > export type ValidDiffEditorBaseOptions = Readonly<Required<IDiffEditorBaseOptions>>;
1022 >
1023 > //#endregion
1024 >
1025 > /**
1026 > * An event describing that the configuration of the editor has changed.
1027 > */
1028 > export class ConfigurationChangedEvent {
1029 > private readonly _values: boolean[];
1030 > /**
1031 > * @internal
1032 > */
1033 > constructor(values: boolean[]) {
1034 this._values = values;
1035 }
1036 > public hasChanged(id: EditorOption): boolean { editorOptions.ts
1037 return this._values[id];
1038 }
1039 > } editorOptions.ts
1040 >
1041 > /**
1042 > * All computed editor options.
1043 > */
1044 > export interface IComputedEditorOptions {
1045 > get<T extends EditorOption>(id: T): FindComputedEditorOptionValueById<T>;
1046 > }
1047 >
1048 > //#region IEditorOption
1049 >
1050 > /**
1051 > * @internal
1052 > */
1053 > export interface IEnvironmentalOptions {
1054 > readonly memory: ComputeOptionsMemory | null;
1055 > readonly outerWidth: number;
1056 > readonly outerHeight: number;
1057 > readonly fontInfo: FontInfo;
1058 > readonly extraEditorClassName: string;
1059 > readonly isDominatedByLongLines: boolean;
1060 > readonly viewLineCount: number;
1061 > readonly lineNumbersDigitCount: number;
1062 > readonly emptySelectionClipboard: boolean;
1063 > readonly pixelRatio: number;
1064 > readonly tabFocusMode: boolean;
1065 > readonly inputMode: 'insert' | 'overtype';
1066 > readonly accessibilitySupport: AccessibilitySupport;
1067 > readonly glyphMarginDecorationLaneCount: number;
1068 > readonly editContextSupported: boolean;
1069 > }
1070 >
1071 > /**
1072 > * @internal
1073 > */
1074 > export class ComputeOptionsMemory {
1075 >
1076 > public stableMinimapLayoutInput: IMinimapLayoutInput | null;
1077 > public stableFitMaxMinimapScale: number;
1078 > public stableFitRemainingWidth: number;
1079 >
1080 > constructor() {
1081 this.stableMinimapLayoutInput = null;
1082 this.stableFitMaxMinimapScale = 0;
1083 this.stableFitRemainingWidth = 0;
1084 }
1085 > } editorOptions.ts
1086 >
1087 > export interface IEditorOption<K extends EditorOption, V> {
1088 > readonly id: K;
1089 > readonly name: string;
1090 > defaultValue: V;
1091 > /**
1092 > * @internal
1093 > */
1094 > readonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema } | undefined;
1095 > /**
1096 > * @internal
1097 > */
1098 > validate(input: unknown): V;
1099 > /**
1100 > * @internal
1101 > */
1102 > compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V;
1103 >
1104 > /**
1105 > * Might modify `value`.
1106 > */
1107 > applyUpdate(value: V | undefined, update: V): ApplyUpdateResult<V>;
1108 > }
1109 >
1110 > /**
1111 > * @internal
1112 > */
1113 > type PossibleKeyName0<V> = { [K in keyof IEditorOptions]: IEditorOptions[K] extends V | undefined ? K : never }[keyof IEditorOptions];
1114 > /**
1115 > * @internal
1116 > */
1117 > type PossibleKeyName<V> = NonNullable<PossibleKeyName0<V>>;
1118 >
1119 > /**
1120 > * @internal
1121 > */
1122 > abstract class BaseEditorOption<K extends EditorOption, T, V> implements IEditorOption<K, V> {
1123 >
1124 > public readonly id: K;
1125 > public readonly name: string;
1126 > public readonly defaultValue: V;
1127 > public readonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema } | undefined;
1128 >
1129 > constructor(id: K, name: PossibleKeyName<T>, defaultValue: V, schema?: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema }) {
1130 > this.id = id;
1131 > this.name = name;
1132 > this.defaultValue = defaultValue;
1133 > this.schema = schema;
1134 > }
1135 >
1136 > public applyUpdate(value: V | undefined, update: V): ApplyUpdateResult<V> {
1137 return applyUpdate(value, update);
1138 }
1140 > public abstract validate(input: unknown): V;
1141 >
1142 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V {
1143 return value;
1144 }
1145 > } editorOptions.ts
1146 >
1147 > export class ApplyUpdateResult<T> {
1148 > constructor(
1149 public readonly newValue: T,
1150 public readonly didChange: boolean
1151 ) { }
1152 > } editorOptions.ts
1153 >
1154 function applyUpdate<T>(value: T | undefined, update: T): ApplyUpdateResult<T> {
1155 if (typeof value !== 'object' || typeof update !== 'object' || !value || !update) {
1172 return new ApplyUpdateResult(value, didChange);
1173 }
1175 > /**
1176 > * @internal
1177 > */
1178 > abstract class ComputedEditorOption<K extends EditorOption, V> implements IEditorOption<K, V> {
1179 >
1180 > public readonly id: K;
1181 > public readonly name: '_never_';
1182 > public readonly defaultValue: V;
1183 > public readonly schema: IConfigurationPropertySchema | undefined = undefined;
1184 >
1185 > constructor(id: K, defaultValue: V) {
1186 > this.id = id;
1187 > this.name = '_never_';
1188 > this.defaultValue = defaultValue;
1189 > }
1190 >
1191 > public applyUpdate(value: V | undefined, update: V): ApplyUpdateResult<V> {
1192 return applyUpdate(value, update);
1193 }
1195 > public validate(input: unknown): V {
1196 return this.defaultValue;
1197 }
1199 > public abstract compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V;
1200 > }
1201 >
1202 > abstract class SimpleEditorOption<K extends EditorOption, V> implements IEditorOption<K, V> {
1203 >
1204 > public readonly id: K;
1205 > public readonly name: PossibleKeyName<V>;
1206 > public readonly defaultValue: V;
1207 > public readonly schema: IConfigurationPropertySchema | undefined;
1208 >
1209 > constructor(id: K, name: PossibleKeyName<V>, defaultValue: V, schema?: IConfigurationPropertySchema) {
1210 > this.id = id;
1211 > this.name = name;
1212 > this.defaultValue = defaultValue;
1213 > this.schema = schema;
1214 > }
1215 >
1216 > public applyUpdate(value: V | undefined, update: V): ApplyUpdateResult<V> {
1217 return applyUpdate(value, update);
1218 }
1220 > public abstract validate(input: unknown): V;
1221 >
1222 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V {
1223 return value;
1224 }
1225 > } editorOptions.ts
1226 >
1227 > /**
1228 > * @internal
1229 > */
1230 > export function boolean(value: unknown, defaultValue: boolean): boolean {
1231 if (typeof value === 'undefined') {
1232 return defaultValue;
1238 return Boolean(value);
1239 }
1241 > class EditorBooleanOption<K extends EditorOption> extends SimpleEditorOption<K, boolean> {
1242 >
1243 > constructor(id: K, name: PossibleKeyName<boolean>, defaultValue: boolean, schema: IConfigurationPropertySchema | undefined = undefined) {
1244 > if (typeof schema !== 'undefined') {
1245 > schema.type = 'boolean';
1246 > schema.default = defaultValue;
1247 > }
1248 > super(id, name, defaultValue, schema);
1249 > }
1250 >
1251 > public override validate(input: unknown): boolean {
1252 return boolean(input, this.defaultValue);
1253 }
1254 > } editorOptions.ts
1255 >
1256 > /**
1257 > * @internal
1258 > */
1259 > export function clampedInt<T = number>(value: unknown, defaultValue: T, minimum: number, maximum: number): number | T {
1260 if (typeof value === 'string') {
1261 value = parseInt(value, 10);
1269 return r | 0;
1270 }
1272 > class EditorIntOption<K extends EditorOption> extends SimpleEditorOption<K, number> {
1273 >
1274 > public static clampedInt<T>(value: unknown, defaultValue: T, minimum: number, maximum: number): number | T {
1275 return clampedInt(value, defaultValue, minimum, maximum);
1276 }
1278 > public readonly minimum: number;
1279 > public readonly maximum: number;
1280 >
1281 > constructor(id: K, name: PossibleKeyName<number>, defaultValue: number, minimum: number, maximum: number, schema: IConfigurationPropertySchema | undefined = undefined) {
1282 > if (typeof schema !== 'undefined') {
1283 > schema.type = 'integer';
1284 > schema.default = defaultValue;
1285 > schema.minimum = minimum;
1286 > schema.maximum = maximum;
1287 > }
1288 > super(id, name, defaultValue, schema);
1289 > this.minimum = minimum;
1290 > this.maximum = maximum;
1291 > }
1292 >
1293 > public override validate(input: unknown): number {
1294 return EditorIntOption.clampedInt(input, this.defaultValue, this.minimum, this.maximum);
1295 }
1296 > } editorOptions.ts
1297 > /**
1298 > * @internal
1299 > */
1300 > export function clampedFloat<T extends number>(value: unknown, defaultValue: T, minimum: number, maximum: number): number | T {
1301 if (typeof value === 'undefined') {
1302 return defaultValue;
1305 return EditorFloatOption.clamp(r, minimum, maximum);
1306 }
1308 > class EditorFloatOption<K extends EditorOption> extends SimpleEditorOption<K, number> {
1309 >
1310 > public readonly minimum: number | undefined;
1311 > public readonly maximum: number | undefined;
1312 >
1313 > public static clamp(n: number, min: number, max: number): number {
1314 if (n < min) {
1315 return min;
1320 return n;
1321 }
1323 > public static float(value: unknown, defaultValue: number): number {
1324 if (typeof value === 'string') {
1325 value = parseFloat(value);
1330 return value;
1331 }
1333 > public readonly validationFn: (value: number) => number;
1334 >
1335 > constructor(id: K, name: PossibleKeyName<number>, defaultValue: number, validationFn: (value: number) => number, schema?: IConfigurationPropertySchema, minimum?: number, maximum?: number) {
1336 > if (typeof schema !== 'undefined') {
1337 > schema.type = 'number';
1338 > schema.default = defaultValue;
1339 > schema.minimum = minimum;
1340 > schema.maximum = maximum;
1341 > }
1342 > super(id, name, defaultValue, schema);
1343 > this.validationFn = validationFn;
1344 > this.minimum = minimum;
1345 > this.maximum = maximum;
1346 > }
1347 >
1348 > public override validate(input: unknown): number {
1349 return this.validationFn(EditorFloatOption.float(input, this.defaultValue));
1350 }
1351 > } editorOptions.ts
1352 >
1353 > class EditorStringOption<K extends EditorOption> extends SimpleEditorOption<K, string> {
1354 >
1355 > public static string(value: unknown, defaultValue: string): string {
1356 if (typeof value !== 'string') {
1357 return defaultValue;
1359 return value;
1360 }
1362 > constructor(id: K, name: PossibleKeyName<string>, defaultValue: string, schema: IConfigurationPropertySchema | undefined = undefined) {
1363 > if (typeof schema !== 'undefined') {
1364 > schema.type = 'string';
1365 > schema.default = defaultValue;
1366 > }
1367 > super(id, name, defaultValue, schema);
1368 > }
1369 >
1370 > public override validate(input: unknown): string {
1371 return EditorStringOption.string(input, this.defaultValue);
1372 }
1373 > } editorOptions.ts
1374 >
1375 > /**
1376 > * @internal
1377 > */
1378 > export function stringSet<T extends string>(value: unknown, defaultValue: T, allowedValues: ReadonlyArray<T>, renamedValues?: Record<string, T>): T {
1379 if (typeof value !== 'string') {
1380 return defaultValue;
1388 return value as T;
1389 }
1391 > class EditorStringEnumOption<K extends EditorOption, V extends string> extends SimpleEditorOption<K, V> {
1392 >
1393 > private readonly _allowedValues: ReadonlyArray<V>;
1394 >
1395 > constructor(id: K, name: PossibleKeyName<V>, defaultValue: V, allowedValues: ReadonlyArray<V>, schema: IConfigurationPropertySchema | undefined = undefined) {
1396 > if (typeof schema !== 'undefined') {
1397 > schema.type = 'string';
1398 > schema.enum = allowedValues.slice(0);
1399 > schema.default = defaultValue;
1400 > }
1401 > super(id, name, defaultValue, schema);
1402 > this._allowedValues = allowedValues;
1403 > }
1404 >
1405 > public override validate(input: unknown): V {
1406 return stringSet<V>(input, this.defaultValue, this._allowedValues);
1407 }
1408 > } editorOptions.ts
1409 >
1410 > class EditorEnumOption<K extends EditorOption, T extends string, V> extends BaseEditorOption<K, T, V> {
1411 >
1412 > private readonly _allowedValues: T[];
1413 > private readonly _convert: (value: T) => V;
1414 >
1415 > constructor(id: K, name: PossibleKeyName<T>, defaultValue: V, defaultStringValue: string, allowedValues: T[], convert: (value: T) => V, schema: IConfigurationPropertySchema | undefined = undefined) {
1416 > if (typeof schema !== 'undefined') {
1417 > schema.type = 'string';
1418 > schema.enum = allowedValues;
1419 > schema.default = defaultStringValue;
1420 > }
1421 > super(id, name, defaultValue, schema);
1422 > this._allowedValues = allowedValues;
1423 > this._convert = convert;
1424 > }
1425 >
1426 > public validate(input: unknown): V {
1427 if (typeof input !== 'string') {
1428 return this.defaultValue;
1433 return this._convert(<T>input);
1434 }
1435 > } editorOptions.ts
1436 >
1437 > //#endregion
1438 >
1439 > //#region autoIndent
1440 >
1441 function _autoIndentFromString(autoIndent: 'none' | 'keep' | 'brackets' | 'advanced' | 'full'): EditorAutoIndentStrategy {
1442 switch (autoIndent) {
1448 }
1449 }
1451 > //#endregion
1452 >
1453 > //#region accessibilitySupport
1454 >
1455 > class EditorAccessibilitySupport extends BaseEditorOption<EditorOption.accessibilitySupport, 'auto' | 'off' | 'on', AccessibilitySupport> {
1456 >
1457 > constructor() {
1458 > super(
1459 > EditorOption.accessibilitySupport, 'accessibilitySupport', AccessibilitySupport.Unknown,
1460 > {
1461 > type: 'string',
1462 > enum: ['auto', 'on', 'off'],
1463 > enumDescriptions: [
1464 > nls.localize('accessibilitySupport.auto', "Use platform APIs to detect when a Screen Reader is attached."),
1465 > nls.localize('accessibilitySupport.on', "Optimize for usage with a Screen Reader."),
1466 > nls.localize('accessibilitySupport.off', "Assume a screen reader is not attached."),
1467 > ],
1468 > default: 'auto',
1469 > tags: ['accessibility'],
1470 > description: nls.localize('accessibilitySupport', "Controls if the UI should run in a mode where it is optimized for screen readers.")
1471 > }
1472 > );
1473 > }
1474 >
1475 > public validate(input: unknown): AccessibilitySupport {
1476 switch (input) {
1477 case 'auto': return AccessibilitySupport.Unknown;
1481 return this.defaultValue;
1482 }
1484 > public override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: AccessibilitySupport): AccessibilitySupport {
1485 if (value === AccessibilitySupport.Unknown) {
1486 // The editor reads the `accessibilitySupport` from the environment
1489 return value;
1490 }
1491 > } editorOptions.ts
1492 >
1493 > //#endregion
1494 >
1495 > //#region comments
1496 >
1497 > /**
1498 > * Configuration options for editor comments
1499 > */
1500 > export interface IEditorCommentsOptions {
1501 > /**
1502 > * Insert a space after the line comment token and inside the block comments tokens.
1503 > * Defaults to true.
1504 > */
1505 > insertSpace?: boolean;
1506 > /**
1507 > * Ignore empty lines when inserting line comments.
1508 > * Defaults to true.
1509 > */
1510 > ignoreEmptyLines?: boolean;
1511 > }
1512 >
1513 > /**
1514 > * @internal
1515 > */
1516 > export type EditorCommentsOptions = Readonly<Required<IEditorCommentsOptions>>;
1517 >
1518 > class EditorComments extends BaseEditorOption<EditorOption.comments, IEditorCommentsOptions, EditorCommentsOptions> {
1519 >
1520 > constructor() {
1521 > const defaults: EditorCommentsOptions = {
1522 > insertSpace: true,
1523 > ignoreEmptyLines: true,
1524 > };
1525 > super(
1526 > EditorOption.comments, 'comments', defaults,
1527 > {
1528 > 'editor.comments.insertSpace': {
1529 > type: 'boolean',
1530 > default: defaults.insertSpace,
1531 > description: nls.localize('comments.insertSpace', "Controls whether a space character is inserted when commenting.")
1532 > },
1533 > 'editor.comments.ignoreEmptyLines': {
1534 > type: 'boolean',
1535 > default: defaults.ignoreEmptyLines,
1536 > description: nls.localize('comments.ignoreEmptyLines', 'Controls if empty lines should be ignored with toggle, add or remove actions for line comments.')
1537 > },
1538 > }
1539 > );
1540 > }
1541 >
1542 > public validate(_input: unknown): EditorCommentsOptions {
1543 if (!_input || typeof _input !== 'object') {
1544 return this.defaultValue;
1550 };
1551 }
1552 > } editorOptions.ts
1553 >
1554 > //#endregion
1555 >
1556 > //#region cursorBlinking
1557 >
1558 > /**
1559 > * The kind of animation in which the editor's cursor should be rendered.
1560 > */
1561 > export const enum TextEditorCursorBlinkingStyle {
1562 > /**
1563 > * Hidden
1564 > */
1565 > Hidden = 0,
1566 > /**
1567 > * Blinking
1568 > */
1569 > Blink = 1,
1570 > /**
1571 > * Blinking with smooth fading
1572 > */
1573 > Smooth = 2,
1574 > /**
1575 > * Blinking with prolonged filled state and smooth fading
1576 > */
1577 > Phase = 3,
1578 > /**
1579 > * Expand collapse animation on the y axis
1580 > */
1581 > Expand = 4,
1582 > /**
1583 > * No-Blinking
1584 > */
1585 > Solid = 5
1586 > }
1587 >
1588 > /**
1589 > * @internal
1590 > */
1591 > export function cursorBlinkingStyleFromString(cursorBlinkingStyle: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid'): TextEditorCursorBlinkingStyle {
1592 switch (cursorBlinkingStyle) {
1593 case 'blink': return TextEditorCursorBlinkingStyle.Blink;
1598 }
1599 }
1601 > //#endregion
1602 >
1603 > //#region cursorStyle
1604 >
1605 > /**
1606 > * The style in which the editor's cursor should be rendered.
1607 > */
1608 > export enum TextEditorCursorStyle {
1609 > /**
1610 > * As a vertical line (sitting between two characters).
1611 > */
1612 > Line = 1,
1613 > /**
1614 > * As a block (sitting on top of a character).
1615 > */
1616 > Block = 2,
1617 > /**
1618 > * As a horizontal line (sitting under a character).
1619 > */
1620 > Underline = 3,
1621 > /**
1622 > * As a thin vertical line (sitting between two characters).
1623 > */
1624 > LineThin = 4,
1625 > /**
1626 > * As an outlined block (sitting on top of a character).
1627 > */
1628 > BlockOutline = 5,
1629 > /**
1630 > * As a thin horizontal line (sitting under a character).
1631 > */
1632 > UnderlineThin = 6
1633 > }
1634 >
1635 > /**
1636 > * @internal
1637 > */
1638 > export function cursorStyleToString(cursorStyle: TextEditorCursorStyle): 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin' {
1639 switch (cursorStyle) {
1640 case TextEditorCursorStyle.Line: return 'line';
1646 }
1647 }
1649 > /**
1650 > * @internal
1651 > */
1652 > export function cursorStyleFromString(cursorStyle: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin'): TextEditorCursorStyle {
1653 switch (cursorStyle) {
1654 case 'line': return TextEditorCursorStyle.Line;
1660 }
1661 }
1663 > //#endregion
1664 >
1665 > //#region editorClassName
1666 >
1667 > class EditorClassName extends ComputedEditorOption<EditorOption.editorClassName, string> {
1668 >
1669 > constructor() {
1670 > super(EditorOption.editorClassName, '');
1671 > }
1672 >
1673 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string {
1674 const classNames = ['monaco-editor'];
1675 if (options.get(EditorOption.extraEditorClassName)) {
1695 return classNames.join(' ');
1696 }
1697 > } editorOptions.ts
1698 >
1699 > //#endregion
1700 >
1701 > //#region emptySelectionClipboard
1702 >
1703 > class EditorEmptySelectionClipboard extends EditorBooleanOption<EditorOption.emptySelectionClipboard> {
1704 >
1705 > constructor() {
1706 > super(
1707 > EditorOption.emptySelectionClipboard, 'emptySelectionClipboard', true,
1708 > { description: nls.localize('emptySelectionClipboard', "Controls whether copying without a selection copies the current line.") }
1709 > );
1710 > }
1711 >
1712 > public override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: boolean): boolean {
1713 return value && env.emptySelectionClipboard;
1714 }
1715 > } editorOptions.ts
1716 >
1717 > //#endregion
1718 >
1719 > //#region find
1720 >
1721 > /**
1722 > * Configuration options for editor find widget
1723 > */
1724 > export interface IEditorFindOptions {
1725 > /**
1726 > * Controls whether the cursor should move to find matches while typing.
1727 > */
1728 > cursorMoveOnType?: boolean;
1729 > /**
1730 > * Controls whether the find widget should search as you type.
1731 > */
1732 > findOnType?: boolean;
1733 > /**
1734 > * Controls if we seed search string in the Find Widget with editor selection.
1735 > */
1736 > seedSearchStringFromSelection?: 'never' | 'always' | 'selection';
1737 > /**
1738 > * Controls if Find in Selection flag is turned on in the editor.
1739 > */
1740 > autoFindInSelection?: 'never' | 'always' | 'multiline';
1741 > /*
1742 > * Controls whether the Find Widget should add extra lines on top of the editor.
1743 > */
1744 > addExtraSpaceOnTop?: boolean;
1745 > /**
1746 > * @internal
1747 > * Controls if the Find Widget should read or modify the shared find clipboard on macOS
1748 > */
1749 > globalFindClipboard?: boolean;
1750 > /**
1751 > * Controls whether the search result and diff result automatically restarts from the beginning (or the end) when no further matches can be found
1752 > */
1753 > loop?: boolean;
1754 > /**
1755 > * Controls whether to close the Find Widget after an explicit find navigation command lands on a match.
1756 > */
1757 > closeOnResult?: boolean;
1758 > /**
1759 > * @internal
1760 > * Controls how the find widget search history should be stored
1761 > */
1762 > history?: 'never' | 'workspace';
1763 > /**
1764 > * @internal
1765 > * Controls how the replace widget search history should be stored
1766 > */
1767 > replaceHistory?: 'never' | 'workspace';
1768 > }
1769 >
1770 > /**
1771 > * @internal
1772 > */
1773 > export type EditorFindOptions = Readonly<Required<IEditorFindOptions>>;
1774 >
1775 > class EditorFind extends BaseEditorOption<EditorOption.find, IEditorFindOptions, EditorFindOptions> {
1776 >
1777 > constructor() {
1778 > const defaults: EditorFindOptions = {
1779 > cursorMoveOnType: true,
1780 > findOnType: true,
1781 > seedSearchStringFromSelection: 'always',
1782 > autoFindInSelection: 'never',
1783 > globalFindClipboard: false,
1784 > addExtraSpaceOnTop: true,
1785 > loop: true,
1786 > closeOnResult: false,
1787 > history: 'workspace',
1788 > replaceHistory: 'workspace',
1789 > };
1790 > super(
1791 > EditorOption.find, 'find', defaults,
1792 > {
1793 > 'editor.find.cursorMoveOnType': {
1794 > type: 'boolean',
1795 > default: defaults.cursorMoveOnType,
1796 > description: nls.localize('find.cursorMoveOnType', "Controls whether the cursor should jump to find matches while typing.")
1797 > },
1798 > 'editor.find.seedSearchStringFromSelection': {
1799 > type: 'string',
1800 > enum: ['never', 'always', 'selection'],
1801 > default: defaults.seedSearchStringFromSelection,
1802 > enumDescriptions: [
1803 > nls.localize('editor.find.seedSearchStringFromSelection.never', 'Never seed search string from the editor selection.'),
1804 > nls.localize('editor.find.seedSearchStringFromSelection.always', 'Always seed search string from the editor selection, including word at cursor position.'),
1805 > nls.localize('editor.find.seedSearchStringFromSelection.selection', 'Only seed search string from the editor selection.')
1806 > ],
1807 > description: nls.localize('find.seedSearchStringFromSelection', "Controls whether the search string in the Find Widget is seeded from the editor selection.")
1808 > },
1809 > 'editor.find.autoFindInSelection': {
1810 > type: 'string',
1811 > enum: ['never', 'always', 'multiline'],
1812 > default: defaults.autoFindInSelection,
1813 > enumDescriptions: [
1814 > nls.localize('editor.find.autoFindInSelection.never', 'Never turn on Find in Selection automatically (default).'),
1815 > nls.localize('editor.find.autoFindInSelection.always', 'Always turn on Find in Selection automatically.'),
1816 > nls.localize('editor.find.autoFindInSelection.multiline', 'Turn on Find in Selection automatically when multiple lines of content are selected.')
1817 > ],
1818 > description: nls.localize('find.autoFindInSelection', "Controls the condition for turning on Find in Selection automatically.")
1819 > },
1820 > 'editor.find.globalFindClipboard': {
1821 > type: 'boolean',
1822 > default: defaults.globalFindClipboard,
1823 > description: nls.localize('find.globalFindClipboard', "Controls whether the Find Widget should read or modify the shared find clipboard on macOS."),
1824 > included: platform.isMacintosh
1825 > },
1826 > 'editor.find.addExtraSpaceOnTop': {
1827 > type: 'boolean',
1828 > default: defaults.addExtraSpaceOnTop,
1829 > description: nls.localize('find.addExtraSpaceOnTop', "Controls whether the Find Widget should add extra lines on top of the editor. When true, you can scroll beyond the first line when the Find Widget is visible.")
1830 > },
1831 > 'editor.find.loop': {
1832 > type: 'boolean',
1833 > default: defaults.loop,
1834 > description: nls.localize('find.loop', "Controls whether the search automatically restarts from the beginning (or the end) when no further matches can be found.")
1835 > },
1836 > 'editor.find.closeOnResult': {
1837 > type: 'boolean',
1838 > default: defaults.closeOnResult,
1839 > description: nls.localize('find.closeOnResult', "Controls whether the Find Widget closes after an explicit find navigation command lands on a result.")
1840 > },
1841 > 'editor.find.history': {
1842 > type: 'string',
1843 > enum: ['never', 'workspace'],
1844 > default: 'workspace',
1845 > enumDescriptions: [
1846 > nls.localize('editor.find.history.never', 'Do not store search history from the find widget.'),
1847 > nls.localize('editor.find.history.workspace', 'Store search history across the active workspace'),
1848 > ],
1849 > description: nls.localize('find.history', "Controls how the find widget history should be stored")
1850 > },
1851 > 'editor.find.replaceHistory': {
1852 > type: 'string',
1853 > enum: ['never', 'workspace'],
1854 > default: 'workspace',
1855 > enumDescriptions: [
1856 > nls.localize('editor.find.replaceHistory.never', 'Do not store history from the replace widget.'),
1857 > nls.localize('editor.find.replaceHistory.workspace', 'Store replace history across the active workspace'),
1858 > ],
1859 > description: nls.localize('find.replaceHistory', "Controls how the replace widget history should be stored")
1860 > },
1861 > 'editor.find.findOnType': {
1862 > type: 'boolean',
1863 > default: defaults.findOnType,
1864 > description: nls.localize('find.findOnType', "Controls whether the Find Widget should search as you type.")
1865 > },
1866 > }
1867 > );
1868 > }
1869 >
1870 > public validate(_input: unknown): EditorFindOptions {
1871 if (!_input || typeof _input !== 'object') {
1872 return this.defaultValue;
1890 };
1891 }
1892 > } editorOptions.ts
1893 >
1894 > //#endregion
1895 >
1896 > //#region fontLigatures
1897 >
1898 > /**
1899 > * @internal
1900 > */
1901 > export class EditorFontLigatures extends BaseEditorOption<EditorOption.fontLigatures, boolean | string, string> {
1902 >
1903 > public static OFF = '"liga" off, "calt" off';
1904 > public static ON = '"liga" on, "calt" on';
1905 >
1906 > constructor() {
1907 > super(
1908 > EditorOption.fontLigatures, 'fontLigatures', EditorFontLigatures.OFF,
1909 > {
1910 > anyOf: [
1911 > {
1912 > type: 'boolean',
1913 > description: nls.localize('fontLigatures', "Enables/Disables font ligatures ('calt' and 'liga' font features). Change this to a string for fine-grained control of the 'font-feature-settings' CSS property."),
1914 > },
1915 > {
1916 > type: 'string',
1917 > description: nls.localize('fontFeatureSettings', "Explicit 'font-feature-settings' CSS property. A boolean can be passed instead if one only needs to turn on/off ligatures.")
1918 > }
1919 > ],
1920 > description: nls.localize('fontLigaturesGeneral', "Configures font ligatures or font features. Can be either a boolean to enable/disable ligatures or a string for the value of the CSS 'font-feature-settings' property."),
1921 > default: false
1922 > }
1923 > );
1924 > }
1925 >
1926 > public validate(input: unknown): string {
1927 if (typeof input === 'undefined') {
1928 return this.defaultValue;
1942 return EditorFontLigatures.OFF;
1943 }
1944 > } editorOptions.ts
1945 >
1946 > //#endregion
1947 >
1948 > //#region fontVariations
1949 >
1950 > /**
1951 > * @internal
1952 > */
1953 > export class EditorFontVariations extends BaseEditorOption<EditorOption.fontVariations, boolean | string, string> {
1954 > // Text is laid out using default settings.
1955 > public static OFF = FONT_VARIATION_OFF;
1956 >
1957 > // Translate `fontWeight` config to the `font-variation-settings` CSS property.
1958 > public static TRANSLATE = FONT_VARIATION_TRANSLATE;
1959 >
1960 > constructor() {
1961 > super(
1962 > EditorOption.fontVariations, 'fontVariations', EditorFontVariations.OFF,
1963 > {
1964 > anyOf: [
1965 > {
1966 > type: 'boolean',
1967 > description: nls.localize('fontVariations', "Enables/Disables the translation from font-weight to font-variation-settings. Change this to a string for fine-grained control of the 'font-variation-settings' CSS property."),
1968 > },
1969 > {
1970 > type: 'string',
1971 > description: nls.localize('fontVariationSettings', "Explicit 'font-variation-settings' CSS property. A boolean can be passed instead if one only needs to translate font-weight to font-variation-settings.")
1972 > }
1973 > ],
1974 > description: nls.localize('fontVariationsGeneral', "Configures font variations. Can be either a boolean to enable/disable the translation from font-weight to font-variation-settings or a string for the value of the CSS 'font-variation-settings' property."),
1975 > default: false
1976 > }
1977 > );
1978 > }
1979 >
1980 > public validate(input: unknown): string {
1981 if (typeof input === 'undefined') {
1982 return this.defaultValue;
1996 return EditorFontVariations.OFF;
1997 }
1999 > public override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: string): string {
2000 // The value is computed from the fontWeight if it is true.
2001 // So take the result from env.fontInfo
2002 return env.fontInfo.fontVariationSettings;
2003 }
2004 > } editorOptions.ts
2005 >
2006 > //#endregion
2007 >
2008 > //#region fontInfo
2009 >
2010 > class EditorFontInfo extends ComputedEditorOption<EditorOption.fontInfo, FontInfo> {
2011 >
2012 > constructor() {
2013 > super(EditorOption.fontInfo, new FontInfo({
2014 > pixelRatio: 0,
2015 > fontFamily: '',
2016 > fontWeight: '',
2017 > fontSize: 0,
2018 > fontFeatureSettings: '',
2019 > fontVariationSettings: '',
2020 > lineHeight: 0,
2021 > letterSpacing: 0,
2022 > isMonospace: false,
2023 > typicalHalfwidthCharacterWidth: 0,
2024 > typicalFullwidthCharacterWidth: 0,
2025 > canUseHalfwidthRightwardsArrow: false,
2026 > spaceWidth: 0,
2027 > middotWidth: 0,
2028 > wsmiddotWidth: 0,
2029 > maxDigitWidth: 0,
2030 > }, false));
2031 > }
2032 >
2033 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: FontInfo): FontInfo {
2034 return env.fontInfo;
2035 }
2036 > } editorOptions.ts
2037 >
2038 > //#endregion
2039 >
2040 > //#region effectiveCursorStyle
2041 >
2042 > class EffectiveCursorStyle extends ComputedEditorOption<EditorOption.effectiveCursorStyle, TextEditorCursorStyle> {
2043 >
2044 > constructor() {
2045 > super(EditorOption.effectiveCursorStyle, TextEditorCursorStyle.Line);
2046 > }
2047 >
2048 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: TextEditorCursorStyle): TextEditorCursorStyle {
2049 return env.inputMode === 'overtype' ?
2050 options.get(EditorOption.overtypeCursorStyle) :
2051 options.get(EditorOption.cursorStyle);
2052 }
2053 > } editorOptions.ts
2054 >
2055 > //#endregion
2056 >
2057 > //#region effectiveExperimentalEditContext
2058 >
2059 > class EffectiveEditContextEnabled extends ComputedEditorOption<EditorOption.effectiveEditContext, boolean> {
2060 >
2061 > constructor() {
2062 > super(EditorOption.effectiveEditContext, false);
2063 > }
2064 >
2065 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions): boolean {
2066 return env.editContextSupported && options.get(EditorOption.editContext);
2067 }
2068 > } editorOptions.ts
2069 >
2070 > //#endregion
2071 >
2072 > //#region effectiveAllowVariableFonts
2073 >
2074 > class EffectiveAllowVariableFonts extends ComputedEditorOption<EditorOption.effectiveAllowVariableFonts, boolean> {
2075 >
2076 > constructor() {
2077 > super(EditorOption.effectiveAllowVariableFonts, false);
2078 > }
2079 >
2080 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions): boolean {
2081 const accessibilitySupport = env.accessibilitySupport;
2082 if (accessibilitySupport === AccessibilitySupport.Enabled) {
2086 }
2087 }
2088 > } editorOptions.ts
2089 >
2090 > //#engregion
2091 >
2092 > //#region fontSize
2093 >
2094 > class EditorFontSize extends SimpleEditorOption<EditorOption.fontSize, number> {
2095 >
2096 > constructor() {
2097 > super(
2098 > EditorOption.fontSize, 'fontSize', EDITOR_FONT_DEFAULTS.fontSize,
2099 > {
2100 > type: 'number',
2101 > minimum: 6,
2102 > maximum: 100,
2103 > default: EDITOR_FONT_DEFAULTS.fontSize,
2104 > description: nls.localize('fontSize', "Controls the font size in pixels.")
2105 > }
2106 > );
2107 > }
2108 >
2109 > public override validate(input: unknown): number {
2110 const r = EditorFloatOption.float(input, this.defaultValue);
2111 if (r === 0) {
2114 return EditorFloatOption.clamp(r, 6, 100);
2115 }
2116 > public override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number { editorOptions.ts
2117 // The final fontSize respects the editor zoom level.
2118 // So take the result from env.fontInfo
2119 return env.fontInfo.fontSize;
2120 }
2121 > } editorOptions.ts
2122 >
2123 > //#endregion
2124 >
2125 > //#region fontWeight
2126 >
2127 > class EditorFontWeight extends BaseEditorOption<EditorOption.fontWeight, string, string> {
2128 > private static SUGGESTION_VALUES = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];
2129 > private static MINIMUM_VALUE = 1;
2130 > private static MAXIMUM_VALUE = 1000;
2131 >
2132 > constructor() {
2133 > super(
2134 > EditorOption.fontWeight, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight,
2135 > {
2136 > anyOf: [
2137 > {
2138 > type: 'number',
2139 > minimum: EditorFontWeight.MINIMUM_VALUE,
2140 > maximum: EditorFontWeight.MAXIMUM_VALUE,
2141 > errorMessage: nls.localize('fontWeightErrorMessage', "Only \"normal\" and \"bold\" keywords or numbers between 1 and 1000 are allowed.")
2142 > },
2143 > {
2144 > type: 'string',
2145 > pattern: '^(normal|bold|1000|[1-9][0-9]{0,2})$'
2146 > },
2147 > {
2148 > enum: EditorFontWeight.SUGGESTION_VALUES
2149 > }
2150 > ],
2151 > default: EDITOR_FONT_DEFAULTS.fontWeight,
2152 > description: nls.localize('fontWeight', "Controls the font weight. Accepts \"normal\" and \"bold\" keywords or numbers between 1 and 1000.")
2153 > }
2154 > );
2155 > }
2156 >
2157 > public validate(input: unknown): string {
2158 if (input === 'normal' || input === 'bold') {
2159 return input;
2161 return String(EditorIntOption.clampedInt(input, EDITOR_FONT_DEFAULTS.fontWeight, EditorFontWeight.MINIMUM_VALUE, EditorFontWeight.MAXIMUM_VALUE));
2162 }
2163 > } editorOptions.ts
2164 >
2165 > //#endregion
2166 >
2167 > //#region gotoLocation
2168 >
2169 > export type GoToLocationValues = 'peek' | 'gotoAndPeek' | 'goto';
2170 >
2171 > /**
2172 > * Configuration options for go to location
2173 > */
2174 > export interface IGotoLocationOptions {
2175 >
2176 > multiple?: GoToLocationValues;
2177 >
2178 > multipleDefinitions?: GoToLocationValues;
2179 > multipleTypeDefinitions?: GoToLocationValues;
2180 > multipleDeclarations?: GoToLocationValues;
2181 > multipleImplementations?: GoToLocationValues;
2182 > multipleReferences?: GoToLocationValues;
2183 > multipleTests?: GoToLocationValues;
2184 >
2185 > alternativeDefinitionCommand?: string;
2186 > alternativeTypeDefinitionCommand?: string;
2187 > alternativeDeclarationCommand?: string;
2188 > alternativeImplementationCommand?: string;
2189 > alternativeReferenceCommand?: string;
2190 > alternativeTestsCommand?: string;
2191 > }
2192 >
2193 > /**
2194 > * @internal
2195 > */
2196 > export type GoToLocationOptions = Readonly<Required<IGotoLocationOptions>>;
2197 >
2198 > class EditorGoToLocation extends BaseEditorOption<EditorOption.gotoLocation, IGotoLocationOptions, GoToLocationOptions> {
2199 >
2200 > constructor() {
2201 > const defaults: GoToLocationOptions = {
2202 > multiple: 'peek',
2203 > multipleDefinitions: 'peek',
2204 > multipleTypeDefinitions: 'peek',
2205 > multipleDeclarations: 'peek',
2206 > multipleImplementations: 'peek',
2207 > multipleReferences: 'peek',
2208 > multipleTests: 'peek',
2209 > alternativeDefinitionCommand: 'editor.action.goToReferences',
2210 > alternativeTypeDefinitionCommand: 'editor.action.goToReferences',
2211 > alternativeDeclarationCommand: 'editor.action.goToReferences',
2212 > alternativeImplementationCommand: '',
2213 > alternativeReferenceCommand: '',
2214 > alternativeTestsCommand: '',
2215 > };
2216 > const jsonSubset: IJSONSchema = {
2217 > type: 'string',
2218 > enum: ['peek', 'gotoAndPeek', 'goto'],
2219 > default: defaults.multiple,
2220 > enumDescriptions: [
2221 > nls.localize('editor.gotoLocation.multiple.peek', 'Show Peek view of the results (default)'),
2222 > nls.localize('editor.gotoLocation.multiple.gotoAndPeek', 'Go to the primary result and show a Peek view'),
2223 > nls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and enable Peek-less navigation to others')
2224 > ]
2225 > };
2226 > const alternativeCommandOptions = ['', 'editor.action.referenceSearch.trigger', 'editor.action.goToReferences', 'editor.action.peekImplementation', 'editor.action.goToImplementation', 'editor.action.peekTypeDefinition', 'editor.action.goToTypeDefinition', 'editor.action.peekDeclaration', 'editor.action.revealDeclaration', 'editor.action.peekDefinition', 'editor.action.revealDefinitionAside', 'editor.action.revealDefinition'];
2227 > super(
2228 > EditorOption.gotoLocation, 'gotoLocation', defaults,
2229 > {
2230 > 'editor.gotoLocation.multiple': {
2231 > deprecationMessage: nls.localize('editor.gotoLocation.multiple.deprecated', "This setting is deprecated, please use separate settings like 'editor.editor.gotoLocation.multipleDefinitions' or 'editor.editor.gotoLocation.multipleImplementations' instead."),
2232 > },
2233 > 'editor.gotoLocation.multipleDefinitions': {
2234 > description: nls.localize('editor.editor.gotoLocation.multipleDefinitions', "Controls the behavior the 'Go to Definition'-command when multiple target locations exist."),
2235 > ...jsonSubset,
2236 > },
2237 > 'editor.gotoLocation.multipleTypeDefinitions': {
2238 > description: nls.localize('editor.editor.gotoLocation.multipleTypeDefinitions', "Controls the behavior the 'Go to Type Definition'-command when multiple target locations exist."),
2239 > ...jsonSubset,
2240 > },
2241 > 'editor.gotoLocation.multipleDeclarations': {
2242 > description: nls.localize('editor.editor.gotoLocation.multipleDeclarations', "Controls the behavior the 'Go to Declaration'-command when multiple target locations exist."),
2243 > ...jsonSubset,
2244 > },
2245 > 'editor.gotoLocation.multipleImplementations': {
2246 > description: nls.localize('editor.editor.gotoLocation.multipleImplemenattions', "Controls the behavior the 'Go to Implementations'-command when multiple target locations exist."),
2247 > ...jsonSubset,
2248 > },
2249 > 'editor.gotoLocation.multipleReferences': {
2250 > description: nls.localize('editor.editor.gotoLocation.multipleReferences', "Controls the behavior the 'Go to References'-command when multiple target locations exist."),
2251 > ...jsonSubset,
2252 > },
2253 > 'editor.gotoLocation.alternativeDefinitionCommand': {
2254 > type: 'string',
2255 > default: defaults.alternativeDefinitionCommand,
2256 > enum: alternativeCommandOptions,
2257 > description: nls.localize('alternativeDefinitionCommand', "Alternative command id that is being executed when the result of 'Go to Definition' is the current location.")
2258 > },
2259 > 'editor.gotoLocation.alternativeTypeDefinitionCommand': {
2260 > type: 'string',
2261 > default: defaults.alternativeTypeDefinitionCommand,
2262 > enum: alternativeCommandOptions,
2263 > description: nls.localize('alternativeTypeDefinitionCommand', "Alternative command id that is being executed when the result of 'Go to Type Definition' is the current location.")
2264 > },
2265 > 'editor.gotoLocation.alternativeDeclarationCommand': {
2266 > type: 'string',
2267 > default: defaults.alternativeDeclarationCommand,
2268 > enum: alternativeCommandOptions,
2269 > description: nls.localize('alternativeDeclarationCommand', "Alternative command id that is being executed when the result of 'Go to Declaration' is the current location.")
2270 > },
2271 > 'editor.gotoLocation.alternativeImplementationCommand': {
2272 > type: 'string',
2273 > default: defaults.alternativeImplementationCommand,
2274 > enum: alternativeCommandOptions,
2275 > description: nls.localize('alternativeImplementationCommand', "Alternative command id that is being executed when the result of 'Go to Implementation' is the current location.")
2276 > },
2277 > 'editor.gotoLocation.alternativeReferenceCommand': {
2278 > type: 'string',
2279 > default: defaults.alternativeReferenceCommand,
2280 > enum: alternativeCommandOptions,
2281 > description: nls.localize('alternativeReferenceCommand', "Alternative command id that is being executed when the result of 'Go to Reference' is the current location.")
2282 > },
2283 > }
2284 > );
2285 > }
2286 >
2287 > public validate(_input: unknown): GoToLocationOptions {
2288 if (!_input || typeof _input !== 'object') {
2289 return this.defaultValue;
2306 };
2307 }
2308 > } editorOptions.ts
2309 >
2310 > //#endregion
2311 >
2312 > //#region hover
2313 >
2314 > /**
2315 > * Configuration options for editor hover
2316 > */
2317 > export interface IEditorHoverOptions {
2318 > /**
2319 > * Enable the hover.
2320 > * Defaults to 'on'.
2321 > */
2322 > enabled?: 'on' | 'off' | 'onKeyboardModifier';
2323 > /**
2324 > * Delay for showing the hover.
2325 > * Defaults to 300.
2326 > */
2327 > delay?: number;
2328 > /**
2329 > * Is the hover sticky such that it can be clicked and its contents selected?
2330 > * Defaults to true.
2331 > */
2332 > sticky?: boolean;
2333 > /**
2334 > * Controls how long the hover is visible after you hovered out of it.
2335 > * Require sticky setting to be true.
2336 > */
2337 > hidingDelay?: number;
2338 > /**
2339 > * Should the hover be shown above the line if possible?
2340 > * Defaults to false.
2341 > */
2342 > above?: boolean;
2343 > /**
2344 > * Should long line warning hovers be shown (tokenization skipped, rendering paused)?
2345 > * Defaults to true.
2346 > */
2347 > showLongLineWarning?: boolean;
2348 > }
2349 >
2350 > /**
2351 > * @internal
2352 > */
2353 > export type EditorHoverOptions = Readonly<Required<IEditorHoverOptions>>;
2354 >
2355 > class EditorHover extends BaseEditorOption<EditorOption.hover, IEditorHoverOptions, EditorHoverOptions> {
2356 >
2357 > constructor() {
2358 > const defaults: EditorHoverOptions = {
2359 > enabled: 'on',
2360 > delay: 300,
2361 > hidingDelay: 300,
2362 > sticky: true,
2363 > above: true,
2364 > showLongLineWarning: true,
2365 > };
2366 > super(
2367 > EditorOption.hover, 'hover', defaults,
2368 > {
2369 > 'editor.hover.enabled': {
2370 > type: 'string',
2371 > enum: ['on', 'off', 'onKeyboardModifier'],
2372 > default: defaults.enabled,
2373 > markdownEnumDescriptions: [
2374 > nls.localize('hover.enabled.on', "Hover is enabled."),
2375 > nls.localize('hover.enabled.off', "Hover is disabled."),
2376 > nls.localize('hover.enabled.onKeyboardModifier', "Hover is shown when holding `{0}` or `Alt` (the opposite modifier of `#editor.multiCursorModifier#`)", platform.isMacintosh ? `Command` : `Control`)
2377 > ],
2378 > description: nls.localize('hover.enabled', "Controls whether the hover is shown."),
2379 > keywords: ['hint', 'info', 'tooltip']
2380 > },
2381 > 'editor.hover.delay': {
2382 > type: 'number',
2383 > default: defaults.delay,
2384 > minimum: 0,
2385 > maximum: 10000,
2386 > description: nls.localize('hover.delay', "Controls the delay in milliseconds after which the hover is shown.")
2387 > },
2388 > 'editor.hover.sticky': {
2389 > type: 'boolean',
2390 > default: defaults.sticky,
2391 > description: nls.localize('hover.sticky', "Controls whether the hover should remain visible when mouse is moved over it.")
2392 > },
2393 > 'editor.hover.hidingDelay': {
2394 > type: 'integer',
2395 > minimum: 0,
2396 > default: defaults.hidingDelay,
2397 > markdownDescription: nls.localize('hover.hidingDelay', "Controls the delay in milliseconds after which the hover is hidden. Requires `#editor.hover.sticky#` to be enabled.")
2398 > },
2399 > 'editor.hover.above': {
2400 > type: 'boolean',
2401 > default: defaults.above,
2402 > description: nls.localize('hover.above', "Prefer showing hovers above the line, if there's space.")
2403 > },
2404 > 'editor.hover.showLongLineWarning': {
2405 > type: 'boolean',
2406 > default: defaults.showLongLineWarning,
2407 > description: nls.localize('hover.showLongLineWarning', "Controls whether long line warning hovers are shown, such as when tokenization is skipped or rendering is paused.")
2408 > },
2409 > }
2410 > );
2411 > }
2412 >
2413 > public validate(_input: unknown): EditorHoverOptions {
2414 if (!_input || typeof _input !== 'object') {
2415 return this.defaultValue;
2425 };
2426 }
2427 > } editorOptions.ts
2428 >
2429 > //#endregion
2430 >
2431 > //#region layoutInfo
2432 >
2433 > /**
2434 > * A description for the overview ruler position.
2435 > */
2436 > export interface OverviewRulerPosition {
2437 > /**
2438 > * Width of the overview ruler
2439 > */
2440 > readonly width: number;
2441 > /**
2442 > * Height of the overview ruler
2443 > */
2444 > readonly height: number;
2445 > /**
2446 > * Top position for the overview ruler
2447 > */
2448 > readonly top: number;
2449 > /**
2450 > * Right position for the overview ruler
2451 > */
2452 > readonly right: number;
2453 > }
2454 >
2455 > export const enum RenderMinimap {
2456 > None = 0,
2457 > Text = 1,
2458 > Blocks = 2,
2459 > }
2460 >
2461 > /**
2462 > * The internal layout details of the editor.
2463 > */
2464 > export interface EditorLayoutInfo {
2465 >
2466 > /**
2467 > * Full editor width.
2468 > */
2469 > readonly width: number;
2470 > /**
2471 > * Full editor height.
2472 > */
2473 > readonly height: number;
2474 >
2475 > /**
2476 > * Left position for the glyph margin.
2477 > */
2478 > readonly glyphMarginLeft: number;
2479 > /**
2480 > * The width of the glyph margin.
2481 > */
2482 > readonly glyphMarginWidth: number;
2483 >
2484 > /**
2485 > * The number of decoration lanes to render in the glyph margin.
2486 > */
2487 > readonly glyphMarginDecorationLaneCount: number;
2488 >
2489 > /**
2490 > * Left position for the line numbers.
2491 > */
2492 > readonly lineNumbersLeft: number;
2493 > /**
2494 > * The width of the line numbers.
2495 > */
2496 > readonly lineNumbersWidth: number;
2497 >
2498 > /**
2499 > * Left position for the line decorations.
2500 > */
2501 > readonly decorationsLeft: number;
2502 > /**
2503 > * The width of the line decorations.
2504 > */
2505 > readonly decorationsWidth: number;
2506 >
2507 > /**
2508 > * Left position for the content (actual text)
2509 > */
2510 > readonly contentLeft: number;
2511 > /**
2512 > * The width of the content (actual text)
2513 > */
2514 > readonly contentWidth: number;
2515 >
2516 > /**
2517 > * Layout information for the minimap
2518 > */
2519 > readonly minimap: EditorMinimapLayoutInfo;
2520 >
2521 > /**
2522 > * The number of columns (of typical characters) fitting on a viewport line.
2523 > */
2524 > readonly viewportColumn: number;
2525 >
2526 > readonly isWordWrapMinified: boolean;
2527 > readonly isViewportWrapping: boolean;
2528 > readonly wrappingColumn: number;
2529 >
2530 > /**
2531 > * The width of the vertical scrollbar.
2532 > */
2533 > readonly verticalScrollbarWidth: number;
2534 > /**
2535 > * The height of the horizontal scrollbar.
2536 > */
2537 > readonly horizontalScrollbarHeight: number;
2538 >
2539 > /**
2540 > * The position of the overview ruler.
2541 > */
2542 > readonly overviewRuler: OverviewRulerPosition;
2543 > }
2544 >
2545 > /**
2546 > * The internal layout details of the editor.
2547 > */
2548 > export interface EditorMinimapLayoutInfo {
2549 > readonly renderMinimap: RenderMinimap;
2550 > readonly minimapLeft: number;
2551 > readonly minimapWidth: number;
2552 > readonly minimapHeightIsEditorHeight: boolean;
2553 > readonly minimapIsSampling: boolean;
2554 > readonly minimapScale: number;
2555 > readonly minimapLineHeight: number;
2556 > readonly minimapCanvasInnerWidth: number;
2557 > readonly minimapCanvasInnerHeight: number;
2558 > readonly minimapCanvasOuterWidth: number;
2559 > readonly minimapCanvasOuterHeight: number;
2560 > }
2561 >
2562 > /**
2563 > * @internal
2564 > */
2565 > export interface EditorLayoutInfoComputerEnv {
2566 > readonly memory: ComputeOptionsMemory | null;
2567 > readonly outerWidth: number;
2568 > readonly outerHeight: number;
2569 > readonly isDominatedByLongLines: boolean;
2570 > readonly lineHeight: number;
2571 > readonly viewLineCount: number;
2572 > readonly lineNumbersDigitCount: number;
2573 > readonly typicalHalfwidthCharacterWidth: number;
2574 > readonly maxDigitWidth: number;
2575 > readonly pixelRatio: number;
2576 > readonly glyphMarginDecorationLaneCount: number;
2577 > }
2578 >
2579 > /**
2580 > * @internal
2581 > */
2582 > export interface IEditorLayoutComputerInput {
2583 > readonly outerWidth: number;
2584 > readonly outerHeight: number;
2585 > readonly isDominatedByLongLines: boolean;
2586 > readonly lineHeight: number;
2587 > readonly lineNumbersDigitCount: number;
2588 > readonly typicalHalfwidthCharacterWidth: number;
2589 > readonly maxDigitWidth: number;
2590 > readonly pixelRatio: number;
2591 > readonly glyphMargin: boolean;
2592 > readonly lineDecorationsWidth: string | number;
2593 > readonly folding: boolean;
2594 > readonly minimap: Readonly<Required<IEditorMinimapOptions>>;
2595 > readonly scrollbar: InternalEditorScrollbarOptions;
2596 > readonly lineNumbers: InternalEditorRenderLineNumbersOptions;
2597 > readonly lineNumbersMinChars: number;
2598 > readonly scrollBeyondLastLine: boolean;
2599 > readonly wordWrap: 'wordWrapColumn' | 'on' | 'off' | 'bounded';
2600 > readonly wordWrapColumn: number;
2601 > readonly wordWrapMinified: boolean;
2602 > readonly accessibilitySupport: AccessibilitySupport;
2603 > }
2604 >
2605 > /**
2606 > * @internal
2607 > */
2608 > export interface IMinimapLayoutInput {
2609 > readonly outerWidth: number;
2610 > readonly outerHeight: number;
2611 > readonly lineHeight: number;
2612 > readonly typicalHalfwidthCharacterWidth: number;
2613 > readonly pixelRatio: number;
2614 > readonly scrollBeyondLastLine: boolean;
2615 > readonly paddingTop: number;
2616 > readonly paddingBottom: number;
2617 > readonly minimap: Readonly<Required<IEditorMinimapOptions>>;
2618 > readonly verticalScrollbarWidth: number;
2619 > readonly viewLineCount: number;
2620 > readonly remainingWidth: number;
2621 > readonly isViewportWrapping: boolean;
2622 > }
2623 >
2624 > /**
2625 > * @internal
2626 > */
2627 > export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.layoutInfo, EditorLayoutInfo> {
2628 >
2629 > constructor() {
2630 > super(EditorOption.layoutInfo, {
2631 > width: 0,
2632 > height: 0,
2633 > glyphMarginLeft: 0,
2634 > glyphMarginWidth: 0,
2635 > glyphMarginDecorationLaneCount: 0,
2636 > lineNumbersLeft: 0,
2637 > lineNumbersWidth: 0,
2638 > decorationsLeft: 0,
2639 > decorationsWidth: 0,
2640 > contentLeft: 0,
2641 > contentWidth: 0,
2642 > minimap: {
2643 > renderMinimap: RenderMinimap.None,
2644 > minimapLeft: 0,
2645 > minimapWidth: 0,
2646 > minimapHeightIsEditorHeight: false,
2647 > minimapIsSampling: false,
2648 > minimapScale: 1,
2649 > minimapLineHeight: 1,
2650 > minimapCanvasInnerWidth: 0,
2651 > minimapCanvasInnerHeight: 0,
2652 > minimapCanvasOuterWidth: 0,
2653 > minimapCanvasOuterHeight: 0,
2654 > },
2655 > viewportColumn: 0,
2656 > isWordWrapMinified: false,
2657 > isViewportWrapping: false,
2658 > wrappingColumn: -1,
2659 > verticalScrollbarWidth: 0,
2660 > horizontalScrollbarHeight: 0,
2661 > overviewRuler: {
2662 > top: 0,
2663 > width: 0,
2664 > height: 0,
2665 > right: 0
2666 > }
2667 > });
2668 > }
2669 >
2670 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorLayoutInfo): EditorLayoutInfo {
2671 return EditorLayoutInfoComputer.computeLayout(options, {
2672 memory: env.memory,
2683 });
2684 }
2686 > public static computeContainedMinimapLineCount(input: {
2687 viewLineCount: number;
2688 scrollBeyondLastLine: boolean;
2703 return { typicalViewportLineCount, extraLinesBeforeFirstLine, extraLinesBeyondLastLine, desiredRatio, minimapLineCount };
2704 }
2706 > private static _computeMinimapLayout(input: IMinimapLayoutInput, memory: ComputeOptionsMemory): EditorMinimapLayoutInfo {
2707 const outerWidth = input.outerWidth;
2708 const outerHeight = input.outerHeight;
2879 };
2880 }
2882 > public static computeLayout(options: IComputedEditorOptions, env: EditorLayoutInfoComputerEnv): EditorLayoutInfo {
2883 const outerWidth = env.outerWidth | 0;
2884 const outerHeight = env.outerHeight | 0;
3024 };
3025 }
3026 > } editorOptions.ts
3027 >
3028 > //#endregion
3029 >
3030 > //#region WrappingStrategy
3031 > class WrappingStrategy extends BaseEditorOption<EditorOption.wrappingStrategy, 'simple' | 'advanced', 'simple' | 'advanced'> {
3032 >
3033 > constructor() {
3034 > super(EditorOption.wrappingStrategy, 'wrappingStrategy', 'simple',
3035 > {
3036 > 'editor.wrappingStrategy': {
3037 > enumDescriptions: [
3038 > nls.localize('wrappingStrategy.simple', "Assumes that all characters are of the same width. This is a fast algorithm that works correctly for monospace fonts and certain scripts (like Latin characters) where glyphs are of equal width."),
3039 > nls.localize('wrappingStrategy.advanced', "Delegates wrapping points computation to the browser. This is a slow algorithm, that might cause freezes for large files, but it works correctly in all cases.")
3040 > ],
3041 > type: 'string',
3042 > enum: ['simple', 'advanced'],
3043 > default: 'simple',
3044 > description: nls.localize('wrappingStrategy', "Controls the algorithm that computes wrapping points. Note that when in accessibility mode, advanced will be used for the best experience.")
3045 > }
3046 > }
3047 > );
3048 > }
3049 >
3050 > public validate(input: unknown): 'simple' | 'advanced' {
3051 return stringSet<'simple' | 'advanced'>(input, 'simple', ['simple', 'advanced']);
3052 }
3054 > public override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: 'simple' | 'advanced'): 'simple' | 'advanced' {
3055 const accessibilitySupport = options.get(EditorOption.accessibilitySupport);
3056 if (accessibilitySupport === AccessibilitySupport.Enabled) {
3061 return value;
3062 }
3063 > } editorOptions.ts
3064 > //#endregion
3065 >
3066 > //#region lightbulb
3067 >
3068 > export enum ShowLightbulbIconMode {
3069 > Off = 'off',
3070 > OnCode = 'onCode',
3071 > On = 'on'
3072 > }
3073 >
3074 > /**
3075 > * Configuration options for editor lightbulb
3076 > */
3077 > export interface IEditorLightbulbOptions {
3078 > /**
3079 > * Enable the lightbulb code action.
3080 > * The three possible values are `off`, `on` and `onCode` and the default is `onCode`.
3081 > * `off` disables the code action menu.
3082 > * `on` shows the code action menu on code and on empty lines.
3083 > * `onCode` shows the code action menu on code only.
3084 > */
3085 > enabled?: ShowLightbulbIconMode;
3086 > }
3087 >
3088 > /**
3089 > * @internal
3090 > */
3091 > export type EditorLightbulbOptions = Readonly<Required<IEditorLightbulbOptions>>;
3092 >
3093 > class EditorLightbulb extends BaseEditorOption<EditorOption.lightbulb, IEditorLightbulbOptions, EditorLightbulbOptions> {
3094 >
3095 > constructor() {
3096 > const defaults: EditorLightbulbOptions = { enabled: ShowLightbulbIconMode.OnCode };
3097 > super(
3098 > EditorOption.lightbulb, 'lightbulb', defaults,
3099 > {
3100 > 'editor.lightbulb.enabled': {
3101 > type: 'string',
3102 > enum: [ShowLightbulbIconMode.Off, ShowLightbulbIconMode.OnCode, ShowLightbulbIconMode.On],
3103 > default: defaults.enabled,
3104 > enumDescriptions: [
3105 > nls.localize('editor.lightbulb.enabled.off', 'Disable the code action menu.'),
3106 > nls.localize('editor.lightbulb.enabled.onCode', 'Show the code action menu when the cursor is on lines with code.'),
3107 > nls.localize('editor.lightbulb.enabled.on', 'Show the code action menu when the cursor is on lines with code or on empty lines.'),
3108 > ],
3109 > description: nls.localize('enabled', "Enables the Code Action lightbulb in the editor.")
3110 > }
3111 > }
3112 > );
3113 > }
3114 >
3115 > public validate(_input: unknown): EditorLightbulbOptions {
3116 if (!_input || typeof _input !== 'object') {
3117 return this.defaultValue;
3122 };
3123 }
3124 > } editorOptions.ts
3125 >
3126 > //#endregion
3127 >
3128 > //#region stickyScroll
3129 >
3130 > export interface IEditorStickyScrollOptions {
3131 > /**
3132 > * Enable the sticky scroll
3133 > */
3134 > enabled?: boolean;
3135 > /**
3136 > * Maximum number of sticky lines to show
3137 > */
3138 > maxLineCount?: number;
3139 > /**
3140 > * Model to choose for sticky scroll by default
3141 > */
3142 > defaultModel?: 'outlineModel' | 'foldingProviderModel' | 'indentationModel';
3143 > /**
3144 > * Define whether to scroll sticky scroll with editor horizontal scrollbae
3145 > */
3146 > scrollWithEditor?: boolean;
3147 > }
3148 >
3149 > /**
3150 > * @internal
3151 > */
3152 > export type EditorStickyScrollOptions = Readonly<Required<IEditorStickyScrollOptions>>;
3153 >
3154 > class EditorStickyScroll extends BaseEditorOption<EditorOption.stickyScroll, IEditorStickyScrollOptions, EditorStickyScrollOptions> {
3155 >
3156 > constructor() {
3157 > const defaults: EditorStickyScrollOptions = { enabled: true, maxLineCount: 5, defaultModel: 'outlineModel', scrollWithEditor: true };
3158 > super(
3159 > EditorOption.stickyScroll, 'stickyScroll', defaults,
3160 > {
3161 > 'editor.stickyScroll.enabled': {
3162 > type: 'boolean',
3163 > default: defaults.enabled,
3164 > description: nls.localize('editor.stickyScroll.enabled', "Shows the nested current scopes during the scroll at the top of the editor.")
3165 > },
3166 > 'editor.stickyScroll.maxLineCount': {
3167 > type: 'number',
3168 > default: defaults.maxLineCount,
3169 > minimum: 1,
3170 > maximum: 20,
3171 > description: nls.localize('editor.stickyScroll.maxLineCount', "Defines the maximum number of sticky lines to show.")
3172 > },
3173 > 'editor.stickyScroll.defaultModel': {
3174 > type: 'string',
3175 > enum: ['outlineModel', 'foldingProviderModel', 'indentationModel'],
3176 > default: defaults.defaultModel,
3177 > description: nls.localize('editor.stickyScroll.defaultModel', "Defines the model to use for determining which lines to stick. If the outline model does not exist, it will fall back on the folding provider model which falls back on the indentation model. This order is respected in all three cases.")
3178 > },
3179 > 'editor.stickyScroll.scrollWithEditor': {
3180 > type: 'boolean',
3181 > default: defaults.scrollWithEditor,
3182 > description: nls.localize('editor.stickyScroll.scrollWithEditor', "Enable scrolling of Sticky Scroll with the editor's horizontal scrollbar.")
3183 > },
3184 > }
3185 > );
3186 > }
3187 >
3188 > public validate(_input: unknown): EditorStickyScrollOptions {
3189 if (!_input || typeof _input !== 'object') {
3190 return this.defaultValue;
3198 };
3199 }
3200 > } editorOptions.ts
3201 >
3202 > //#endregion
3203 >
3204 > //#region inlayHints
3205 >
3206 > /**
3207 > * Configuration options for editor inlayHints
3208 > */
3209 > export interface IEditorInlayHintsOptions {
3210 > /**
3211 > * Enable the inline hints.
3212 > * Defaults to true.
3213 > */
3214 > enabled?: 'on' | 'off' | 'offUnlessPressed' | 'onUnlessPressed';
3215 >
3216 > /**
3217 > * Font size of inline hints.
3218 > * Default to 90% of the editor font size.
3219 > */
3220 > fontSize?: number;
3221 >
3222 > /**
3223 > * Font family of inline hints.
3224 > * Defaults to editor font family.
3225 > */
3226 > fontFamily?: string;
3227 >
3228 > /**
3229 > * Enables the padding around the inlay hint.
3230 > * Defaults to false.
3231 > */
3232 > padding?: boolean;
3233 >
3234 > /**
3235 > * Maximum length for inlay hints per line
3236 > * Set to 0 to have an unlimited length.
3237 > */
3238 > maximumLength?: number;
3239 > }
3240 >
3241 > /**
3242 > * @internal
3243 > */
3244 > export type EditorInlayHintsOptions = Readonly<Required<IEditorInlayHintsOptions>>;
3245 >
3246 > class EditorInlayHints extends BaseEditorOption<EditorOption.inlayHints, IEditorInlayHintsOptions, EditorInlayHintsOptions> {
3247 >
3248 > constructor() {
3249 > const defaults: EditorInlayHintsOptions = { enabled: 'on', fontSize: 0, fontFamily: '', padding: false, maximumLength: 43 };
3250 > super(
3251 > EditorOption.inlayHints, 'inlayHints', defaults,
3252 > {
3253 > 'editor.inlayHints.enabled': {
3254 > type: 'string',
3255 > default: defaults.enabled,
3256 > description: nls.localize('inlayHints.enable', "Enables the inlay hints in the editor."),
3257 > enum: ['on', 'onUnlessPressed', 'offUnlessPressed', 'off'],
3258 > markdownEnumDescriptions: [
3259 > nls.localize('editor.inlayHints.on', "Inlay hints are enabled"),
3260 > nls.localize('editor.inlayHints.onUnlessPressed', "Inlay hints are showing by default and hide when holding {0}", platform.isMacintosh ? `Ctrl+Option` : `Ctrl+Alt`),
3261 > nls.localize('editor.inlayHints.offUnlessPressed', "Inlay hints are hidden by default and show when holding {0}", platform.isMacintosh ? `Ctrl+Option` : `Ctrl+Alt`),
3262 > nls.localize('editor.inlayHints.off', "Inlay hints are disabled"),
3263 > ],
3264 > },
3265 > 'editor.inlayHints.fontSize': {
3266 > type: 'number',
3267 > default: defaults.fontSize,
3268 > markdownDescription: nls.localize('inlayHints.fontSize', "Controls font size of inlay hints in the editor. As default the {0} is used when the configured value is less than {1} or greater than the editor font size.", '`#editor.fontSize#`', '`5`')
3269 > },
3270 > 'editor.inlayHints.fontFamily': {
3271 > type: 'string',
3272 > default: defaults.fontFamily,
3273 > markdownDescription: nls.localize('inlayHints.fontFamily', "Controls font family of inlay hints in the editor. When set to empty, the {0} is used.", '`#editor.fontFamily#`')
3274 > },
3275 > 'editor.inlayHints.padding': {
3276 > type: 'boolean',
3277 > default: defaults.padding,
3278 > description: nls.localize('inlayHints.padding', "Enables the padding around the inlay hints in the editor.")
3279 > },
3280 > 'editor.inlayHints.maximumLength': {
3281 > type: 'number',
3282 > default: defaults.maximumLength,
3283 > markdownDescription: nls.localize('inlayHints.maximumLength', "Maximum overall length of inlay hints, for a single line, before they get truncated by the editor. Set to `0` to never truncate")
3284 > }
3285 > }
3286 > );
3287 > }
3288 >
3289 > public validate(_input: unknown): EditorInlayHintsOptions {
3290 if (!_input || typeof _input !== 'object') {
3291 return this.defaultValue;
3303 };
3304 }
3305 > } editorOptions.ts
3306 >
3307 > //#endregion
3308 >
3309 > //#region lineDecorationsWidth
3310 >
3311 > class EditorLineDecorationsWidth extends BaseEditorOption<EditorOption.lineDecorationsWidth, number | string, number> {
3312 >
3313 > constructor() {
3314 > super(EditorOption.lineDecorationsWidth, 'lineDecorationsWidth', 10);
3315 > }
3316 >
3317 > public validate(input: unknown): number {
3318 if (typeof input === 'string' && /^\d+(\.\d+)?ch$/.test(input)) {
3319 const multiple = parseFloat(input.substring(0, input.length - 2));
3323 }
3324 }
3326 > public override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number {
3327 if (value < 0) {
3328 // negative numbers signal a multiple
3332 }
3333 }
3334 > } editorOptions.ts
3335 >
3336 > //#endregion
3337 >
3338 > //#region lineHeight
3339 >
3340 > class EditorLineHeight extends EditorFloatOption<EditorOption.lineHeight> {
3341 >
3342 > constructor() {
3343 > super(
3344 > EditorOption.lineHeight, 'lineHeight',
3345 > EDITOR_FONT_DEFAULTS.lineHeight,
3346 > x => EditorFloatOption.clamp(x, 0, 150),
3347 > { markdownDescription: nls.localize('lineHeight', "Controls the line height. \n - Use 0 to automatically compute the line height from the font size.\n - Values between 0 and 8 will be used as a multiplier with the font size.\n - Values greater than or equal to 8 will be used as effective values.") },
3348 > 0,
3349 > 150
3350 > );
3351 > }
3352 >
3353 > public override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number {
3354 // The lineHeight is computed from the fontSize if it is 0.
3355 // Moreover, the final lineHeight respects the editor zoom level.
3357 return env.fontInfo.lineHeight;
3358 }
3359 > } editorOptions.ts
3360 >
3361 > //#endregion
3362 >
3363 > //#region minimap
3364 >
3365 > /**
3366 > * Configuration options for editor minimap
3367 > */
3368 > export interface IEditorMinimapOptions {
3369 > /**
3370 > * Enable the rendering of the minimap.
3371 > * Defaults to true.
3372 > */
3373 > enabled?: boolean;
3374 > /**
3375 > * Control the rendering of minimap.
3376 > */
3377 > autohide?: 'none' | 'mouseover' | 'scroll';
3378 > /**
3379 > * Control the side of the minimap in editor.
3380 > * Defaults to 'right'.
3381 > */
3382 > side?: 'right' | 'left';
3383 > /**
3384 > * Control the minimap rendering mode.
3385 > * Defaults to 'actual'.
3386 > */
3387 > size?: 'proportional' | 'fill' | 'fit';
3388 > /**
3389 > * Control the rendering of the minimap slider.
3390 > * Defaults to 'mouseover'.
3391 > */
3392 > showSlider?: 'always' | 'mouseover';
3393 > /**
3394 > * Render the actual text on a line (as opposed to color blocks).
3395 > * Defaults to true.
3396 > */
3397 > renderCharacters?: boolean;
3398 > /**
3399 > * Limit the width of the minimap to render at most a certain number of columns.
3400 > * Defaults to 120.
3401 > */
3402 > maxColumn?: number;
3403 > /**
3404 > * Relative size of the font in the minimap. Defaults to 1.
3405 > */
3406 > scale?: number;
3407 > /**
3408 > * Whether to show named regions as section headers. Defaults to true.
3409 > */
3410 > showRegionSectionHeaders?: boolean;
3411 > /**
3412 > * Whether to show MARK: comments as section headers. Defaults to true.
3413 > */
3414 > showMarkSectionHeaders?: boolean;
3415 > /**
3416 > * When specified, is used to create a custom section header parser regexp.
3417 > * Must contain a match group named 'label' (written as (?<label>.+)) that encapsulates the section header.
3418 > * Optionally can include another match group named 'separator'.
3419 > * To match multi-line headers like:
3420 > * // ==========
3421 > * // My Section
3422 > * // ==========
3423 > * Use a pattern like: ^={3,}\n^\/\/ *(?<label>[^\n]*?)\n^={3,}$
3424 > */
3425 > markSectionHeaderRegex?: string;
3426 > /**
3427 > * Font size of section headers. Defaults to 9.
3428 > */
3429 > sectionHeaderFontSize?: number;
3430 > /**
3431 > * Spacing between the section header characters (in CSS px). Defaults to 1.
3432 > */
3433 > sectionHeaderLetterSpacing?: number;
3434 > }
3435 >
3436 > /**
3437 > * @internal
3438 > */
3439 > export type EditorMinimapOptions = Readonly<Required<IEditorMinimapOptions>>;
3440 >
3441 > class EditorMinimap extends BaseEditorOption<EditorOption.minimap, IEditorMinimapOptions, EditorMinimapOptions> {
3442 >
3443 > constructor() {
3444 > const defaults: EditorMinimapOptions = {
3445 > enabled: true,
3446 > size: 'proportional',
3447 > side: 'right',
3448 > showSlider: 'mouseover',
3449 > autohide: 'none',
3450 > renderCharacters: true,
3451 > maxColumn: 120,
3452 > scale: 1,
3453 > showRegionSectionHeaders: true,
3454 > showMarkSectionHeaders: true,
3455 > markSectionHeaderRegex: '\\bMARK:\\s*(?<separator>\-?)\\s*(?<label>.*)$',
3456 > sectionHeaderFontSize: 9,
3457 > sectionHeaderLetterSpacing: 1,
3458 > };
3459 > super(
3460 > EditorOption.minimap, 'minimap', defaults,
3461 > {
3462 > 'editor.minimap.enabled': {
3463 > type: 'boolean',
3464 > default: defaults.enabled,
3465 > description: nls.localize('minimap.enabled', "Controls whether the minimap is shown.")
3466 > },
3467 > 'editor.minimap.autohide': {
3468 > type: 'string',
3469 > enum: ['none', 'mouseover', 'scroll'],
3470 > enumDescriptions: [
3471 > nls.localize('minimap.autohide.none', "The minimap is always shown."),
3472 > nls.localize('minimap.autohide.mouseover', "The minimap is hidden when mouse is not over the minimap and shown when mouse is over the minimap."),
3473 > nls.localize('minimap.autohide.scroll', "The minimap is only shown when the editor is scrolled"),
3474 > ],
3475 > default: defaults.autohide,
3476 > description: nls.localize('minimap.autohide', "Controls whether the minimap is hidden automatically.")
3477 > },
3478 > 'editor.minimap.size': {
3479 > type: 'string',
3480 > enum: ['proportional', 'fill', 'fit'],
3481 > enumDescriptions: [
3482 > nls.localize('minimap.size.proportional', "The minimap has the same size as the editor contents (and might scroll)."),
3483 > nls.localize('minimap.size.fill', "The minimap will stretch or shrink as necessary to fill the height of the editor (no scrolling)."),
3484 > nls.localize('minimap.size.fit', "The minimap will shrink as necessary to never be larger than the editor (no scrolling)."),
3485 > ],
3486 > default: defaults.size,
3487 > description: nls.localize('minimap.size', "Controls the size of the minimap.")
3488 > },
3489 > 'editor.minimap.side': {
3490 > type: 'string',
3491 > enum: ['left', 'right'],
3492 > default: defaults.side,
3493 > description: nls.localize('minimap.side', "Controls the side where to render the minimap.")
3494 > },
3495 > 'editor.minimap.showSlider': {
3496 > type: 'string',
3497 > enum: ['always', 'mouseover'],
3498 > default: defaults.showSlider,
3499 > description: nls.localize('minimap.showSlider', "Controls when the minimap slider is shown.")
3500 > },
3501 > 'editor.minimap.scale': {
3502 > type: 'number',
3503 > default: defaults.scale,
3504 > minimum: 1,
3505 > maximum: 3,
3506 > enum: [1, 2, 3],
3507 > description: nls.localize('minimap.scale', "Scale of content drawn in the minimap: 1, 2 or 3.")
3508 > },
3509 > 'editor.minimap.renderCharacters': {
3510 > type: 'boolean',
3511 > default: defaults.renderCharacters,
3512 > description: nls.localize('minimap.renderCharacters', "Render the actual characters on a line as opposed to color blocks.")
3513 > },
3514 > 'editor.minimap.maxColumn': {
3515 > type: 'number',
3516 > default: defaults.maxColumn,
3517 > description: nls.localize('minimap.maxColumn', "Limit the width of the minimap to render at most a certain number of columns.")
3518 > },
3519 > 'editor.minimap.showRegionSectionHeaders': {
3520 > type: 'boolean',
3521 > default: defaults.showRegionSectionHeaders,
3522 > description: nls.localize('minimap.showRegionSectionHeaders', "Controls whether named regions are shown as section headers in the minimap.")
3523 > },
3524 > 'editor.minimap.showMarkSectionHeaders': {
3525 > type: 'boolean',
3526 > default: defaults.showMarkSectionHeaders,
3527 > description: nls.localize('minimap.showMarkSectionHeaders', "Controls whether MARK: comments are shown as section headers in the minimap.")
3528 > },
3529 > 'editor.minimap.markSectionHeaderRegex': {
3530 > type: 'string',
3531 > default: defaults.markSectionHeaderRegex,
3532 > description: nls.localize('minimap.markSectionHeaderRegex', "Defines the regular expression used to find section headers in comments. The regex must contain a named match group `label` (written as `(?<label>.+)`) that encapsulates the section header, otherwise it will not work. Optionally you can include another match group named `separator`. Use \\n in the pattern to match multi-line headers."),
3533 > },
3534 > 'editor.minimap.sectionHeaderFontSize': {
3535 > type: 'number',
3536 > default: defaults.sectionHeaderFontSize,
3537 > description: nls.localize('minimap.sectionHeaderFontSize', "Controls the font size of section headers in the minimap.")
3538 > },
3539 > 'editor.minimap.sectionHeaderLetterSpacing': {
3540 > type: 'number',
3541 > default: defaults.sectionHeaderLetterSpacing,
3542 > description: nls.localize('minimap.sectionHeaderLetterSpacing', "Controls the amount of space (in pixels) between characters of section header. This helps the readability of the header in small font sizes.")
3543 > }
3544 > }
3545 > );
3546 > }
3547 >
3548 > public validate(_input: unknown): EditorMinimapOptions {
3549 if (!_input || typeof _input !== 'object') {
3550 return this.defaultValue;
3578 };
3579 }
3580 > } editorOptions.ts
3581 >
3582 > //#endregion
3583 >
3584 > //#region multiCursorModifier
3585 >
3586 function _multiCursorModifierFromString(multiCursorModifier: 'ctrlCmd' | 'alt'): 'altKey' | 'metaKey' | 'ctrlKey' {
3587 if (multiCursorModifier === 'ctrlCmd') {
3590 return 'altKey';
3591 }
3593 > //#endregion
3594 >
3595 > //#region padding
3596 >
3597 > /**
3598 > * Configuration options for editor padding
3599 > */
3600 > export interface IEditorPaddingOptions {
3601 > /**
3602 > * Spacing between top edge of editor and first line.
3603 > */
3604 > top?: number;
3605 > /**
3606 > * Spacing between bottom edge of editor and last line.
3607 > */
3608 > bottom?: number;
3609 > }
3610 >
3611 > /**
3612 > * @internal
3613 > */
3614 > export type InternalEditorPaddingOptions = Readonly<Required<IEditorPaddingOptions>>;
3615 >
3616 > class EditorPadding extends BaseEditorOption<EditorOption.padding, IEditorPaddingOptions, InternalEditorPaddingOptions> {
3617 >
3618 > constructor() {
3619 > super(
3620 > EditorOption.padding, 'padding', { top: 0, bottom: 0 },
3621 > {
3622 > 'editor.padding.top': {
3623 > type: 'number',
3624 > default: 0,
3625 > minimum: 0,
3626 > maximum: 1000,
3627 > description: nls.localize('padding.top', "Controls the amount of space between the top edge of the editor and the first line.")
3628 > },
3629 > 'editor.padding.bottom': {
3630 > type: 'number',
3631 > default: 0,
3632 > minimum: 0,
3633 > maximum: 1000,
3634 > description: nls.localize('padding.bottom', "Controls the amount of space between the bottom edge of the editor and the last line.")
3635 > }
3636 > }
3637 > );
3638 > }
3639 >
3640 > public validate(_input: unknown): InternalEditorPaddingOptions {
3641 if (!_input || typeof _input !== 'object') {
3642 return this.defaultValue;
3649 };
3650 }
3651 > } editorOptions.ts
3652 > //#endregion
3653 >
3654 > //#region parameterHints
3655 >
3656 > /**
3657 > * Configuration options for parameter hints
3658 > */
3659 > export interface IEditorParameterHintOptions {
3660 > /**
3661 > * Enable parameter hints.
3662 > * Defaults to true.
3663 > */
3664 > enabled?: boolean;
3665 > /**
3666 > * Enable cycling of parameter hints.
3667 > * Defaults to false.
3668 > */
3669 > cycle?: boolean;
3670 > }
3671 >
3672 > /**
3673 > * @internal
3674 > */
3675 > export type InternalParameterHintOptions = Readonly<Required<IEditorParameterHintOptions>>;
3676 >
3677 > class EditorParameterHints extends BaseEditorOption<EditorOption.parameterHints, IEditorParameterHintOptions, InternalParameterHintOptions> {
3678 >
3679 > constructor() {
3680 > const defaults: InternalParameterHintOptions = {
3681 > enabled: true,
3682 > cycle: true
3683 > };
3684 > super(
3685 > EditorOption.parameterHints, 'parameterHints', defaults,
3686 > {
3687 > 'editor.parameterHints.enabled': {
3688 > type: 'boolean',
3689 > default: defaults.enabled,
3690 > description: nls.localize('parameterHints.enabled', "Enables a pop-up that shows parameter documentation and type information as you type.")
3691 > },
3692 > 'editor.parameterHints.cycle': {
3693 > type: 'boolean',
3694 > default: defaults.cycle,
3695 > description: nls.localize('parameterHints.cycle', "Controls whether the parameter hints menu cycles or closes when reaching the end of the list.")
3696 > },
3697 > }
3698 > );
3699 > }
3700 >
3701 > public validate(_input: unknown): InternalParameterHintOptions {
3702 if (!_input || typeof _input !== 'object') {
3703 return this.defaultValue;
3709 };
3710 }
3711 > } editorOptions.ts
3712 >
3713 > //#endregion
3714 >
3715 > //#region pixelRatio
3716 >
3717 > class EditorPixelRatio extends ComputedEditorOption<EditorOption.pixelRatio, number> {
3718 >
3719 > constructor() {
3720 > super(EditorOption.pixelRatio, 1);
3721 > }
3722 >
3723 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: number): number {
3724 return env.pixelRatio;
3725 }
3726 > } editorOptions.ts
3727 >
3728 > //#endregion
3729 >
3730 > //#region
3731 >
3732 > class PlaceholderOption extends BaseEditorOption<EditorOption.placeholder, string | undefined, string | undefined> {
3733 > constructor() {
3734 > super(EditorOption.placeholder, 'placeholder', undefined);
3735 > }
3736 >
3737 > public validate(input: unknown): string | undefined {
3738 if (typeof input === 'undefined') {
3739 return this.defaultValue;
3744 return this.defaultValue;
3745 }
3746 > } editorOptions.ts
3747 > //#endregion
3748 >
3749 > //#region quickSuggestions
3750 >
3751 > export type QuickSuggestionsValue = 'on' | 'inline' | 'off' | 'offWhenInlineCompletions';
3752 >
3753 > /**
3754 > * Configuration options for quick suggestions
3755 > */
3756 > export interface IQuickSuggestionsOptions {
3757 > other?: boolean | QuickSuggestionsValue;
3758 > comments?: boolean | QuickSuggestionsValue;
3759 > strings?: boolean | QuickSuggestionsValue;
3760 > }
3761 >
3762 > export interface InternalQuickSuggestionsOptions {
3763 > readonly other: QuickSuggestionsValue;
3764 > readonly comments: QuickSuggestionsValue;
3765 > readonly strings: QuickSuggestionsValue;
3766 > }
3767 >
3768 > class EditorQuickSuggestions extends BaseEditorOption<EditorOption.quickSuggestions, boolean | QuickSuggestionsValue | IQuickSuggestionsOptions, InternalQuickSuggestionsOptions> {
3769 >
3770 > public override readonly defaultValue: InternalQuickSuggestionsOptions;
3771 >
3772 > constructor() {
3773 > const defaults: InternalQuickSuggestionsOptions = {
3774 > other: 'offWhenInlineCompletions',
3775 > comments: 'off',
3776 > strings: 'off'
3777 > };
3778 > const types: IJSONSchema[] = [
3779 > { type: 'boolean' },
3780 > {
3781 > type: 'string',
3782 > enum: ['on', 'inline', 'off', 'offWhenInlineCompletions'],
3783 > enumDescriptions: [nls.localize('on', "Quick suggestions show inside the suggest widget"), nls.localize('inline', "Quick suggestions show as ghost text"), nls.localize('off', "Quick suggestions are disabled"), nls.localize('offWhenInlineCompletions', "Quick suggestions are disabled when inline completions are showing")]
3784 > }
3785 > ];
3786 > super(EditorOption.quickSuggestions, 'quickSuggestions', defaults, {
3787 > anyOf: [
3788 > { type: 'boolean' },
3789 > {
3790 > type: 'string',
3791 > enum: ['on', 'inline', 'off', 'offWhenInlineCompletions'],
3792 > enumDescriptions: [nls.localize('quickSuggestions.topLevel.on', "Quick suggestions are enabled for all token types"), nls.localize('quickSuggestions.topLevel.inline', "Quick suggestions show as ghost text for all token types"), nls.localize('quickSuggestions.topLevel.off', "Quick suggestions are disabled for all token types"), nls.localize('quickSuggestions.topLevel.offWhenInlineCompletions', "Quick suggestions are disabled for all token types when inline completions are showing")]
3793 > },
3794 > {
3795 > type: 'object',
3796 > additionalProperties: false,
3797 > properties: {
3798 > strings: {
3799 > anyOf: types,
3800 > default: defaults.strings,
3801 > description: nls.localize('quickSuggestions.strings', "Enable quick suggestions inside strings.")
3802 > },
3803 > comments: {
3804 > anyOf: types,
3805 > default: defaults.comments,
3806 > description: nls.localize('quickSuggestions.comments', "Enable quick suggestions inside comments.")
3807 > },
3808 > other: {
3809 > anyOf: types,
3810 > default: defaults.other,
3811 > description: nls.localize('quickSuggestions.other', "Enable quick suggestions outside of strings and comments.")
3812 > },
3813 > },
3814 > }
3815 > ],
3816 > default: defaults,
3817 > markdownDescription: nls.localize('quickSuggestions', "Controls whether suggestions should automatically show up while typing. This can be controlled for typing in comments, strings, and other code. Quick suggestion can be configured to show as ghost text or with the suggest widget. Also be aware of the {0}-setting which controls if suggestions are triggered by special characters.", '`#editor.suggestOnTriggerCharacters#`'),
3818 > experiment: {
3819 > mode: 'auto'
3820 > }
3821 > });
3822 > this.defaultValue = defaults;
3823 > }
3824 >
3825 > public validate(input: unknown): InternalQuickSuggestionsOptions {
3826 if (typeof input === 'boolean') {
3827 // boolean -> all on/off
3867 };
3868 }
3869 > } editorOptions.ts
3870 >
3871 > //#endregion
3872 >
3873 > //#region renderLineNumbers
3874 >
3875 > export type LineNumbersType = 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string);
3876 >
3877 > export const enum RenderLineNumbersType {
3878 > Off = 0,
3879 > On = 1,
3880 > Relative = 2,
3881 > Interval = 3,
3882 > Custom = 4
3883 > }
3884 >
3885 > export interface InternalEditorRenderLineNumbersOptions {
3886 > readonly renderType: RenderLineNumbersType;
3887 > readonly renderFn: ((lineNumber: number) => string) | null;
3888 > }
3889 >
3890 > class EditorRenderLineNumbersOption extends BaseEditorOption<EditorOption.lineNumbers, LineNumbersType, InternalEditorRenderLineNumbersOptions> {
3891 >
3892 > constructor() {
3893 > super(
3894 > EditorOption.lineNumbers, 'lineNumbers', { renderType: RenderLineNumbersType.On, renderFn: null },
3895 > {
3896 > type: 'string',
3897 > enum: ['off', 'on', 'relative', 'interval'],
3898 > enumDescriptions: [
3899 > nls.localize('lineNumbers.off', "Line numbers are not rendered."),
3900 > nls.localize('lineNumbers.on', "Line numbers are rendered as absolute number."),
3901 > nls.localize('lineNumbers.relative', "Line numbers are rendered as distance in lines to cursor position."),
3902 > nls.localize('lineNumbers.interval', "Line numbers are rendered every 10 lines.")
3903 > ],
3904 > default: 'on',
3905 > description: nls.localize('lineNumbers', "Controls the display of line numbers.")
3906 > }
3907 > );
3908 > }
3909 >
3910 > public validate(lineNumbers: unknown): InternalEditorRenderLineNumbersOptions {
3911 let renderType: RenderLineNumbersType = this.defaultValue.renderType;
3912 let renderFn: ((lineNumber: number) => string) | null = this.defaultValue.renderFn;
3932 };
3933 }
3934 > } editorOptions.ts
3935 >
3936 > //#endregion
3937 >
3938 > //#region renderValidationDecorations
3939 >
3940 > /**
3941 > * @internal
3942 > */
3943 > export function filterValidationDecorations(options: IComputedEditorOptions): boolean {
3944 const renderValidationDecorations = options.get(EditorOption.renderValidationDecorations);
3945 if (renderValidationDecorations === 'editable') {
3948 return renderValidationDecorations === 'on' ? false : true;
3949 }
3951 > //#endregion
3952 >
3953 > //#region filterFontDecorations
3954 >
3955 > /**
3956 > * @internal
3957 > */
3958 > export function filterFontDecorations(options: IComputedEditorOptions): boolean {
3959 return !options.get(EditorOption.effectiveAllowVariableFonts);
3960 }
3962 > //#endregion
3963 >
3964 > //#region rulers
3965 >
3966 > export interface IRulerOption {
3967 > readonly column: number;
3968 > readonly color: string | null;
3969 > }
3970 >
3971 > class EditorRulers extends BaseEditorOption<EditorOption.rulers, (number | IRulerOption)[], IRulerOption[]> {
3972 >
3973 > constructor() {
3974 > const defaults: IRulerOption[] = [];
3975 > const columnSchema: IJSONSchema = { type: 'number', description: nls.localize('rulers.size', "Number of monospace characters at which this editor ruler will render.") };
3976 > super(
3977 > EditorOption.rulers, 'rulers', defaults,
3978 > {
3979 > type: 'array',
3980 > items: {
3981 > anyOf: [
3982 > columnSchema,
3983 > {
3984 > type: [
3985 > 'object'
3986 > ],
3987 > properties: {
3988 > column: columnSchema,
3989 > color: {
3990 > type: 'string',
3991 > description: nls.localize('rulers.color', "Color of this editor ruler."),
3992 > format: 'color-hex'
3993 > }
3994 > }
3995 > }
3996 > ]
3997 > },
3998 > default: defaults,
3999 > description: nls.localize('rulers', "Render vertical rulers after a certain number of monospace characters. Use multiple values for multiple rulers. No rulers are drawn if array is empty.")
4000 > }
4001 > );
4002 > }
4003 >
4004 > public validate(input: unknown): IRulerOption[] {
4005 if (Array.isArray(input)) {
4006 const rulers: IRulerOption[] = [];
4024 return this.defaultValue;
4025 }
4026 > } editorOptions.ts
4027 >
4028 > //#endregion
4029 >
4030 > //#region readonly
4031 >
4032 > /**
4033 > * Configuration options for readonly message
4034 > */
4035 > class ReadonlyMessage extends BaseEditorOption<EditorOption.readOnlyMessage, IMarkdownString | undefined, IMarkdownString | undefined> {
4036 > constructor() {
4037 > const defaults = undefined;
4038 >
4039 > super(
4040 > EditorOption.readOnlyMessage, 'readOnlyMessage', defaults
4041 > );
4042 > }
4043 >
4044 > public validate(_input: unknown): IMarkdownString | undefined {
4045 if (!_input || typeof _input !== 'object') {
4046 return this.defaultValue;
4048 return _input as IMarkdownString;
4049 }
4050 > } editorOptions.ts
4051 >
4052 > //#endregion
4053 >
4054 > //#region scrollbar
4055 >
4056 > /**
4057 > * Configuration options for editor scrollbars
4058 > */
4059 > export interface IEditorScrollbarOptions {
4060 > /**
4061 > * The size of arrows (if displayed).
4062 > * Defaults to 11.
4063 > * **NOTE**: This option cannot be updated using `updateOptions()`
4064 > */
4065 > arrowSize?: number;
4066 > /**
4067 > * Render vertical scrollbar.
4068 > * Defaults to 'auto'.
4069 > */
4070 > vertical?: 'auto' | 'visible' | 'hidden';
4071 > /**
4072 > * Render horizontal scrollbar.
4073 > * Defaults to 'auto'.
4074 > */
4075 > horizontal?: 'auto' | 'visible' | 'hidden';
4076 > /**
4077 > * Cast horizontal and vertical shadows when the content is scrolled.
4078 > * Defaults to true.
4079 > * **NOTE**: This option cannot be updated using `updateOptions()`
4080 > */
4081 > useShadows?: boolean;
4082 > /**
4083 > * Render arrows at the top and bottom of the vertical scrollbar.
4084 > * Defaults to false.
4085 > * **NOTE**: This option cannot be updated using `updateOptions()`
4086 > */
4087 > verticalHasArrows?: boolean;
4088 > /**
4089 > * Render arrows at the left and right of the horizontal scrollbar.
4090 > * Defaults to false.
4091 > * **NOTE**: This option cannot be updated using `updateOptions()`
4092 > */
4093 > horizontalHasArrows?: boolean;
4094 > /**
4095 > * Listen to mouse wheel events and react to them by scrolling.
4096 > * Defaults to true.
4097 > */
4098 > handleMouseWheel?: boolean;
4099 > /**
4100 > * Always consume mouse wheel events (always call preventDefault() and stopPropagation() on the browser events).
4101 > * Defaults to true.
4102 > * **NOTE**: This option cannot be updated using `updateOptions()`
4103 > */
4104 > alwaysConsumeMouseWheel?: boolean;
4105 > /**
4106 > * Height in pixels for the horizontal scrollbar.
4107 > * Defaults to 12 (px).
4108 > */
4109 > horizontalScrollbarSize?: number;
4110 > /**
4111 > * Width in pixels for the vertical scrollbar.
4112 > * Defaults to 14 (px).
4113 > */
4114 > verticalScrollbarSize?: number;
4115 > /**
4116 > * Width in pixels for the vertical slider.
4117 > * Defaults to `verticalScrollbarSize`.
4118 > * **NOTE**: This option cannot be updated using `updateOptions()`
4119 > */
4120 > verticalSliderSize?: number;
4121 > /**
4122 > * Height in pixels for the horizontal slider.
4123 > * Defaults to `horizontalScrollbarSize`.
4124 > * **NOTE**: This option cannot be updated using `updateOptions()`
4125 > */
4126 > horizontalSliderSize?: number;
4127 > /**
4128 > * Scroll gutter clicks move by page vs jump to position.
4129 > * Defaults to false.
4130 > */
4131 > scrollByPage?: boolean;
4132 >
4133 > /**
4134 > * When set, the horizontal scrollbar will not increase content height.
4135 > * Defaults to false.
4136 > */
4137 > ignoreHorizontalScrollbarInContentHeight?: boolean;
4138 > }
4139 >
4140 > export interface InternalEditorScrollbarOptions {
4141 > readonly arrowSize: number;
4142 > readonly vertical: ScrollbarVisibility;
4143 > readonly horizontal: ScrollbarVisibility;
4144 > readonly useShadows: boolean;
4145 > readonly verticalHasArrows: boolean;
4146 > readonly horizontalHasArrows: boolean;
4147 > readonly handleMouseWheel: boolean;
4148 > readonly alwaysConsumeMouseWheel: boolean;
4149 > readonly horizontalScrollbarSize: number;
4150 > readonly horizontalSliderSize: number;
4151 > readonly verticalScrollbarSize: number;
4152 > readonly verticalSliderSize: number;
4153 > readonly scrollByPage: boolean;
4154 > readonly ignoreHorizontalScrollbarInContentHeight: boolean;
4155 > }
4156 >
4157 function _scrollbarVisibilityFromString(visibility: unknown, defaultValue: ScrollbarVisibility): ScrollbarVisibility {
4158 if (typeof visibility !== 'string') {
4165 }
4166 }
4168 > class EditorScrollbar extends BaseEditorOption<EditorOption.scrollbar, IEditorScrollbarOptions, InternalEditorScrollbarOptions> {
4169 >
4170 > constructor() {
4171 > const defaults: InternalEditorScrollbarOptions = {
4172 > vertical: ScrollbarVisibility.Auto,
4173 > horizontal: ScrollbarVisibility.Auto,
4174 > arrowSize: 11,
4175 > useShadows: true,
4176 > verticalHasArrows: false,
4177 > horizontalHasArrows: false,
4178 > horizontalScrollbarSize: 12,
4179 > horizontalSliderSize: 12,
4180 > verticalScrollbarSize: 14,
4181 > verticalSliderSize: 14,
4182 > handleMouseWheel: true,
4183 > alwaysConsumeMouseWheel: true,
4184 > scrollByPage: false,
4185 > ignoreHorizontalScrollbarInContentHeight: false,
4186 > };
4187 > super(
4188 > EditorOption.scrollbar, 'scrollbar', defaults,
4189 > {
4190 > 'editor.scrollbar.vertical': {
4191 > type: 'string',
4192 > enum: ['auto', 'visible', 'hidden'],
4193 > enumDescriptions: [
4194 > nls.localize('scrollbar.vertical.auto', "The vertical scrollbar will be visible only when necessary."),
4195 > nls.localize('scrollbar.vertical.visible', "The vertical scrollbar will always be visible."),
4196 > nls.localize('scrollbar.vertical.fit', "The vertical scrollbar will always be hidden."),
4197 > ],
4198 > default: 'auto',
4199 > description: nls.localize('scrollbar.vertical', "Controls the visibility of the vertical scrollbar.")
4200 > },
4201 > 'editor.scrollbar.horizontal': {
4202 > type: 'string',
4203 > enum: ['auto', 'visible', 'hidden'],
4204 > enumDescriptions: [
4205 > nls.localize('scrollbar.horizontal.auto', "The horizontal scrollbar will be visible only when necessary."),
4206 > nls.localize('scrollbar.horizontal.visible', "The horizontal scrollbar will always be visible."),
4207 > nls.localize('scrollbar.horizontal.fit', "The horizontal scrollbar will always be hidden."),
4208 > ],
4209 > default: 'auto',
4210 > description: nls.localize('scrollbar.horizontal', "Controls the visibility of the horizontal scrollbar.")
4211 > },
4212 > 'editor.scrollbar.verticalScrollbarSize': {
4213 > type: 'number',
4214 > default: defaults.verticalScrollbarSize,
4215 > description: nls.localize('scrollbar.verticalScrollbarSize', "The width of the vertical scrollbar.")
4216 > },
4217 > 'editor.scrollbar.horizontalScrollbarSize': {
4218 > type: 'number',
4219 > default: defaults.horizontalScrollbarSize,
4220 > description: nls.localize('scrollbar.horizontalScrollbarSize', "The height of the horizontal scrollbar.")
4221 > },
4222 > 'editor.scrollbar.scrollByPage': {
4223 > type: 'boolean',
4224 > default: defaults.scrollByPage,
4225 > description: nls.localize('scrollbar.scrollByPage', "Controls whether clicks scroll by page or jump to click position.")
4226 > },
4227 > 'editor.scrollbar.ignoreHorizontalScrollbarInContentHeight': {
4228 > type: 'boolean',
4229 > default: defaults.ignoreHorizontalScrollbarInContentHeight,
4230 > description: nls.localize('scrollbar.ignoreHorizontalScrollbarInContentHeight', "When set, the horizontal scrollbar will not increase the size of the editor's content.")
4231 > }
4232 > }
4233 > );
4234 > }
4235 >
4236 > public validate(_input: unknown): InternalEditorScrollbarOptions {
4237 if (!_input || typeof _input !== 'object') {
4238 return this.defaultValue;
4258 };
4259 }
4260 > } editorOptions.ts
4261 >
4262 > //#endregion
4263 >
4264 > //#region UnicodeHighlight
4265 >
4266 > export type InUntrustedWorkspace = 'inUntrustedWorkspace';
4267 >
4268 > /**
4269 > * @internal
4270 > */
4271 > export const inUntrustedWorkspace: InUntrustedWorkspace = 'inUntrustedWorkspace';
4272 >
4273 > /**
4274 > * Configuration options for unicode highlighting.
4275 > */
4276 > export interface IUnicodeHighlightOptions {
4277 >
4278 > /**
4279 > * Controls whether all non-basic ASCII characters are highlighted. Only characters between U+0020 and U+007E, tab, line-feed and carriage-return are considered basic ASCII.
4280 > */
4281 > nonBasicASCII?: boolean | InUntrustedWorkspace;
4282 >
4283 > /**
4284 > * Controls whether characters that just reserve space or have no width at all are highlighted.
4285 > */
4286 > invisibleCharacters?: boolean;
4287 >
4288 > /**
4289 > * Controls whether characters are highlighted that can be confused with basic ASCII characters, except those that are common in the current user locale.
4290 > */
4291 > ambiguousCharacters?: boolean;
4292 >
4293 > /**
4294 > * Controls whether characters in comments should also be subject to unicode highlighting.
4295 > */
4296 > includeComments?: boolean | InUntrustedWorkspace;
4297 >
4298 > /**
4299 > * Controls whether characters in strings should also be subject to unicode highlighting.
4300 > */
4301 > includeStrings?: boolean | InUntrustedWorkspace;
4302 >
4303 > /**
4304 > * Defines allowed characters that are not being highlighted.
4305 > */
4306 > allowedCharacters?: Record<string, true>;
4307 >
4308 > /**
4309 > * Unicode characters that are common in allowed locales are not being highlighted.
4310 > */
4311 > allowedLocales?: Record<string | '_os' | '_vscode', true>;
4312 > }
4313 >
4314 > /**
4315 > * @internal
4316 > */
4317 > export type InternalUnicodeHighlightOptions = Required<Readonly<IUnicodeHighlightOptions>>;
4318 >
4319 > /**
4320 > * @internal
4321 > */
4322 > export const unicodeHighlightConfigKeys = {
4323 > allowedCharacters: 'editor.unicodeHighlight.allowedCharacters',
4324 > invisibleCharacters: 'editor.unicodeHighlight.invisibleCharacters',
4325 > nonBasicASCII: 'editor.unicodeHighlight.nonBasicASCII',
4326 > ambiguousCharacters: 'editor.unicodeHighlight.ambiguousCharacters',
4327 > includeComments: 'editor.unicodeHighlight.includeComments',
4328 > includeStrings: 'editor.unicodeHighlight.includeStrings',
4329 > allowedLocales: 'editor.unicodeHighlight.allowedLocales',
4330 > };
4331 >
4332 > class UnicodeHighlight extends BaseEditorOption<EditorOption.unicodeHighlighting, IUnicodeHighlightOptions, InternalUnicodeHighlightOptions> {
4333 > constructor() {
4334 > const defaults: InternalUnicodeHighlightOptions = {
4335 > nonBasicASCII: inUntrustedWorkspace,
4336 > invisibleCharacters: true,
4337 > ambiguousCharacters: true,
4338 > includeComments: inUntrustedWorkspace,
4339 > includeStrings: true,
4340 > allowedCharacters: {},
4341 > allowedLocales: { _os: true, _vscode: true },
4342 > };
4343 >
4344 > super(
4345 > EditorOption.unicodeHighlighting, 'unicodeHighlight', defaults,
4346 > {
4347 > [unicodeHighlightConfigKeys.nonBasicASCII]: {
4348 > restricted: true,
4349 > type: ['boolean', 'string'],
4350 > enum: [true, false, inUntrustedWorkspace],
4351 > default: defaults.nonBasicASCII,
4352 > description: nls.localize('unicodeHighlight.nonBasicASCII', "Controls whether all non-basic ASCII characters are highlighted. Only characters between U+0020 and U+007E, tab, line-feed and carriage-return are considered basic ASCII.")
4353 > },
4354 > [unicodeHighlightConfigKeys.invisibleCharacters]: {
4355 > restricted: true,
4356 > type: 'boolean',
4357 > default: defaults.invisibleCharacters,
4358 > description: nls.localize('unicodeHighlight.invisibleCharacters', "Controls whether characters that just reserve space or have no width at all are highlighted.")
4359 > },
4360 > [unicodeHighlightConfigKeys.ambiguousCharacters]: {
4361 > restricted: true,
4362 > type: 'boolean',
4363 > default: defaults.ambiguousCharacters,
4364 > description: nls.localize('unicodeHighlight.ambiguousCharacters', "Controls whether characters are highlighted that can be confused with basic ASCII characters, except those that are common in the current user locale.")
4365 > },
4366 > [unicodeHighlightConfigKeys.includeComments]: {
4367 > restricted: true,
4368 > type: ['boolean', 'string'],
4369 > enum: [true, false, inUntrustedWorkspace],
4370 > default: defaults.includeComments,
4371 > description: nls.localize('unicodeHighlight.includeComments', "Controls whether characters in comments should also be subject to Unicode highlighting.")
4372 > },
4373 > [unicodeHighlightConfigKeys.includeStrings]: {
4374 > restricted: true,
4375 > type: ['boolean', 'string'],
4376 > enum: [true, false, inUntrustedWorkspace],
4377 > default: defaults.includeStrings,
4378 > description: nls.localize('unicodeHighlight.includeStrings', "Controls whether characters in strings should also be subject to Unicode highlighting.")
4379 > },
4380 > [unicodeHighlightConfigKeys.allowedCharacters]: {
4381 > restricted: true,
4382 > type: 'object',
4383 > default: defaults.allowedCharacters,
4384 > description: nls.localize('unicodeHighlight.allowedCharacters', "Defines allowed characters that are not being highlighted."),
4385 > additionalProperties: {
4386 > type: 'boolean'
4387 > }
4388 > },
4389 > [unicodeHighlightConfigKeys.allowedLocales]: {
4390 > restricted: true,
4391 > type: 'object',
4392 > additionalProperties: {
4393 > type: 'boolean'
4394 > },
4395 > default: defaults.allowedLocales,
4396 > description: nls.localize('unicodeHighlight.allowedLocales', "Unicode characters that are common in allowed locales are not being highlighted.")
4397 > },
4398 > }
4399 > );
4400 > }
4401 >
4402 > public override applyUpdate(value: Required<Readonly<IUnicodeHighlightOptions>> | undefined, update: Required<Readonly<IUnicodeHighlightOptions>>): ApplyUpdateResult<Required<Readonly<IUnicodeHighlightOptions>>> {
4403 let didChange = false;
4404 if (update.allowedCharacters && value) {
4423 return result;
4424 }
4426 > public validate(_input: unknown): InternalUnicodeHighlightOptions {
4427 if (!_input || typeof _input !== 'object') {
4428 return this.defaultValue;
4439 };
4440 }
4442 > private validateBooleanMap(map: unknown, defaultValue: Record<string, true>): Record<string, true> {
4443 if ((typeof map !== 'object') || !map) {
4444 return defaultValue;
4452 return result;
4453 }
4454 > } editorOptions.ts
4455 >
4456 > //#endregion
4457 >
4458 > //#region inlineSuggest
4459 >
4460 > export interface IInlineSuggestOptions {
4461 > /**
4462 > * Enable or disable the rendering of automatic inline completions.
4463 > */
4464 > enabled?: boolean;
4465 >
4466 > /**
4467 > * Configures the mode.
4468 > * Use `prefix` to only show ghost text if the text to replace is a prefix of the suggestion text.
4469 > * Use `subword` to only show ghost text if the replace text is a subword of the suggestion text.
4470 > * Use `subwordSmart` to only show ghost text if the replace text is a subword of the suggestion text, but the subword must start after the cursor position.
4471 > * Defaults to `prefix`.
4472 > */
4473 > mode?: 'prefix' | 'subword' | 'subwordSmart';
4474 >
4475 > showToolbar?: 'always' | 'onHover' | 'never';
4476 >
4477 > syntaxHighlightingEnabled?: boolean;
4478 >
4479 > suppressSuggestions?: boolean;
4480 >
4481 > minShowDelay?: number;
4482 > suppressInSnippetMode?: boolean;
4483 > /**
4484 > * Does not clear active inline suggestions when the editor loses focus.
4485 > */
4486 > keepOnBlur?: boolean;
4487 >
4488 > /**
4489 > * Font family for inline suggestions.
4490 > */
4491 > fontFamily?: string | 'default';
4492 >
4493 > edits?: {
4494 > allowCodeShifting?: 'always' | 'horizontal' | 'never';
4495 >
4496 > renderSideBySide?: 'never' | 'auto';
4497 >
4498 > showCollapsed?: boolean;
4499 >
4500 > showLongDistanceHint?: boolean;
4501 >
4502 > /**
4503 > * Controls how many lines of surrounding context are shown above and below the target line
4504 > * in the long distance inline suggestion hint preview. `0` shows only the target line.
4505 > */
4506 > longDistanceHintContextLineCount?: number;
4507 >
4508 > /**
4509 > * @internal
4510 > */
4511 > enabled?: boolean;
4512 > };
4513 >
4514 > /**
4515 > * @internal
4516 > */
4517 > triggerCommandOnProviderChange?: boolean;
4518 >
4519 > /**
4520 > * @internal
4521 > */
4522 > experimental?: {
4523 > /**
4524 > * @internal
4525 > */
4526 > suppressInlineSuggestions?: string;
4527 >
4528 > /**
4529 > * @internal
4530 > */
4531 > emptyResponseInformation?: boolean;
4532 >
4533 > showOnSuggestConflict?: 'always' | 'never' | 'whenSuggestListIsIncomplete';
4534 > };
4535 > }
4536 >
4537 > type RequiredRecursive<T> = {
4538 > [P in keyof T]-?: T[P] extends object | undefined ? RequiredRecursive<T[P]> : T[P];
4539 > };
4540 >
4541 > /**
4542 > * @internal
4543 > */
4544 > export type InternalInlineSuggestOptions = Readonly<RequiredRecursive<IInlineSuggestOptions>>;
4545 >
4546 > /**
4547 > * Configuration options for inline suggestions
4548 > */
4549 > class InlineEditorSuggest extends BaseEditorOption<EditorOption.inlineSuggest, IInlineSuggestOptions, InternalInlineSuggestOptions> {
4550 > constructor() {
4551 > const defaults: InternalInlineSuggestOptions = {
4552 > enabled: true,
4553 > mode: 'subwordSmart',
4554 > showToolbar: 'onHover',
4555 > suppressSuggestions: false,
4556 > keepOnBlur: false,
4557 > fontFamily: 'default',
4558 > syntaxHighlightingEnabled: true,
4559 > minShowDelay: 0,
4560 > suppressInSnippetMode: true,
4561 > edits: {
4562 > enabled: true,
4563 > showCollapsed: false,
4564 > renderSideBySide: 'auto',
4565 > allowCodeShifting: 'always',
4566 > showLongDistanceHint: true,
4567 > longDistanceHintContextLineCount: 0,
4568 > },
4569 > triggerCommandOnProviderChange: false,
4570 > experimental: {
4571 > suppressInlineSuggestions: '',
4572 > showOnSuggestConflict: 'never',
4573 > emptyResponseInformation: true,
4574 > },
4575 > };
4576 >
4577 > super(
4578 > EditorOption.inlineSuggest, 'inlineSuggest', defaults,
4579 > {
4580 > 'editor.inlineSuggest.enabled': {
4581 > type: 'boolean',
4582 > default: defaults.enabled,
4583 > description: nls.localize('inlineSuggest.enabled', "Controls whether to automatically show inline suggestions in the editor.")
4584 > },
4585 > 'editor.inlineSuggest.showToolbar': {
4586 > type: 'string',
4587 > default: defaults.showToolbar,
4588 > enum: ['always', 'onHover', 'never'],
4589 > enumDescriptions: [
4590 > nls.localize('inlineSuggest.showToolbar.always', "Show the inline suggestion toolbar whenever an inline suggestion is shown."),
4591 > nls.localize('inlineSuggest.showToolbar.onHover', "Show the inline suggestion toolbar when hovering over an inline suggestion."),
4592 > nls.localize('inlineSuggest.showToolbar.never', "Never show the inline suggestion toolbar."),
4593 > ],
4594 > description: nls.localize('inlineSuggest.showToolbar', "Controls when to show the inline suggestion toolbar."),
4595 > },
4596 > 'editor.inlineSuggest.syntaxHighlightingEnabled': {
4597 > type: 'boolean',
4598 > default: defaults.syntaxHighlightingEnabled,
4599 > description: nls.localize('inlineSuggest.syntaxHighlightingEnabled', "Controls whether to show syntax highlighting for inline suggestions in the editor."),
4600 > },
4601 > 'editor.inlineSuggest.suppressSuggestions': {
4602 > type: 'boolean',
4603 > default: defaults.suppressSuggestions,
4604 > description: nls.localize('inlineSuggest.suppressSuggestions', "Controls how inline suggestions interact with the suggest widget. If enabled, the suggest widget is not shown automatically when inline suggestions are available.")
4605 > },
4606 > 'editor.inlineSuggest.suppressInSnippetMode': {
4607 > type: 'boolean',
4608 > default: defaults.suppressInSnippetMode,
4609 > description: nls.localize('inlineSuggest.suppressInSnippetMode', "Controls whether inline suggestions are suppressed when in snippet mode."),
4610 > },
4611 > 'editor.inlineSuggest.minShowDelay': {
4612 > type: 'number',
4613 > default: 0,
4614 > minimum: 0,
4615 > maximum: 10000,
4616 > description: nls.localize('inlineSuggest.minShowDelay', "Controls the minimal delay in milliseconds after which inline suggestions are shown after typing."),
4617 > },
4618 > 'editor.inlineSuggest.experimental.suppressInlineSuggestions': {
4619 > type: 'string',
4620 > default: defaults.experimental.suppressInlineSuggestions,
4621 > tags: ['experimental'],
4622 > description: nls.localize('inlineSuggest.suppressInlineSuggestions', "Suppresses inline completions for specified extension IDs -- comma separated."),
4623 > experiment: {
4624 > mode: 'auto'
4625 > }
4626 > },
4627 > 'editor.inlineSuggest.experimental.emptyResponseInformation': {
4628 > type: 'boolean',
4629 > default: defaults.experimental.emptyResponseInformation,
4630 > tags: ['experimental'],
4631 > description: nls.localize('inlineSuggest.emptyResponseInformation', "Controls whether to send request information from the inline suggestion provider."),
4632 > experiment: {
4633 > mode: 'auto'
4634 > }
4635 > },
4636 > 'editor.inlineSuggest.triggerCommandOnProviderChange': {
4637 > type: 'boolean',
4638 > default: defaults.triggerCommandOnProviderChange,
4639 > tags: ['experimental'],
4640 > description: nls.localize('inlineSuggest.triggerCommandOnProviderChange', "Controls whether to trigger a command when the inline suggestion provider changes."),
4641 > experiment: {
4642 > mode: 'auto'
4643 > }
4644 > },
4645 > 'editor.inlineSuggest.experimental.showOnSuggestConflict': {
4646 > type: 'string',
4647 > default: defaults.experimental.showOnSuggestConflict,
4648 > tags: ['experimental'],
4649 > enum: ['always', 'never', 'whenSuggestListIsIncomplete'],
4650 > description: nls.localize('inlineSuggest.showOnSuggestConflict', "Controls whether to show inline suggestions when there is a suggest conflict."),
4651 > experiment: {
4652 > mode: 'auto'
4653 > }
4654 > },
4655 > 'editor.inlineSuggest.fontFamily': {
4656 > type: 'string',
4657 > default: defaults.fontFamily,
4658 > description: nls.localize('inlineSuggest.fontFamily', "Controls the font family of the inline suggestions.")
4659 > },
4660 > 'editor.inlineSuggest.edits.allowCodeShifting': {
4661 > type: 'string',
4662 > default: defaults.edits.allowCodeShifting,
4663 > description: nls.localize('inlineSuggest.edits.allowCodeShifting', "Controls whether showing a suggestion will shift the code to make space for the suggestion inline."),
4664 > enum: ['always', 'horizontal', 'never'],
4665 > tags: ['nextEditSuggestions']
4666 > },
4667 > 'editor.inlineSuggest.edits.showLongDistanceHint': {
4668 > type: 'boolean',
4669 > default: defaults.edits.showLongDistanceHint,
4670 > description: nls.localize('inlineSuggest.edits.showLongDistanceHint', "Controls whether long distance inline suggestions are shown."),
4671 > tags: ['nextEditSuggestions', 'experimental']
4672 > },
4673 > 'editor.inlineSuggest.edits.longDistanceHintContextLineCount': {
4674 > type: 'number',
4675 > default: defaults.edits.longDistanceHintContextLineCount,
4676 > minimum: 0,
4677 > maximum: 10,
4678 > description: nls.localize('inlineSuggest.edits.longDistanceHintContextLineCount', "Controls how many lines of surrounding context are shown above and below the target line in the long distance inline suggestion preview. Set to 0 to only show the target line."),
4679 > tags: ['nextEditSuggestions', 'experimental'],
4680 > experiment: {
4681 > mode: 'auto'
4682 > }
4683 > },
4684 > 'editor.inlineSuggest.edits.renderSideBySide': {
4685 > type: 'string',
4686 > default: defaults.edits.renderSideBySide,
4687 > description: nls.localize('inlineSuggest.edits.renderSideBySide', "Controls whether larger suggestions can be shown side by side."),
4688 > enum: ['auto', 'never'],
4689 > enumDescriptions: [
4690 > nls.localize('editor.inlineSuggest.edits.renderSideBySide.auto', "Larger suggestions will show side by side if there is enough space, otherwise they will be shown below."),
4691 > nls.localize('editor.inlineSuggest.edits.renderSideBySide.never', "Larger suggestions are never shown side by side and will always be shown below."),
4692 > ],
4693 > tags: ['nextEditSuggestions']
4694 > },
4695 > 'editor.inlineSuggest.edits.showCollapsed': {
4696 > type: 'boolean',
4697 > default: defaults.edits.showCollapsed,
4698 > description: nls.localize('inlineSuggest.edits.showCollapsed', "Controls whether the suggestion will show as collapsed until jumping to it."),
4699 > tags: ['nextEditSuggestions']
4700 > },
4701 > }
4702 > );
4703 > }
4704 >
4705 > public validate(_input: unknown): InternalInlineSuggestOptions {
4706 if (!_input || typeof _input !== 'object') {
4707 return this.defaultValue;
4723 };
4724 }
4726 > private _validateEdits(_input: unknown): InternalInlineSuggestOptions['edits'] {
4727 if (!_input || typeof _input !== 'object') {
4728 return this.defaultValue.edits;
4738 };
4739 }
4741 > private _validateExperimental(_input: unknown): InternalInlineSuggestOptions['experimental'] {
4742 if (!_input || typeof _input !== 'object') {
4743 return this.defaultValue.experimental;
4750 };
4751 }
4752 > } editorOptions.ts
4753 >
4754 > //#endregion
4755 >
4756 > //#region bracketPairColorization
4757 >
4758 > export interface IBracketPairColorizationOptions {
4759 > /**
4760 > * Enable or disable bracket pair colorization.
4761 > */
4762 > enabled?: boolean;
4763 >
4764 > /**
4765 > * Use independent color pool per bracket type.
4766 > */
4767 > independentColorPoolPerBracketType?: boolean;
4768 > }
4769 >
4770 > /**
4771 > * @internal
4772 > */
4773 > export type InternalBracketPairColorizationOptions = Readonly<Required<IBracketPairColorizationOptions>>;
4774 >
4775 > /**
4776 > * Configuration options for inline suggestions
4777 > */
4778 > class BracketPairColorization extends BaseEditorOption<EditorOption.bracketPairColorization, IBracketPairColorizationOptions, InternalBracketPairColorizationOptions> {
4779 > constructor() {
4780 > const defaults: InternalBracketPairColorizationOptions = {
4781 > enabled: EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions.enabled,
4782 > independentColorPoolPerBracketType: EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions.independentColorPoolPerBracketType,
4783 > };
4784 >
4785 > super(
4786 > EditorOption.bracketPairColorization, 'bracketPairColorization', defaults,
4787 > {
4788 > 'editor.bracketPairColorization.enabled': {
4789 > type: 'boolean',
4790 > default: defaults.enabled,
4791 > markdownDescription: nls.localize('bracketPairColorization.enabled', "Controls whether bracket pair colorization is enabled or not. Use {0} to override the bracket highlight colors.", '`#workbench.colorCustomizations#`')
4792 > },
4793 > 'editor.bracketPairColorization.independentColorPoolPerBracketType': {
4794 > type: 'boolean',
4795 > default: defaults.independentColorPoolPerBracketType,
4796 > description: nls.localize('bracketPairColorization.independentColorPoolPerBracketType', "Controls whether each bracket type has its own independent color pool.")
4797 > },
4798 > }
4799 > );
4800 > }
4801 >
4802 > public validate(_input: unknown): InternalBracketPairColorizationOptions {
4803 if (!_input || typeof _input !== 'object') {
4804 return this.defaultValue;
4810 };
4811 }
4812 > } editorOptions.ts
4813 >
4814 > //#endregion
4815 >
4816 > //#region guides
4817 >
4818 > export interface IGuidesOptions {
4819 > /**
4820 > * Enable rendering of bracket pair guides.
4821 > * Defaults to false.
4822 > */
4823 > bracketPairs?: boolean | 'active';
4824 >
4825 > /**
4826 > * Enable rendering of vertical bracket pair guides.
4827 > * Defaults to 'active'.
4828 > */
4829 > bracketPairsHorizontal?: boolean | 'active';
4830 >
4831 > /**
4832 > * Enable highlighting of the active bracket pair.
4833 > * Defaults to true.
4834 > */
4835 > highlightActiveBracketPair?: boolean;
4836 >
4837 > /**
4838 > * Enable rendering of indent guides.
4839 > * Defaults to true.
4840 > */
4841 > indentation?: boolean;
4842 >
4843 > /**
4844 > * Enable highlighting of the active indent guide.
4845 > * Defaults to true.
4846 > */
4847 > highlightActiveIndentation?: boolean | 'always';
4848 > }
4849 >
4850 > /**
4851 > * @internal
4852 > */
4853 > export type InternalGuidesOptions = Readonly<Required<IGuidesOptions>>;
4854 >
4855 > /**
4856 > * Configuration options for inline suggestions
4857 > */
4858 > class GuideOptions extends BaseEditorOption<EditorOption.guides, IGuidesOptions, InternalGuidesOptions> {
4859 > constructor() {
4860 > const defaults: InternalGuidesOptions = {
4861 > bracketPairs: false,
4862 > bracketPairsHorizontal: 'active',
4863 > highlightActiveBracketPair: true,
4864 >
4865 > indentation: true,
4866 > highlightActiveIndentation: true
4867 > };
4868 >
4869 > super(
4870 > EditorOption.guides, 'guides', defaults,
4871 > {
4872 > 'editor.guides.bracketPairs': {
4873 > type: ['boolean', 'string'],
4874 > enum: [true, 'active', false],
4875 > enumDescriptions: [
4876 > nls.localize('editor.guides.bracketPairs.true', "Enables bracket pair guides."),
4877 > nls.localize('editor.guides.bracketPairs.active', "Enables bracket pair guides only for the active bracket pair."),
4878 > nls.localize('editor.guides.bracketPairs.false', "Disables bracket pair guides."),
4879 > ],
4880 > default: defaults.bracketPairs,
4881 > description: nls.localize('editor.guides.bracketPairs', "Controls whether bracket pair guides are enabled or not.")
4882 > },
4883 > 'editor.guides.bracketPairsHorizontal': {
4884 > type: ['boolean', 'string'],
4885 > enum: [true, 'active', false],
4886 > enumDescriptions: [
4887 > nls.localize('editor.guides.bracketPairsHorizontal.true', "Enables horizontal guides as addition to vertical bracket pair guides."),
4888 > nls.localize('editor.guides.bracketPairsHorizontal.active', "Enables horizontal guides only for the active bracket pair."),
4889 > nls.localize('editor.guides.bracketPairsHorizontal.false', "Disables horizontal bracket pair guides."),
4890 > ],
4891 > default: defaults.bracketPairsHorizontal,
4892 > description: nls.localize('editor.guides.bracketPairsHorizontal', "Controls whether horizontal bracket pair guides are enabled or not.")
4893 > },
4894 > 'editor.guides.highlightActiveBracketPair': {
4895 > type: 'boolean',
4896 > default: defaults.highlightActiveBracketPair,
4897 > description: nls.localize('editor.guides.highlightActiveBracketPair', "Controls whether the editor should highlight the active bracket pair.")
4898 > },
4899 > 'editor.guides.indentation': {
4900 > type: 'boolean',
4901 > default: defaults.indentation,
4902 > description: nls.localize('editor.guides.indentation', "Controls whether the editor should render indent guides.")
4903 > },
4904 > 'editor.guides.highlightActiveIndentation': {
4905 > type: ['boolean', 'string'],
4906 > enum: [true, 'always', false],
4907 > enumDescriptions: [
4908 > nls.localize('editor.guides.highlightActiveIndentation.true', "Highlights the active indent guide."),
4909 > nls.localize('editor.guides.highlightActiveIndentation.always', "Highlights the active indent guide even if bracket guides are highlighted."),
4910 > nls.localize('editor.guides.highlightActiveIndentation.false', "Do not highlight the active indent guide."),
4911 > ],
4912 > default: defaults.highlightActiveIndentation,
4913 >
4914 > description: nls.localize('editor.guides.highlightActiveIndentation', "Controls whether the editor should highlight the active indent guide.")
4915 > }
4916 > }
4917 > );
4918 > }
4919 >
4920 > public validate(_input: unknown): InternalGuidesOptions {
4921 if (!_input || typeof _input !== 'object') {
4922 return this.defaultValue;
4932 };
4933 }
4934 > } editorOptions.ts
4935 >
4936 function primitiveSet<T extends string | boolean>(value: unknown, defaultValue: T, allowedValues: T[]): T {
4937 const idx = allowedValues.indexOf(value as T);
4941 return allowedValues[idx];
4942 }
4944 > //#endregion
4945 >
4946 > //#region suggest
4947 >
4948 > /**
4949 > * Configuration options for editor suggest widget
4950 > */
4951 > export interface ISuggestOptions {
4952 > /**
4953 > * Overwrite word ends on accept. Default to false.
4954 > */
4955 > insertMode?: 'insert' | 'replace';
4956 > /**
4957 > * Enable graceful matching. Defaults to true.
4958 > */
4959 > filterGraceful?: boolean;
4960 > /**
4961 > * Prevent quick suggestions when a snippet is active. Defaults to true.
4962 > */
4963 > snippetsPreventQuickSuggestions?: boolean;
4964 > /**
4965 > * Favors words that appear close to the cursor.
4966 > */
4967 > localityBonus?: boolean;
4968 > /**
4969 > * Enable using global storage for remembering suggestions.
4970 > */
4971 > shareSuggestSelections?: boolean;
4972 > /**
4973 > * Select suggestions when triggered via quick suggest or trigger characters
4974 > */
4975 > selectionMode?: 'always' | 'never' | 'whenTriggerCharacter' | 'whenQuickSuggestion';
4976 > /**
4977 > * Enable or disable icons in suggestions. Defaults to true.
4978 > */
4979 > showIcons?: boolean;
4980 > /**
4981 > * Enable or disable the suggest status bar.
4982 > */
4983 > showStatusBar?: boolean;
4984 > /**
4985 > * Enable or disable the rendering of the suggestion preview.
4986 > */
4987 > preview?: boolean;
4988 > /**
4989 > * Configures the mode of the preview.
4990 > */
4991 > previewMode?: 'prefix' | 'subword' | 'subwordSmart';
4992 > /**
4993 > * Show details inline with the label. Defaults to true.
4994 > */
4995 > showInlineDetails?: boolean;
4996 > /**
4997 > * Show method-suggestions.
4998 > */
4999 > showMethods?: boolean;
5000 > /**
5001 > * Show function-suggestions.
5002 > */
5003 > showFunctions?: boolean;
5004 > /**
5005 > * Show constructor-suggestions.
5006 > */
5007 > showConstructors?: boolean;
5008 > /**
5009 > * Show deprecated-suggestions.
5010 > */
5011 > showDeprecated?: boolean;
5012 > /**
5013 > * Controls whether suggestions allow matches in the middle of the word instead of only at the beginning
5014 > */
5015 > matchOnWordStartOnly?: boolean;
5016 > /**
5017 > * Show field-suggestions.
5018 > */
5019 > showFields?: boolean;
5020 > /**
5021 > * Show variable-suggestions.
5022 > */
5023 > showVariables?: boolean;
5024 > /**
5025 > * Show class-suggestions.
5026 > */
5027 > showClasses?: boolean;
5028 > /**
5029 > * Show struct-suggestions.
5030 > */
5031 > showStructs?: boolean;
5032 > /**
5033 > * Show interface-suggestions.
5034 > */
5035 > showInterfaces?: boolean;
5036 > /**
5037 > * Show module-suggestions.
5038 > */
5039 > showModules?: boolean;
5040 > /**
5041 > * Show property-suggestions.
5042 > */
5043 > showProperties?: boolean;
5044 > /**
5045 > * Show event-suggestions.
5046 > */
5047 > showEvents?: boolean;
5048 > /**
5049 > * Show operator-suggestions.
5050 > */
5051 > showOperators?: boolean;
5052 > /**
5053 > * Show unit-suggestions.
5054 > */
5055 > showUnits?: boolean;
5056 > /**
5057 > * Show value-suggestions.
5058 > */
5059 > showValues?: boolean;
5060 > /**
5061 > * Show constant-suggestions.
5062 > */
5063 > showConstants?: boolean;
5064 > /**
5065 > * Show enum-suggestions.
5066 > */
5067 > showEnums?: boolean;
5068 > /**
5069 > * Show enumMember-suggestions.
5070 > */
5071 > showEnumMembers?: boolean;
5072 > /**
5073 > * Show keyword-suggestions.
5074 > */
5075 > showKeywords?: boolean;
5076 > /**
5077 > * Show text-suggestions.
5078 > */
5079 > showWords?: boolean;
5080 > /**
5081 > * Show color-suggestions.
5082 > */
5083 > showColors?: boolean;
5084 > /**
5085 > * Show file-suggestions.
5086 > */
5087 > showFiles?: boolean;
5088 > /**
5089 > * Show reference-suggestions.
5090 > */
5091 > showReferences?: boolean;
5092 > /**
5093 > * Show folder-suggestions.
5094 > */
5095 > showFolders?: boolean;
5096 > /**
5097 > * Show typeParameter-suggestions.
5098 > */
5099 > showTypeParameters?: boolean;
5100 > /**
5101 > * Show issue-suggestions.
5102 > */
5103 > showIssues?: boolean;
5104 > /**
5105 > * Show user-suggestions.
5106 > */
5107 > showUsers?: boolean;
5108 > /**
5109 > * Show snippet-suggestions.
5110 > */
5111 > showSnippets?: boolean;
5112 > }
5113 >
5114 > /**
5115 > * @internal
5116 > */
5117 > export type InternalSuggestOptions = Readonly<Required<ISuggestOptions>>;
5118 >
5119 > class EditorSuggest extends BaseEditorOption<EditorOption.suggest, ISuggestOptions, InternalSuggestOptions> {
5120 >
5121 > constructor() {
5122 > const defaults: InternalSuggestOptions = {
5123 > insertMode: 'insert',
5124 > filterGraceful: true,
5125 > snippetsPreventQuickSuggestions: false,
5126 > localityBonus: false,
5127 > shareSuggestSelections: false,
5128 > selectionMode: 'always',
5129 > showIcons: true,
5130 > showStatusBar: false,
5131 > preview: false,
5132 > previewMode: 'subwordSmart',
5133 > showInlineDetails: true,
5134 > showMethods: true,
5135 > showFunctions: true,
5136 > showConstructors: true,
5137 > showDeprecated: true,
5138 > matchOnWordStartOnly: true,
5139 > showFields: true,
5140 > showVariables: true,
5141 > showClasses: true,
5142 > showStructs: true,
5143 > showInterfaces: true,
5144 > showModules: true,
5145 > showProperties: true,
5146 > showEvents: true,
5147 > showOperators: true,
5148 > showUnits: true,
5149 > showValues: true,
5150 > showConstants: true,
5151 > showEnums: true,
5152 > showEnumMembers: true,
5153 > showKeywords: true,
5154 > showWords: true,
5155 > showColors: true,
5156 > showFiles: true,
5157 > showReferences: true,
5158 > showFolders: true,
5159 > showTypeParameters: true,
5160 > showSnippets: true,
5161 > showUsers: true,
5162 > showIssues: true,
5163 > };
5164 > super(
5165 > EditorOption.suggest, 'suggest', defaults,
5166 > {
5167 > 'editor.suggest.insertMode': {
5168 > type: 'string',
5169 > enum: ['insert', 'replace'],
5170 > enumDescriptions: [
5171 > nls.localize('suggest.insertMode.insert', "Insert suggestion without overwriting text right of the cursor."),
5172 > nls.localize('suggest.insertMode.replace', "Insert suggestion and overwrite text right of the cursor."),
5173 > ],
5174 > default: defaults.insertMode,
5175 > description: nls.localize('suggest.insertMode', "Controls whether words are overwritten when accepting completions. Note that this depends on extensions opting into this feature.")
5176 > },
5177 > 'editor.suggest.filterGraceful': {
5178 > type: 'boolean',
5179 > default: defaults.filterGraceful,
5180 > description: nls.localize('suggest.filterGraceful', "Controls whether filtering and sorting suggestions accounts for small typos.")
5181 > },
5182 > 'editor.suggest.localityBonus': {
5183 > type: 'boolean',
5184 > default: defaults.localityBonus,
5185 > description: nls.localize('suggest.localityBonus', "Controls whether sorting favors words that appear close to the cursor.")
5186 > },
5187 > 'editor.suggest.shareSuggestSelections': {
5188 > type: 'boolean',
5189 > default: defaults.shareSuggestSelections,
5190 > markdownDescription: nls.localize('suggest.shareSuggestSelections', "Controls whether remembered suggestion selections are shared between multiple workspaces and windows (needs `#editor.suggestSelection#`).")
5191 > },
5192 > 'editor.suggest.selectionMode': {
5193 > type: 'string',
5194 > enum: ['always', 'never', 'whenTriggerCharacter', 'whenQuickSuggestion'],
5195 > enumDescriptions: [
5196 > nls.localize('suggest.insertMode.always', "Always select a suggestion when automatically triggering IntelliSense."),
5197 > nls.localize('suggest.insertMode.never', "Never select a suggestion when automatically triggering IntelliSense."),
5198 > nls.localize('suggest.insertMode.whenTriggerCharacter', "Select a suggestion only when triggering IntelliSense from a trigger character."),
5199 > nls.localize('suggest.insertMode.whenQuickSuggestion', "Select a suggestion only when triggering IntelliSense as you type."),
5200 > ],
5201 > default: defaults.selectionMode,
5202 > markdownDescription: nls.localize('suggest.selectionMode', "Controls whether a suggestion is selected when the widget shows. Note that this only applies to automatically triggered suggestions ({0} and {1}) and that a suggestion is always selected when explicitly invoked, e.g via `Ctrl+Space`.", '`#editor.quickSuggestions#`', '`#editor.suggestOnTriggerCharacters#`')
5203 > },
5204 > 'editor.suggest.snippetsPreventQuickSuggestions': {
5205 > type: 'boolean',
5206 > default: defaults.snippetsPreventQuickSuggestions,
5207 > description: nls.localize('suggest.snippetsPreventQuickSuggestions', "Controls whether an active snippet prevents quick suggestions.")
5208 > },
5209 > 'editor.suggest.showIcons': {
5210 > type: 'boolean',
5211 > default: defaults.showIcons,
5212 > description: nls.localize('suggest.showIcons', "Controls whether to show or hide icons in suggestions.")
5213 > },
5214 > 'editor.suggest.showStatusBar': {
5215 > type: 'boolean',
5216 > default: defaults.showStatusBar,
5217 > description: nls.localize('suggest.showStatusBar', "Controls the visibility of the status bar at the bottom of the suggest widget.")
5218 > },
5219 > 'editor.suggest.preview': {
5220 > type: 'boolean',
5221 > default: defaults.preview,
5222 > description: nls.localize('suggest.preview', "Controls whether to preview the suggestion outcome in the editor.")
5223 > },
5224 > 'editor.suggest.showInlineDetails': {
5225 > type: 'boolean',
5226 > default: defaults.showInlineDetails,
5227 > description: nls.localize('suggest.showInlineDetails', "Controls whether suggest details show inline with the label or only in the details widget.")
5228 > },
5229 > 'editor.suggest.filteredTypes': {
5230 > type: 'object',
5231 > deprecationMessage: nls.localize('deprecated', "This setting is deprecated, please use separate settings like 'editor.suggest.showKeywords' or 'editor.suggest.showSnippets' instead.")
5232 > },
5233 > 'editor.suggest.showMethods': {
5234 > type: 'boolean',
5235 > default: true,
5236 > markdownDescription: nls.localize('editor.suggest.showMethods', "When enabled IntelliSense shows `method`-suggestions.")
5237 > },
5238 > 'editor.suggest.showFunctions': {
5239 > type: 'boolean',
5240 > default: true,
5241 > markdownDescription: nls.localize('editor.suggest.showFunctions', "When enabled IntelliSense shows `function`-suggestions.")
5242 > },
5243 > 'editor.suggest.showConstructors': {
5244 > type: 'boolean',
5245 > default: true,
5246 > markdownDescription: nls.localize('editor.suggest.showConstructors', "When enabled IntelliSense shows `constructor`-suggestions.")
5247 > },
5248 > 'editor.suggest.showDeprecated': {
5249 > type: 'boolean',
5250 > default: true,
5251 > markdownDescription: nls.localize('editor.suggest.showDeprecated', "When enabled IntelliSense shows `deprecated`-suggestions.")
5252 > },
5253 > 'editor.suggest.matchOnWordStartOnly': {
5254 > type: 'boolean',
5255 > default: true,
5256 > markdownDescription: nls.localize('editor.suggest.matchOnWordStartOnly', "When enabled IntelliSense filtering requires that the first character matches on a word start. For example, `c` on `Console` or `WebContext` but _not_ on `description`. When disabled IntelliSense will show more results but still sorts them by match quality.")
5257 > },
5258 > 'editor.suggest.showFields': {
5259 > type: 'boolean',
5260 > default: true,
5261 > markdownDescription: nls.localize('editor.suggest.showFields', "When enabled IntelliSense shows `field`-suggestions.")
5262 > },
5263 > 'editor.suggest.showVariables': {
5264 > type: 'boolean',
5265 > default: true,
5266 > markdownDescription: nls.localize('editor.suggest.showVariables', "When enabled IntelliSense shows `variable`-suggestions.")
5267 > },
5268 > 'editor.suggest.showClasses': {
5269 > type: 'boolean',
5270 > default: true,
5271 > markdownDescription: nls.localize('editor.suggest.showClasss', "When enabled IntelliSense shows `class`-suggestions.")
5272 > },
5273 > 'editor.suggest.showStructs': {
5274 > type: 'boolean',
5275 > default: true,
5276 > markdownDescription: nls.localize('editor.suggest.showStructs', "When enabled IntelliSense shows `struct`-suggestions.")
5277 > },
5278 > 'editor.suggest.showInterfaces': {
5279 > type: 'boolean',
5280 > default: true,
5281 > markdownDescription: nls.localize('editor.suggest.showInterfaces', "When enabled IntelliSense shows `interface`-suggestions.")
5282 > },
5283 > 'editor.suggest.showModules': {
5284 > type: 'boolean',
5285 > default: true,
5286 > markdownDescription: nls.localize('editor.suggest.showModules', "When enabled IntelliSense shows `module`-suggestions.")
5287 > },
5288 > 'editor.suggest.showProperties': {
5289 > type: 'boolean',
5290 > default: true,
5291 > markdownDescription: nls.localize('editor.suggest.showPropertys', "When enabled IntelliSense shows `property`-suggestions.")
5292 > },
5293 > 'editor.suggest.showEvents': {
5294 > type: 'boolean',
5295 > default: true,
5296 > markdownDescription: nls.localize('editor.suggest.showEvents', "When enabled IntelliSense shows `event`-suggestions.")
5297 > },
5298 > 'editor.suggest.showOperators': {
5299 > type: 'boolean',
5300 > default: true,
5301 > markdownDescription: nls.localize('editor.suggest.showOperators', "When enabled IntelliSense shows `operator`-suggestions.")
5302 > },
5303 > 'editor.suggest.showUnits': {
5304 > type: 'boolean',
5305 > default: true,
5306 > markdownDescription: nls.localize('editor.suggest.showUnits', "When enabled IntelliSense shows `unit`-suggestions.")
5307 > },
5308 > 'editor.suggest.showValues': {
5309 > type: 'boolean',
5310 > default: true,
5311 > markdownDescription: nls.localize('editor.suggest.showValues', "When enabled IntelliSense shows `value`-suggestions.")
5312 > },
5313 > 'editor.suggest.showConstants': {
5314 > type: 'boolean',
5315 > default: true,
5316 > markdownDescription: nls.localize('editor.suggest.showConstants', "When enabled IntelliSense shows `constant`-suggestions.")
5317 > },
5318 > 'editor.suggest.showEnums': {
5319 > type: 'boolean',
5320 > default: true,
5321 > markdownDescription: nls.localize('editor.suggest.showEnums', "When enabled IntelliSense shows `enum`-suggestions.")
5322 > },
5323 > 'editor.suggest.showEnumMembers': {
5324 > type: 'boolean',
5325 > default: true,
5326 > markdownDescription: nls.localize('editor.suggest.showEnumMembers', "When enabled IntelliSense shows `enumMember`-suggestions.")
5327 > },
5328 > 'editor.suggest.showKeywords': {
5329 > type: 'boolean',
5330 > default: true,
5331 > markdownDescription: nls.localize('editor.suggest.showKeywords', "When enabled IntelliSense shows `keyword`-suggestions.")
5332 > },
5333 > 'editor.suggest.showWords': {
5334 > type: 'boolean',
5335 > default: true,
5336 > markdownDescription: nls.localize('editor.suggest.showTexts', "When enabled IntelliSense shows `text`-suggestions.")
5337 > },
5338 > 'editor.suggest.showColors': {
5339 > type: 'boolean',
5340 > default: true,
5341 > markdownDescription: nls.localize('editor.suggest.showColors', "When enabled IntelliSense shows `color`-suggestions.")
5342 > },
5343 > 'editor.suggest.showFiles': {
5344 > type: 'boolean',
5345 > default: true,
5346 > markdownDescription: nls.localize('editor.suggest.showFiles', "When enabled IntelliSense shows `file`-suggestions.")
5347 > },
5348 > 'editor.suggest.showReferences': {
5349 > type: 'boolean',
5350 > default: true,
5351 > markdownDescription: nls.localize('editor.suggest.showReferences', "When enabled IntelliSense shows `reference`-suggestions.")
5352 > },
5353 > 'editor.suggest.showCustomcolors': {
5354 > type: 'boolean',
5355 > default: true,
5356 > markdownDescription: nls.localize('editor.suggest.showCustomcolors', "When enabled IntelliSense shows `customcolor`-suggestions.")
5357 > },
5358 > 'editor.suggest.showFolders': {
5359 > type: 'boolean',
5360 > default: true,
5361 > markdownDescription: nls.localize('editor.suggest.showFolders', "When enabled IntelliSense shows `folder`-suggestions.")
5362 > },
5363 > 'editor.suggest.showTypeParameters': {
5364 > type: 'boolean',
5365 > default: true,
5366 > markdownDescription: nls.localize('editor.suggest.showTypeParameters', "When enabled IntelliSense shows `typeParameter`-suggestions.")
5367 > },
5368 > 'editor.suggest.showSnippets': {
5369 > type: 'boolean',
5370 > default: true,
5371 > markdownDescription: nls.localize('editor.suggest.showSnippets', "When enabled IntelliSense shows `snippet`-suggestions.")
5372 > },
5373 > 'editor.suggest.showUsers': {
5374 > type: 'boolean',
5375 > default: true,
5376 > markdownDescription: nls.localize('editor.suggest.showUsers', "When enabled IntelliSense shows `user`-suggestions.")
5377 > },
5378 > 'editor.suggest.showIssues': {
5379 > type: 'boolean',
5380 > default: true,
5381 > markdownDescription: nls.localize('editor.suggest.showIssues', "When enabled IntelliSense shows `issues`-suggestions.")
5382 > }
5383 > }
5384 > );
5385 > }
5386 >
5387 > public validate(_input: unknown): InternalSuggestOptions {
5388 if (!_input || typeof _input !== 'object') {
5389 return this.defaultValue;
5433 };
5434 }
5435 > } editorOptions.ts
5436 >
5437 > //#endregion
5438 >
5439 > //#region smart select
5440 >
5441 > export interface ISmartSelectOptions {
5442 > selectLeadingAndTrailingWhitespace?: boolean;
5443 > selectSubwords?: boolean;
5444 > }
5445 >
5446 > /**
5447 > * @internal
5448 > */
5449 > export type SmartSelectOptions = Readonly<Required<ISmartSelectOptions>>;
5450 >
5451 > class SmartSelect extends BaseEditorOption<EditorOption.smartSelect, ISmartSelectOptions, SmartSelectOptions> {
5452 >
5453 > constructor() {
5454 > super(
5455 > EditorOption.smartSelect, 'smartSelect',
5456 > {
5457 > selectLeadingAndTrailingWhitespace: true,
5458 > selectSubwords: true,
5459 > },
5460 > {
5461 > 'editor.smartSelect.selectLeadingAndTrailingWhitespace': {
5462 > description: nls.localize('selectLeadingAndTrailingWhitespace', "Whether leading and trailing whitespace should always be selected."),
5463 > default: true,
5464 > type: 'boolean'
5465 > },
5466 > 'editor.smartSelect.selectSubwords': {
5467 > description: nls.localize('selectSubwords', "Whether subwords (like 'foo' in 'fooBar' or 'foo_bar') should be selected."),
5468 > default: true,
5469 > type: 'boolean'
5470 > }
5471 > }
5472 > );
5473 > }
5474 >
5475 > public validate(input: unknown): Readonly<Required<ISmartSelectOptions>> {
5476 if (!input || typeof input !== 'object') {
5477 return this.defaultValue;
5482 };
5483 }
5484 > } editorOptions.ts
5485 >
5486 > //#endregion
5487 >
5488 > //#region wordSegmenterLocales
5489 >
5490 > /**
5491 > * Locales used for segmenting lines into words when doing word related navigations or operations.
5492 > *
5493 > * Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.).
5494 > */
5495 > class WordSegmenterLocales extends BaseEditorOption<EditorOption.wordSegmenterLocales, string | string[], string[]> {
5496 > constructor() {
5497 > const defaults: string[] = [];
5498 >
5499 > super(
5500 > EditorOption.wordSegmenterLocales, 'wordSegmenterLocales', defaults,
5501 > {
5502 > anyOf: [
5503 > {
5504 > type: 'string',
5505 > }, {
5506 > type: 'array',
5507 > items: {
5508 > type: 'string'
5509 > }
5510 > }
5511 > ],
5512 > description: nls.localize('wordSegmenterLocales', "Locales to be used for word segmentation when doing word related navigations or operations. Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.)."),
5513 > type: 'array',
5514 > items: {
5515 > type: 'string',
5516 > },
5517 > default: defaults,
5518 > },
5519 > );
5520 > }
5521 >
5522 > public validate(input: unknown): string[] {
5523 if (typeof input === 'string') {
5524 input = [input];
5542 return this.defaultValue;
5543 }
5544 > } editorOptions.ts
5545 >
5546 >
5547 > //#endregion
5548 >
5549 > //#region wrappingIndent
5550 >
5551 > /**
5552 > * Describes how to indent wrapped lines.
5553 > */
5554 > export const enum WrappingIndent {
5555 > /**
5556 > * No indentation => wrapped lines begin at column 1.
5557 > */
5558 > None = 0,
5559 > /**
5560 > * Same => wrapped lines get the same indentation as the parent.
5561 > */
5562 > Same = 1,
5563 > /**
5564 > * Indent => wrapped lines get +1 indentation toward the parent.
5565 > */
5566 > Indent = 2,
5567 > /**
5568 > * DeepIndent => wrapped lines get +2 indentation toward the parent.
5569 > */
5570 > DeepIndent = 3
5571 > }
5572 >
5573 > class WrappingIndentOption extends BaseEditorOption<EditorOption.wrappingIndent, 'none' | 'same' | 'indent' | 'deepIndent', WrappingIndent> {
5574 >
5575 > constructor() {
5576 > super(EditorOption.wrappingIndent, 'wrappingIndent', WrappingIndent.Same,
5577 > {
5578 > 'editor.wrappingIndent': {
5579 > type: 'string',
5580 > enum: ['none', 'same', 'indent', 'deepIndent'],
5581 > enumDescriptions: [
5582 > nls.localize('wrappingIndent.none', "No indentation. Wrapped lines begin at column 1."),
5583 > nls.localize('wrappingIndent.same', "Wrapped lines get the same indentation as the parent."),
5584 > nls.localize('wrappingIndent.indent', "Wrapped lines get +1 indentation toward the parent."),
5585 > nls.localize('wrappingIndent.deepIndent', "Wrapped lines get +2 indentation toward the parent."),
5586 > ],
5587 > description: nls.localize('wrappingIndent', "Controls the indentation of wrapped lines."),
5588 > default: 'same'
5589 > }
5590 > }
5591 > );
5592 > }
5593 >
5594 > public validate(input: unknown): WrappingIndent {
5595 switch (input) {
5596 case 'none': return WrappingIndent.None;
5601 return WrappingIndent.Same;
5602 }
5604 > public override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: WrappingIndent): WrappingIndent {
5605 const accessibilitySupport = options.get(EditorOption.accessibilitySupport);
5606 if (accessibilitySupport === AccessibilitySupport.Enabled) {
5611 return value;
5612 }
5613 > } editorOptions.ts
5614 >
5615 > //#endregion
5616 >
5617 > //#region wrappingInfo
5618 >
5619 > export interface EditorWrappingInfo {
5620 > readonly isDominatedByLongLines: boolean;
5621 > readonly isWordWrapMinified: boolean;
5622 > readonly isViewportWrapping: boolean;
5623 > readonly wrappingColumn: number;
5624 > }
5625 >
5626 > class EditorWrappingInfoComputer extends ComputedEditorOption<EditorOption.wrappingInfo, EditorWrappingInfo> {
5627 >
5628 > constructor() {
5629 > super(EditorOption.wrappingInfo, {
5630 > isDominatedByLongLines: false,
5631 > isWordWrapMinified: false,
5632 > isViewportWrapping: false,
5633 > wrappingColumn: -1
5634 > });
5635 > }
5636 >
5637 > public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorWrappingInfo): EditorWrappingInfo {
5638 const layoutInfo = options.get(EditorOption.layoutInfo);
5639
5645 };
5646 }
5647 > } editorOptions.ts
5648 >
5649 > //#endregion
5650 >
5651 > //#region dropIntoEditor
5652 >
5653 > /**
5654 > * Configuration options for editor drop into behavior
5655 > */
5656 > export interface IDropIntoEditorOptions {
5657 > /**
5658 > * Enable dropping into editor.
5659 > * Defaults to true.
5660 > */
5661 > enabled?: boolean;
5662 >
5663 > /**
5664 > * Controls if a widget is shown after a drop.
5665 > * Defaults to 'afterDrop'.
5666 > */
5667 > showDropSelector?: 'afterDrop' | 'never';
5668 > }
5669 >
5670 > /**
5671 > * @internal
5672 > */
5673 > export type EditorDropIntoEditorOptions = Readonly<Required<IDropIntoEditorOptions>>;
5674 >
5675 > class EditorDropIntoEditor extends BaseEditorOption<EditorOption.dropIntoEditor, IDropIntoEditorOptions, EditorDropIntoEditorOptions> {
5676 >
5677 > constructor() {
5678 > const defaults: EditorDropIntoEditorOptions = { enabled: true, showDropSelector: 'afterDrop' };
5679 > super(
5680 > EditorOption.dropIntoEditor, 'dropIntoEditor', defaults,
5681 > {
5682 > 'editor.dropIntoEditor.enabled': {
5683 > type: 'boolean',
5684 > default: defaults.enabled,
5685 > markdownDescription: nls.localize('dropIntoEditor.enabled', "Controls whether you can drag and drop a file into a text editor by holding down the `Shift` key (instead of opening the file in an editor)."),
5686 > },
5687 > 'editor.dropIntoEditor.showDropSelector': {
5688 > type: 'string',
5689 > markdownDescription: nls.localize('dropIntoEditor.showDropSelector', "Controls if a widget is shown when dropping files into the editor. This widget lets you control how the file is dropped."),
5690 > enum: [
5691 > 'afterDrop',
5692 > 'never'
5693 > ],
5694 > enumDescriptions: [
5695 > nls.localize('dropIntoEditor.showDropSelector.afterDrop', "Show the drop selector widget after a file is dropped into the editor."),
5696 > nls.localize('dropIntoEditor.showDropSelector.never', "Never show the drop selector widget. Instead the default drop provider is always used."),
5697 > ],
5698 > default: 'afterDrop',
5699 > },
5700 > }
5701 > );
5702 > }
5703 >
5704 > public validate(_input: unknown): EditorDropIntoEditorOptions {
5705 if (!_input || typeof _input !== 'object') {
5706 return this.defaultValue;
5712 };
5713 }
5714 > } editorOptions.ts
5715 >
5716 > //#endregion
5717 >
5718 > //#region pasteAs
5719 >
5720 > /**
5721 > * Configuration options for editor pasting as into behavior
5722 > */
5723 > export interface IPasteAsOptions {
5724 > /**
5725 > * Enable paste as functionality in editors.
5726 > * Defaults to true.
5727 > */
5728 > enabled?: boolean;
5729 >
5730 > /**
5731 > * Controls if a widget is shown after a drop.
5732 > * Defaults to 'afterPaste'.
5733 > */
5734 > showPasteSelector?: 'afterPaste' | 'never';
5735 > }
5736 >
5737 > /**
5738 > * @internal
5739 > */
5740 > export type EditorPasteAsOptions = Readonly<Required<IPasteAsOptions>>;
5741 >
5742 > class EditorPasteAs extends BaseEditorOption<EditorOption.pasteAs, IPasteAsOptions, EditorPasteAsOptions> {
5743 >
5744 > constructor() {
5745 > const defaults: EditorPasteAsOptions = { enabled: true, showPasteSelector: 'afterPaste' };
5746 > super(
5747 > EditorOption.pasteAs, 'pasteAs', defaults,
5748 > {
5749 > 'editor.pasteAs.enabled': {
5750 > type: 'boolean',
5751 > default: defaults.enabled,
5752 > markdownDescription: nls.localize('pasteAs.enabled', "Controls whether you can paste content in different ways."),
5753 > },
5754 > 'editor.pasteAs.showPasteSelector': {
5755 > type: 'string',
5756 > markdownDescription: nls.localize('pasteAs.showPasteSelector', "Controls if a widget is shown when pasting content in to the editor. This widget lets you control how the file is pasted."),
5757 > enum: [
5758 > 'afterPaste',
5759 > 'never'
5760 > ],
5761 > enumDescriptions: [
5762 > nls.localize('pasteAs.showPasteSelector.afterPaste', "Show the paste selector widget after content is pasted into the editor."),
5763 > nls.localize('pasteAs.showPasteSelector.never', "Never show the paste selector widget. Instead the default pasting behavior is always used."),
5764 > ],
5765 > default: 'afterPaste',
5766 > },
5767 > }
5768 > );
5769 > }
5770 >
5771 > public validate(_input: unknown): EditorPasteAsOptions {
5772 if (!_input || typeof _input !== 'object') {
5773 return this.defaultValue;
5779 };
5780 }
5781 > } editorOptions.ts
5782 >
5783 > //#endregion
5784 >
5785 > /**
5786 > * @internal
5787 > */
5788 > export const editorOptionsRegistry: IEditorOption<EditorOption, unknown>[] = [];
5789 >
5790 > function register<K extends EditorOption, V>(option: IEditorOption<K, V>): IEditorOption<K, V> {
5791 > editorOptionsRegistry[option.id] = option;
5792 > return option;
5793 > }
5794 >
5795 > export const enum EditorOption {
5796 > acceptSuggestionOnCommitCharacter,
5797 > acceptSuggestionOnEnter,
5798 > accessibilitySupport,
5799 > accessibilityPageSize,
5800 > allowOverflow,
5801 > allowVariableLineHeights,
5802 > allowVariableFonts,
5803 > allowVariableFontsInAccessibilityMode,
5804 > ariaLabel,
5805 > ariaRequired,
5806 > autoClosingBrackets,
5807 > autoClosingComments,
5808 > screenReaderAnnounceInlineSuggestion,
5809 > autoClosingDelete,
5810 > autoClosingOvertype,
5811 > autoClosingQuotes,
5812 > autoIndent,
5813 > autoIndentOnPaste,
5814 > autoIndentOnPasteWithinString,
5815 > automaticLayout,
5816 > autoSurround,
5817 > bracketPairColorization,
5818 > guides,
5819 > codeLens,
5820 > codeLensFontFamily,
5821 > codeLensFontSize,
5822 > colorDecorators,
5823 > colorDecoratorsLimit,
5824 > columnSelection,
5825 > comments,
5826 > contextmenu,
5827 > copyWithSyntaxHighlighting,
5828 > cursorBlinking,
5829 > cursorSmoothCaretAnimation,
5830 > cursorStyle,
5831 > cursorSurroundingLines,
5832 > cursorSurroundingLinesStyle,
5833 > cursorWidth,
5834 > cursorHeight,
5835 > disableLayerHinting,
5836 > disableMonospaceOptimizations,
5837 > domReadOnly,
5838 > dragAndDrop,
5839 > dropIntoEditor,
5840 > editContext,
5841 > emptySelectionClipboard,
5842 > experimentalGpuAcceleration,
5843 > experimentalWhitespaceRendering,
5844 > extraEditorClassName,
5845 > fastScrollSensitivity,
5846 > find,
5847 > fixedOverflowWidgets,
5848 > folding,
5849 > foldingStrategy,
5850 > foldingHighlight,
5851 > foldingImportsByDefault,
5852 > foldingMaximumRegions,
5853 > unfoldOnClickAfterEndOfLine,
5854 > fontFamily,
5855 > fontInfo,
5856 > fontLigatures,
5857 > fontSize,
5858 > fontWeight,
5859 > fontVariations,
5860 > formatOnPaste,
5861 > formatOnType,
5862 > glyphMargin,
5863 > gotoLocation,
5864 > hideCursorInOverviewRuler,
5865 > hover,
5866 > inDiffEditor,
5867 > inlineSuggest,
5868 > letterSpacing,
5869 > lightbulb,
5870 > lineDecorationsWidth,
5871 > lineHeight,
5872 > lineNumbers,
5873 > lineNumbersMinChars,
5874 > linkedEditing,
5875 > links,
5876 > matchBrackets,
5877 > minimap,
5878 > mouseStyle,
5879 > mouseWheelScrollSensitivity,
5880 > mouseWheelZoom,
5881 > multiCursorMergeOverlapping,
5882 > multiCursorModifier,
5883 > mouseMiddleClickAction,
5884 > multiCursorPaste,
5885 > multiCursorLimit,
5886 > occurrencesHighlight,
5887 > occurrencesHighlightDelay,
5888 > overtypeCursorStyle,
5889 > overtypeOnPaste,
5890 > overviewRulerBorder,
5891 > overviewRulerLanes,
5892 > padding,
5893 > pasteAs,
5894 > parameterHints,
5895 > peekWidgetDefaultFocus,
5896 > placeholder,
5897 > definitionLinkOpensInPeek,
5898 > quickSuggestions,
5899 > quickSuggestionsDelay,
5900 > readOnly,
5901 > readOnlyMessage,
5902 > renameOnType,
5903 > renderRichScreenReaderContent,
5904 > renderControlCharacters,
5905 > renderFinalNewline,
5906 > renderLineHighlight,
5907 > renderLineHighlightOnlyWhenFocus,
5908 > renderValidationDecorations,
5909 > renderWhitespace,
5910 > revealHorizontalRightPadding,
5911 > roundedSelection,
5912 > rulers,
5913 > scrollbar,
5914 > scrollBeyondLastColumn,
5915 > scrollBeyondLastLine,
5916 > scrollPredominantAxis,
5917 > selectionClipboard,
5918 > selectionHighlight,
5919 > selectionHighlightMaxLength,
5920 > selectionHighlightMultiline,
5921 > selectOnLineNumbers,
5922 > showFoldingControls,
5923 > showUnused,
5924 > snippetSuggestions,
5925 > smartSelect,
5926 > smoothScrolling,
5927 > stickyScroll,
5928 > stickyTabStops,
5929 > stopRenderingLineAfter,
5930 > suggest,
5931 > suggestFontSize,
5932 > suggestLineHeight,
5933 > suggestOnTriggerCharacters,
5934 > suggestSelection,
5935 > tabCompletion,
5936 > tabIndex,
5937 > trimWhitespaceOnDelete,
5938 > unicodeHighlighting,
5939 > unusualLineTerminators,
5940 > useShadowDOM,
5941 > useTabStops,
5942 > wordBreak,
5943 > wordSegmenterLocales,
5944 > wordSeparators,
5945 > wordWrap,
5946 > wordWrapBreakAfterCharacters,
5947 > wordWrapBreakBeforeCharacters,
5948 > wordWrapColumn,
5949 > wordWrapOverride1,
5950 > wordWrapOverride2,
5951 > wrappingIndent,
5952 > wrappingStrategy,
5953 > showDeprecated,
5954 > inertialScroll,
5955 > inlayHints,
5956 > wrapOnEscapedLineFeeds,
5957 > // Leave these at the end (because they have dependencies!)
5958 > effectiveCursorStyle,
5959 > editorClassName,
5960 > pixelRatio,
5961 > tabFocusMode,
5962 > layoutInfo,
5963 > wrappingInfo,
5964 > defaultColorDecorators,
5965 > colorDecoratorsActivatedOn,
5966 > inlineCompletionsAccessibilityVerbose,
5967 > effectiveEditContext,
5968 > scrollOnMiddleClick,
5969 > effectiveAllowVariableFonts,
5970 > doubleClickSelectsBlock
5971 > }
5972 >
5973 > export const EditorOptions = {
5974 > acceptSuggestionOnCommitCharacter: register(new EditorBooleanOption(
5975 > EditorOption.acceptSuggestionOnCommitCharacter, 'acceptSuggestionOnCommitCharacter', true,
5976 > { markdownDescription: nls.localize('acceptSuggestionOnCommitCharacter', "Controls whether suggestions should be accepted on commit characters. For example, in JavaScript, the semi-colon (`;`) can be a commit character that accepts a suggestion and types that character.") }
5977 > )),
5978 > acceptSuggestionOnEnter: register(new EditorStringEnumOption(
5979 > EditorOption.acceptSuggestionOnEnter, 'acceptSuggestionOnEnter',
5980 > 'on' as 'on' | 'smart' | 'off',
5981 > ['on', 'smart', 'off'] as const,
5982 > {
5983 > markdownEnumDescriptions: [
5984 > '',
5985 > nls.localize('acceptSuggestionOnEnterSmart', "Only accept a suggestion with `Enter` when it makes a textual change."),
5986 > ''
5987 > ],
5988 > markdownDescription: nls.localize('acceptSuggestionOnEnter', "Controls whether suggestions should be accepted on `Enter`, in addition to `Tab`. Helps to avoid ambiguity between inserting new lines or accepting suggestions.")
5989 > }
5990 > )),
5991 > accessibilitySupport: register(new EditorAccessibilitySupport()),
5992 > accessibilityPageSize: register(new EditorIntOption(EditorOption.accessibilityPageSize, 'accessibilityPageSize', 500, 1, Constants.MAX_SAFE_SMALL_INTEGER,
5993 > {
5994 > description: nls.localize('accessibilityPageSize', "Controls the number of lines in the editor that can be read out by a screen reader at once. When we detect a screen reader we automatically set the default to be 500. Warning: this has a performance implication for numbers larger than the default."),
5995 > tags: ['accessibility']
5996 > }
5997 > )),
5998 > allowOverflow: register(new EditorBooleanOption(
5999 > EditorOption.allowOverflow, 'allowOverflow', true,
6000 > )),
6001 > allowVariableLineHeights: register(new EditorBooleanOption(
6002 > EditorOption.allowVariableLineHeights, 'allowVariableLineHeights', true,
6003 > {
6004 > description: nls.localize('allowVariableLineHeights', "Controls whether to allow using variable line heights in the editor.")
6005 > }
6006 > )),
6007 > allowVariableFonts: register(new EditorBooleanOption(
6008 > EditorOption.allowVariableFonts, 'allowVariableFonts', true,
6009 > {
6010 > description: nls.localize('allowVariableFonts', "Controls whether to allow using variable fonts in the editor.")
6011 > }
6012 > )),
6013 > allowVariableFontsInAccessibilityMode: register(new EditorBooleanOption(
6014 > EditorOption.allowVariableFontsInAccessibilityMode, 'allowVariableFontsInAccessibilityMode', false,
6015 > {
6016 > description: nls.localize('allowVariableFontsInAccessibilityMode', "Controls whether to allow using variable fonts in the editor in the accessibility mode."),
6017 > tags: ['accessibility']
6018 > }
6019 > )),
6020 > ariaLabel: register(new EditorStringOption(
6021 > EditorOption.ariaLabel, 'ariaLabel', nls.localize('editorViewAccessibleLabel', "Editor content")
6022 > )),
6023 > ariaRequired: register(new EditorBooleanOption(
6024 > EditorOption.ariaRequired, 'ariaRequired', false, undefined
6025 > )),
6026 > screenReaderAnnounceInlineSuggestion: register(new EditorBooleanOption(
6027 > EditorOption.screenReaderAnnounceInlineSuggestion, 'screenReaderAnnounceInlineSuggestion', true,
6028 > {
6029 > description: nls.localize('screenReaderAnnounceInlineSuggestion', "Control whether inline suggestions are announced by a screen reader."),
6030 > tags: ['accessibility']
6031 > }
6032 > )),
6033 > autoClosingBrackets: register(new EditorStringEnumOption(
6034 > EditorOption.autoClosingBrackets, 'autoClosingBrackets',
6035 > 'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never',
6036 > ['always', 'languageDefined', 'beforeWhitespace', 'never'] as const,
6037 > {
6038 > enumDescriptions: [
6039 > '',
6040 > nls.localize('editor.autoClosingBrackets.languageDefined', "Use language configurations to determine when to autoclose brackets."),
6041 > nls.localize('editor.autoClosingBrackets.beforeWhitespace', "Autoclose brackets only when the cursor is to the left of whitespace."),
6042 > '',
6043 > ],
6044 > description: nls.localize('autoClosingBrackets', "Controls whether the editor should automatically close brackets after the user adds an opening bracket.")
6045 > }
6046 > )),
6047 > autoClosingComments: register(new EditorStringEnumOption(
6048 > EditorOption.autoClosingComments, 'autoClosingComments',
6049 > 'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never',
6050 > ['always', 'languageDefined', 'beforeWhitespace', 'never'] as const,
6051 > {
6052 > enumDescriptions: [
6053 > '',
6054 > nls.localize('editor.autoClosingComments.languageDefined', "Use language configurations to determine when to autoclose comments."),
6055 > nls.localize('editor.autoClosingComments.beforeWhitespace', "Autoclose comments only when the cursor is to the left of whitespace."),
6056 > '',
6057 > ],
6058 > description: nls.localize('autoClosingComments', "Controls whether the editor should automatically close comments after the user adds an opening comment.")
6059 > }
6060 > )),
6061 > autoClosingDelete: register(new EditorStringEnumOption(
6062 > EditorOption.autoClosingDelete, 'autoClosingDelete',
6063 > 'auto' as 'always' | 'auto' | 'never',
6064 > ['always', 'auto', 'never'] as const,
6065 > {
6066 > enumDescriptions: [
6067 > '',
6068 > nls.localize('editor.autoClosingDelete.auto', "Remove adjacent closing quotes or brackets only if they were automatically inserted."),
6069 > '',
6070 > ],
6071 > description: nls.localize('autoClosingDelete', "Controls whether the editor should remove adjacent closing quotes or brackets when deleting.")
6072 > }
6073 > )),
6074 > autoClosingOvertype: register(new EditorStringEnumOption(
6075 > EditorOption.autoClosingOvertype, 'autoClosingOvertype',
6076 > 'auto' as 'always' | 'auto' | 'never',
6077 > ['always', 'auto', 'never'] as const,
6078 > {
6079 > enumDescriptions: [
6080 > '',
6081 > nls.localize('editor.autoClosingOvertype.auto', "Type over closing quotes or brackets only if they were automatically inserted."),
6082 > '',
6083 > ],
6084 > description: nls.localize('autoClosingOvertype', "Controls whether the editor should type over closing quotes or brackets.")
6085 > }
6086 > )),
6087 > autoClosingQuotes: register(new EditorStringEnumOption(
6088 > EditorOption.autoClosingQuotes, 'autoClosingQuotes',
6089 > 'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never',
6090 > ['always', 'languageDefined', 'beforeWhitespace', 'never'] as const,
6091 > {
6092 > enumDescriptions: [
6093 > '',
6094 > nls.localize('editor.autoClosingQuotes.languageDefined', "Use language configurations to determine when to autoclose quotes."),
6095 > nls.localize('editor.autoClosingQuotes.beforeWhitespace', "Autoclose quotes only when the cursor is to the left of whitespace."),
6096 > '',
6097 > ],
6098 > description: nls.localize('autoClosingQuotes', "Controls whether the editor should automatically close quotes after the user adds an opening quote.")
6099 > }
6100 > )),
6101 > autoIndent: register(new EditorEnumOption(
6102 > EditorOption.autoIndent, 'autoIndent',
6103 > EditorAutoIndentStrategy.Full, 'full',
6104 > ['none', 'keep', 'brackets', 'advanced', 'full'],
6105 > _autoIndentFromString,
6106 > {
6107 > enumDescriptions: [
6108 > nls.localize('editor.autoIndent.none', "The editor will not insert indentation automatically."),
6109 > nls.localize('editor.autoIndent.keep', "The editor will keep the current line's indentation."),
6110 > nls.localize('editor.autoIndent.brackets', "The editor will keep the current line's indentation and honor language defined brackets."),
6111 > nls.localize('editor.autoIndent.advanced', "The editor will keep the current line's indentation, honor language defined brackets and invoke special onEnterRules defined by languages."),
6112 > nls.localize('editor.autoIndent.full', "The editor will keep the current line's indentation, honor language defined brackets, invoke special onEnterRules defined by languages, and honor indentationRules defined by languages."),
6113 > ],
6114 > description: nls.localize('autoIndent', "Controls whether the editor should automatically adjust the indentation when users type, paste, move or indent lines.")
6115 > }
6116 > )),
6117 > autoIndentOnPaste: register(new EditorBooleanOption(
6118 > EditorOption.autoIndentOnPaste, 'autoIndentOnPaste', false,
6119 > { description: nls.localize('autoIndentOnPaste', "Controls whether the editor should automatically auto-indent the pasted content.") }
6120 > )),
6121 > autoIndentOnPasteWithinString: register(new EditorBooleanOption(
6122 > EditorOption.autoIndentOnPasteWithinString, 'autoIndentOnPasteWithinString', true,
6123 > { description: nls.localize('autoIndentOnPasteWithinString', "Controls whether the editor should automatically auto-indent the pasted content when pasted within a string. This takes effect when autoIndentOnPaste is true.") }
6124 > )),
6125 > automaticLayout: register(new EditorBooleanOption(
6126 > EditorOption.automaticLayout, 'automaticLayout', false,
6127 > )),
6128 > autoSurround: register(new EditorStringEnumOption(
6129 > EditorOption.autoSurround, 'autoSurround',
6130 > 'languageDefined' as 'languageDefined' | 'quotes' | 'brackets' | 'never',
6131 > ['languageDefined', 'quotes', 'brackets', 'never'] as const,
6132 > {
6133 > enumDescriptions: [
6134 > nls.localize('editor.autoSurround.languageDefined', "Use language configurations to determine when to automatically surround selections."),
6135 > nls.localize('editor.autoSurround.quotes', "Surround with quotes but not brackets."),
6136 > nls.localize('editor.autoSurround.brackets', "Surround with brackets but not quotes."),
6137 > ''
6138 > ],
6139 > description: nls.localize('autoSurround', "Controls whether the editor should automatically surround selections when typing quotes or brackets.")
6140 > }
6141 > )),
6142 > bracketPairColorization: register(new BracketPairColorization()),
6143 > bracketPairGuides: register(new GuideOptions()),
6144 > stickyTabStops: register(new EditorBooleanOption(
6145 > EditorOption.stickyTabStops, 'stickyTabStops', false,
6146 > { description: nls.localize('stickyTabStops', "Emulate selection behavior of tab characters when using spaces for indentation. Selection will stick to tab stops.") }
6147 > )),
6148 > codeLens: register(new EditorBooleanOption(
6149 > EditorOption.codeLens, 'codeLens', true,
6150 > { description: nls.localize('codeLens', "Controls whether the editor shows CodeLens.") }
6151 > )),
6152 > codeLensFontFamily: register(new EditorStringOption(
6153 > EditorOption.codeLensFontFamily, 'codeLensFontFamily', '',
6154 > { description: nls.localize('codeLensFontFamily', "Controls the font family for CodeLens.") }
6155 > )),
6156 > codeLensFontSize: register(new EditorIntOption(EditorOption.codeLensFontSize, 'codeLensFontSize', 0, 0, 100, {
6157 > type: 'number',
6158 > default: 0,
6159 > minimum: 0,
6160 > maximum: 100,
6161 > markdownDescription: nls.localize('codeLensFontSize', "Controls the font size in pixels for CodeLens. When set to 0, 90% of `#editor.fontSize#` is used.")
6162 > })),
6163 > colorDecorators: register(new EditorBooleanOption(
6164 > EditorOption.colorDecorators, 'colorDecorators', true,
6165 > { description: nls.localize('colorDecorators', "Controls whether the editor should render the inline color decorators and color picker.") }
6166 > )),
6167 > colorDecoratorActivatedOn: register(new EditorStringEnumOption(EditorOption.colorDecoratorsActivatedOn, 'colorDecoratorsActivatedOn', 'clickAndHover' as 'clickAndHover' | 'hover' | 'click', ['clickAndHover', 'hover', 'click'] as const, {
6168 > enumDescriptions: [
6169 > nls.localize('editor.colorDecoratorActivatedOn.clickAndHover', "Make the color picker appear both on click and hover of the color decorator"),
6170 > nls.localize('editor.colorDecoratorActivatedOn.hover', "Make the color picker appear on hover of the color decorator"),
6171 > nls.localize('editor.colorDecoratorActivatedOn.click', "Make the color picker appear on click of the color decorator")
6172 > ],
6173 > description: nls.localize('colorDecoratorActivatedOn', "Controls the condition to make a color picker appear from a color decorator.")
6174 > })),
6175 > colorDecoratorsLimit: register(new EditorIntOption(
6176 > EditorOption.colorDecoratorsLimit, 'colorDecoratorsLimit', 500, 1, 1000000,
6177 > {
6178 > markdownDescription: nls.localize('colorDecoratorsLimit', "Controls the max number of color decorators that can be rendered in an editor at once.")
6179 > }
6180 > )),
6181 > columnSelection: register(new EditorBooleanOption(
6182 > EditorOption.columnSelection, 'columnSelection', false,
6183 > { description: nls.localize('columnSelection', "Enable that the selection with the mouse and keys is doing column selection.") }
6184 > )),
6185 > comments: register(new EditorComments()),
6186 > contextmenu: register(new EditorBooleanOption(
6187 > EditorOption.contextmenu, 'contextmenu', true,
6188 > )),
6189 > copyWithSyntaxHighlighting: register(new EditorBooleanOption(
6190 > EditorOption.copyWithSyntaxHighlighting, 'copyWithSyntaxHighlighting', true,
6191 > { description: nls.localize('copyWithSyntaxHighlighting', "Controls whether syntax highlighting should be copied into the clipboard.") }
6192 > )),
6193 > cursorBlinking: register(new EditorEnumOption(
6194 > EditorOption.cursorBlinking, 'cursorBlinking',
6195 > TextEditorCursorBlinkingStyle.Blink, 'blink',
6196 > ['blink', 'smooth', 'phase', 'expand', 'solid'],
6197 > cursorBlinkingStyleFromString,
6198 > { description: nls.localize('cursorBlinking', "Control the cursor animation style.") }
6199 > )),
6200 > cursorSmoothCaretAnimation: register(new EditorStringEnumOption(
6201 > EditorOption.cursorSmoothCaretAnimation, 'cursorSmoothCaretAnimation',
6202 > 'off' as 'off' | 'explicit' | 'on',
6203 > ['off', 'explicit', 'on'] as const,
6204 > {
6205 > enumDescriptions: [
6206 > nls.localize('cursorSmoothCaretAnimation.off', "Smooth caret animation is disabled."),
6207 > nls.localize('cursorSmoothCaretAnimation.explicit', "Smooth caret animation is enabled only when the user moves the cursor with an explicit gesture."),
6208 > nls.localize('cursorSmoothCaretAnimation.on', "Smooth caret animation is always enabled.")
6209 > ],
6210 > description: nls.localize('cursorSmoothCaretAnimation', "Controls whether the smooth caret animation should be enabled.")
6211 > }
6212 > )),
6213 > cursorStyle: register(new EditorEnumOption(
6214 > EditorOption.cursorStyle, 'cursorStyle',
6215 > TextEditorCursorStyle.Line, 'line',
6216 > ['line', 'block', 'underline', 'line-thin', 'block-outline', 'underline-thin'],
6217 > cursorStyleFromString,
6218 > { description: nls.localize('cursorStyle', "Controls the cursor style in insert input mode.") }
6219 > )),
6220 > overtypeCursorStyle: register(new EditorEnumOption(
6221 > EditorOption.overtypeCursorStyle, 'overtypeCursorStyle',
6222 > TextEditorCursorStyle.Block, 'block',
6223 > ['line', 'block', 'underline', 'line-thin', 'block-outline', 'underline-thin'],
6224 > cursorStyleFromString,
6225 > { description: nls.localize('overtypeCursorStyle', "Controls the cursor style in overtype input mode.") }
6226 > )),
6227 > cursorSurroundingLines: register(new EditorIntOption(
6228 > EditorOption.cursorSurroundingLines, 'cursorSurroundingLines',
6229 > 0, 0, Constants.MAX_SAFE_SMALL_INTEGER,
6230 > { description: nls.localize('cursorSurroundingLines', "Controls the minimal number of visible leading lines (minimum 0) and trailing lines (minimum 1) surrounding the cursor. Known as 'scrollOff' or 'scrollOffset' in some other editors.") }
6231 > )),
6232 > cursorSurroundingLinesStyle: register(new EditorStringEnumOption(
6233 > EditorOption.cursorSurroundingLinesStyle, 'cursorSurroundingLinesStyle',
6234 > 'default' as 'default' | 'all',
6235 > ['default', 'all'] as const,
6236 > {
6237 > enumDescriptions: [
6238 > nls.localize('cursorSurroundingLinesStyle.default', "`cursorSurroundingLines` is enforced only when triggered via the keyboard or API."),
6239 > nls.localize('cursorSurroundingLinesStyle.all', "`cursorSurroundingLines` is enforced always.")
6240 > ],
6241 > markdownDescription: nls.localize('cursorSurroundingLinesStyle', "Controls when `#editor.cursorSurroundingLines#` should be enforced.")
6242 > }
6243 > )),
6244 > cursorWidth: register(new EditorIntOption(
6245 > EditorOption.cursorWidth, 'cursorWidth',
6246 > 0, 0, Constants.MAX_SAFE_SMALL_INTEGER,
6247 > { markdownDescription: nls.localize('cursorWidth', "Controls the width of the cursor when `#editor.cursorStyle#` is set to `line`.") }
6248 > )),
6249 > cursorHeight: register(new EditorIntOption(
6250 > EditorOption.cursorHeight, 'cursorHeight',
6251 > 0, 0, Constants.MAX_SAFE_SMALL_INTEGER,
6252 > { markdownDescription: nls.localize('cursorHeight', "Controls the height of the cursor when `#editor.cursorStyle#` is set to `line`. Cursor's max height depends on line height.") }
6253 > )),
6254 > disableLayerHinting: register(new EditorBooleanOption(
6255 > EditorOption.disableLayerHinting, 'disableLayerHinting', false,
6256 > )),
6257 > disableMonospaceOptimizations: register(new EditorBooleanOption(
6258 > EditorOption.disableMonospaceOptimizations, 'disableMonospaceOptimizations', false
6259 > )),
6260 > domReadOnly: register(new EditorBooleanOption(
6261 > EditorOption.domReadOnly, 'domReadOnly', false,
6262 > )),
6263 > doubleClickSelectsBlock: register(new EditorBooleanOption(
6264 > EditorOption.doubleClickSelectsBlock, 'doubleClickSelectsBlock', true,
6265 > { description: nls.localize('doubleClickSelectsBlock', "Controls whether double-clicking next to a bracket or quote selects the content inside.") }
6266 > )),
6267 > dragAndDrop: register(new EditorBooleanOption(
6268 > EditorOption.dragAndDrop, 'dragAndDrop', true,
6269 > { description: nls.localize('dragAndDrop', "Controls whether the editor should allow moving selections via drag and drop.") }
6270 > )),
6271 > emptySelectionClipboard: register(new EditorEmptySelectionClipboard()),
6272 > dropIntoEditor: register(new EditorDropIntoEditor()),
6273 > editContext: register(new EditorBooleanOption(
6274 > EditorOption.editContext, 'editContext', true,
6275 > {
6276 > description: nls.localize('editContext', "Sets whether the EditContext API should be used instead of the text area to power input in the editor."),
6277 > included: platform.isChrome || platform.isEdge || platform.isNative
6278 > }
6279 > )),
6280 > renderRichScreenReaderContent: register(new EditorBooleanOption(
6281 > EditorOption.renderRichScreenReaderContent, 'renderRichScreenReaderContent', false,
6282 > {
6283 > markdownDescription: nls.localize('renderRichScreenReaderContent', "Whether to render rich screen reader content when the `#editor.editContext#` setting is enabled."),
6284 > }
6285 > )),
6286 > stickyScroll: register(new EditorStickyScroll()),
6287 > experimentalGpuAcceleration: register(new EditorStringEnumOption(
6288 > EditorOption.experimentalGpuAcceleration, 'experimentalGpuAcceleration',
6289 > 'off' as 'off' | 'on',
6290 > ['off', 'on'] as const,
6291 > {
6292 > tags: ['experimental'],
6293 > enumDescriptions: [
6294 > nls.localize('experimentalGpuAcceleration.off', "Use regular DOM-based rendering."),
6295 > nls.localize('experimentalGpuAcceleration.on', "Use GPU acceleration."),
6296 > ],
6297 > description: nls.localize('experimentalGpuAcceleration', "Controls whether to use the experimental GPU acceleration to render the editor.")
6298 > }
6299 > )),
6300 > experimentalWhitespaceRendering: register(new EditorStringEnumOption(
6301 > EditorOption.experimentalWhitespaceRendering, 'experimentalWhitespaceRendering',
6302 > 'svg' as 'svg' | 'font' | 'off',
6303 > ['svg', 'font', 'off'] as const,
6304 > {
6305 > enumDescriptions: [
6306 > nls.localize('experimentalWhitespaceRendering.svg', "Use a new rendering method with svgs."),
6307 > nls.localize('experimentalWhitespaceRendering.font', "Use a new rendering method with font characters."),
6308 > nls.localize('experimentalWhitespaceRendering.off', "Use the stable rendering method."),
6309 > ],
6310 > description: nls.localize('experimentalWhitespaceRendering', "Controls whether whitespace is rendered with a new, experimental method.")
6311 > }
6312 > )),
6313 > extraEditorClassName: register(new EditorStringOption(
6314 > EditorOption.extraEditorClassName, 'extraEditorClassName', '',
6315 > )),
6316 > fastScrollSensitivity: register(new EditorFloatOption(
6317 > EditorOption.fastScrollSensitivity, 'fastScrollSensitivity',
6318 > 5, x => (x <= 0 ? 5 : x),
6319 > { markdownDescription: nls.localize('fastScrollSensitivity', "Scrolling speed multiplier when pressing `Alt`.") }
6320 > )),
6321 > find: register(new EditorFind()),
6322 > fixedOverflowWidgets: register(new EditorBooleanOption(
6323 > EditorOption.fixedOverflowWidgets, 'fixedOverflowWidgets', false,
6324 > )),
6325 > folding: register(new EditorBooleanOption(
6326 > EditorOption.folding, 'folding', true,
6327 > { description: nls.localize('folding', "Controls whether the editor has code folding enabled.") }
6328 > )),
6329 > foldingStrategy: register(new EditorStringEnumOption(
6330 > EditorOption.foldingStrategy, 'foldingStrategy',
6331 > 'auto' as 'auto' | 'indentation',
6332 > ['auto', 'indentation'] as const,
6333 > {
6334 > enumDescriptions: [
6335 > nls.localize('foldingStrategy.auto', "Use a language-specific folding strategy if available, else the indentation-based one."),
6336 > nls.localize('foldingStrategy.indentation', "Use the indentation-based folding strategy."),
6337 > ],
6338 > description: nls.localize('foldingStrategy', "Controls the strategy for computing folding ranges.")
6339 > }
6340 > )),
6341 > foldingHighlight: register(new EditorBooleanOption(
6342 > EditorOption.foldingHighlight, 'foldingHighlight', true,
6343 > { description: nls.localize('foldingHighlight', "Controls whether the editor should highlight folded ranges.") }
6344 > )),
6345 > foldingImportsByDefault: register(new EditorBooleanOption(
6346 > EditorOption.foldingImportsByDefault, 'foldingImportsByDefault', false,
6347 > { description: nls.localize('foldingImportsByDefault', "Controls whether the editor automatically collapses import ranges.") }
6348 > )),
6349 > foldingMaximumRegions: register(new EditorIntOption(
6350 > EditorOption.foldingMaximumRegions, 'foldingMaximumRegions',
6351 > 5000, 10, 65000, // limit must be less than foldingRanges MAX_FOLDING_REGIONS
6352 > { description: nls.localize('foldingMaximumRegions', "The maximum number of foldable regions. Increasing this value may result in the editor becoming less responsive when the current source has a large number of foldable regions.") }
6353 > )),
6354 > unfoldOnClickAfterEndOfLine: register(new EditorBooleanOption(
6355 > EditorOption.unfoldOnClickAfterEndOfLine, 'unfoldOnClickAfterEndOfLine', false,
6356 > { description: nls.localize('unfoldOnClickAfterEndOfLine', "Controls whether clicking on the empty content after a folded line will unfold the line.") }
6357 > )),
6358 > fontFamily: register(new EditorStringOption(
6359 > EditorOption.fontFamily, 'fontFamily', EDITOR_FONT_DEFAULTS.fontFamily,
6360 > { description: nls.localize('fontFamily', "Controls the font family.") }
6361 > )),
6362 > fontInfo: register(new EditorFontInfo()),
6363 > fontLigatures2: register(new EditorFontLigatures()),
6364 > fontSize: register(new EditorFontSize()),
6365 > fontWeight: register(new EditorFontWeight()),
6366 > fontVariations: register(new EditorFontVariations()),
6367 > formatOnPaste: register(new EditorBooleanOption(
6368 > EditorOption.formatOnPaste, 'formatOnPaste', false,
6369 > { description: nls.localize('formatOnPaste', "Controls whether the editor should automatically format the pasted content. A formatter must be available and the formatter should be able to format a range in a document.") }
6370 > )),
6371 > formatOnType: register(new EditorBooleanOption(
6372 > EditorOption.formatOnType, 'formatOnType', false,
6373 > { description: nls.localize('formatOnType', "Controls whether the editor should automatically format the line after typing.") }
6374 > )),
6375 > glyphMargin: register(new EditorBooleanOption(
6376 > EditorOption.glyphMargin, 'glyphMargin', true,
6377 > { description: nls.localize('glyphMargin', "Controls whether the editor should render the vertical glyph margin. Glyph margin is mostly used for debugging.") }
6378 > )),
6379 > gotoLocation: register(new EditorGoToLocation()),
6380 > hideCursorInOverviewRuler: register(new EditorBooleanOption(
6381 > EditorOption.hideCursorInOverviewRuler, 'hideCursorInOverviewRuler', false,
6382 > { description: nls.localize('hideCursorInOverviewRuler', "Controls whether the cursor should be hidden in the overview ruler.") }
6383 > )),
6384 > hover: register(new EditorHover()),
6385 > inDiffEditor: register(new EditorBooleanOption(
6386 > EditorOption.inDiffEditor, 'inDiffEditor', false
6387 > )),
6388 > inertialScroll: register(new EditorBooleanOption(
6389 > EditorOption.inertialScroll, 'inertialScroll', false,
6390 > { description: nls.localize('inertialScroll', "Make scrolling inertial - mostly useful with touchpad on linux.") }
6391 > )),
6392 > letterSpacing: register(new EditorFloatOption(
6393 > EditorOption.letterSpacing, 'letterSpacing',
6394 > EDITOR_FONT_DEFAULTS.letterSpacing, x => EditorFloatOption.clamp(x, -5, 20),
6395 > { description: nls.localize('letterSpacing', "Controls the letter spacing in pixels.") }
6396 > )),
6397 > lightbulb: register(new EditorLightbulb()),
6398 > lineDecorationsWidth: register(new EditorLineDecorationsWidth()),
6399 > lineHeight: register(new EditorLineHeight()),
6400 > lineNumbers: register(new EditorRenderLineNumbersOption()),
6401 > lineNumbersMinChars: register(new EditorIntOption(
6402 > EditorOption.lineNumbersMinChars, 'lineNumbersMinChars',
6403 > 5, 1, 300
6404 > )),
6405 > linkedEditing: register(new EditorBooleanOption(
6406 > EditorOption.linkedEditing, 'linkedEditing', false,
6407 > { description: nls.localize('linkedEditing', "Controls whether the editor has linked editing enabled. Depending on the language, related symbols such as HTML tags, are updated while editing.") }
6408 > )),
6409 > links: register(new EditorBooleanOption(
6410 > EditorOption.links, 'links', true,
6411 > { description: nls.localize('links', "Controls whether the editor should detect links and make them clickable.") }
6412 > )),
6413 > matchBrackets: register(new EditorStringEnumOption(
6414 > EditorOption.matchBrackets, 'matchBrackets',
6415 > 'always' as 'never' | 'near' | 'always',
6416 > ['always', 'near', 'never'] as const,
6417 > { description: nls.localize('matchBrackets', "Highlight matching brackets.") }
6418 > )),
6419 > minimap: register(new EditorMinimap()),
6420 > mouseStyle: register(new EditorStringEnumOption(
6421 > EditorOption.mouseStyle, 'mouseStyle',
6422 > 'text' as 'text' | 'default' | 'copy',
6423 > ['text', 'default', 'copy'] as const,
6424 > )),
6425 > mouseWheelScrollSensitivity: register(new EditorFloatOption(
6426 > EditorOption.mouseWheelScrollSensitivity, 'mouseWheelScrollSensitivity',
6427 > 1, x => (x === 0 ? 1 : x),
6428 > { markdownDescription: nls.localize('mouseWheelScrollSensitivity', "A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.") }
6429 > )),
6430 > mouseWheelZoom: register(new EditorBooleanOption(
6431 > EditorOption.mouseWheelZoom, 'mouseWheelZoom', false,
6432 > {
6433 > markdownDescription: platform.isMacintosh
6434 ? nls.localize('mouseWheelZoom.mac', "Zoom the font of the editor when using mouse wheel and holding `Cmd`.")
6435 > : nls.localize('mouseWheelZoom', "Zoom the font of the editor when using mouse wheel and holding `Ctrl`.") editorOptions.ts
6436 > }
6437 > )),
6438 > multiCursorMergeOverlapping: register(new EditorBooleanOption(
6439 > EditorOption.multiCursorMergeOverlapping, 'multiCursorMergeOverlapping', true,
6440 > { description: nls.localize('multiCursorMergeOverlapping', "Merge multiple cursors when they are overlapping.") }
6441 > )),
6442 > multiCursorModifier: register(new EditorEnumOption(
6443 > EditorOption.multiCursorModifier, 'multiCursorModifier',
6444 > 'altKey', 'alt',
6445 > ['ctrlCmd', 'alt'],
6446 > _multiCursorModifierFromString,
6447 > {
6448 > markdownEnumDescriptions: [
6449 > nls.localize('multiCursorModifier.ctrlCmd', "Maps to `Control` on Windows and Linux and to `Command` on macOS."),
6450 > nls.localize('multiCursorModifier.alt', "Maps to `Alt` on Windows and Linux and to `Option` on macOS.")
6451 > ],
6452 > markdownDescription: nls.localize({
6453 > key: 'multiCursorModifier',
6454 > comment: [
6455 > '- `ctrlCmd` refers to a value the setting can take and should not be localized.',
6456 > '- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.'
6457 > ]
6458 > }, "The modifier to be used to add multiple cursors with the mouse. The Go to Definition and Open Link mouse gestures will adapt such that they do not conflict with the [multicursor modifier](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).")
6459 > }
6460 > )),
6461 > mouseMiddleClickAction: register(new EditorStringEnumOption(
6462 > EditorOption.mouseMiddleClickAction, 'mouseMiddleClickAction', 'default' as MouseMiddleClickAction,
6463 > ['default', 'openLink', 'ctrlLeftClick'] as MouseMiddleClickAction[],
6464 > { description: nls.localize('mouseMiddleClickAction', "Controls what happens when middle mouse button is clicked in the editor.") }
6465 > )),
6466 > multiCursorPaste: register(new EditorStringEnumOption(
6467 > EditorOption.multiCursorPaste, 'multiCursorPaste',
6468 > 'spread' as 'spread' | 'full',
6469 > ['spread', 'full'] as const,
6470 > {
6471 > markdownEnumDescriptions: [
6472 > nls.localize('multiCursorPaste.spread', "Each cursor pastes a single line of the text."),
6473 > nls.localize('multiCursorPaste.full', "Each cursor pastes the full text.")
6474 > ],
6475 > markdownDescription: nls.localize('multiCursorPaste', "Controls pasting when the line count of the pasted text matches the cursor count.")
6476 > }
6477 > )),
6478 > multiCursorLimit: register(new EditorIntOption(
6479 > EditorOption.multiCursorLimit, 'multiCursorLimit', 10000, 1, 100000,
6480 > {
6481 > markdownDescription: nls.localize('multiCursorLimit', "Controls the max number of cursors that can be in an active editor at once.")
6482 > }
6483 > )),
6484 > occurrencesHighlight: register(new EditorStringEnumOption(
6485 > EditorOption.occurrencesHighlight, 'occurrencesHighlight',
6486 > 'singleFile' as 'off' | 'singleFile' | 'multiFile',
6487 > ['off', 'singleFile', 'multiFile'] as const,
6488 > {
6489 > markdownEnumDescriptions: [
6490 > nls.localize('occurrencesHighlight.off', "Does not highlight occurrences."),
6491 > nls.localize('occurrencesHighlight.singleFile', "Highlights occurrences only in the current file."),
6492 > nls.localize('occurrencesHighlight.multiFile', "Experimental: Highlights occurrences across all valid open files.")
6493 > ],
6494 > markdownDescription: nls.localize('occurrencesHighlight', "Controls whether occurrences should be highlighted across open files.")
6495 > }
6496 > )),
6497 > occurrencesHighlightDelay: register(new EditorIntOption(
6498 > EditorOption.occurrencesHighlightDelay, 'occurrencesHighlightDelay',
6499 > 0, 0, 2000,
6500 > {
6501 > description: nls.localize('occurrencesHighlightDelay', "Controls the delay in milliseconds after which occurrences are highlighted."),
6502 > tags: ['preview']
6503 > }
6504 > )),
6505 > overtypeOnPaste: register(new EditorBooleanOption(
6506 > EditorOption.overtypeOnPaste, 'overtypeOnPaste', true,
6507 > { description: nls.localize('overtypeOnPaste', "Controls whether pasting should overtype.") }
6508 > )),
6509 > overviewRulerBorder: register(new EditorBooleanOption(
6510 > EditorOption.overviewRulerBorder, 'overviewRulerBorder', true,
6511 > { description: nls.localize('overviewRulerBorder', "Controls whether a border should be drawn around the overview ruler.") }
6512 > )),
6513 > overviewRulerLanes: register(new EditorIntOption(
6514 > EditorOption.overviewRulerLanes, 'overviewRulerLanes',
6515 > 3, 0, 3
6516 > )),
6517 > padding: register(new EditorPadding()),
6518 > pasteAs: register(new EditorPasteAs()),
6519 > parameterHints: register(new EditorParameterHints()),
6520 > peekWidgetDefaultFocus: register(new EditorStringEnumOption(
6521 > EditorOption.peekWidgetDefaultFocus, 'peekWidgetDefaultFocus',
6522 > 'tree' as 'tree' | 'editor',
6523 > ['tree', 'editor'] as const,
6524 > {
6525 > enumDescriptions: [
6526 > nls.localize('peekWidgetDefaultFocus.tree', "Focus the tree when opening peek"),
6527 > nls.localize('peekWidgetDefaultFocus.editor', "Focus the editor when opening peek")
6528 > ],
6529 > description: nls.localize('peekWidgetDefaultFocus', "Controls whether to focus the inline editor or the tree in the peek widget.")
6530 > }
6531 > )),
6532 > placeholder: register(new PlaceholderOption()),
6533 > definitionLinkOpensInPeek: register(new EditorBooleanOption(
6534 > EditorOption.definitionLinkOpensInPeek, 'definitionLinkOpensInPeek', false,
6535 > { description: nls.localize('definitionLinkOpensInPeek', "Controls whether the Go to Definition mouse gesture always opens the peek widget.") }
6536 > )),
6537 > quickSuggestions: register(new EditorQuickSuggestions()),
6538 > quickSuggestionsDelay: register(new EditorIntOption(
6539 > EditorOption.quickSuggestionsDelay, 'quickSuggestionsDelay',
6540 > 10, 0, Constants.MAX_SAFE_SMALL_INTEGER,
6541 > {
6542 > description: nls.localize('quickSuggestionsDelay', "Controls the delay in milliseconds after which quick suggestions will show up."),
6543 > experiment: {
6544 > mode: 'auto'
6545 > }
6546 > }
6547 > )),
6548 > readOnly: register(new EditorBooleanOption(
6549 > EditorOption.readOnly, 'readOnly', false,
6550 > )),
6551 > readOnlyMessage: register(new ReadonlyMessage()),
6552 > renameOnType: register(new EditorBooleanOption(
6553 > EditorOption.renameOnType, 'renameOnType', false,
6554 > { description: nls.localize('renameOnType', "Controls whether the editor auto renames on type."), markdownDeprecationMessage: nls.localize('renameOnTypeDeprecate', "Deprecated, use `#editor.linkedEditing#` instead.") }
6555 > )),
6556 > renderControlCharacters: register(new EditorBooleanOption(
6557 > EditorOption.renderControlCharacters, 'renderControlCharacters', true,
6558 > { description: nls.localize('renderControlCharacters', "Controls whether the editor should render control characters."), restricted: true }
6559 > )),
6560 > renderFinalNewline: register(new EditorStringEnumOption(
6561 > EditorOption.renderFinalNewline, 'renderFinalNewline',
6562 > (platform.isLinux ? 'dimmed' : 'on') as 'off' | 'on' | 'dimmed',
6563 > ['off', 'on', 'dimmed'] as const,
6564 > { description: nls.localize('renderFinalNewline', "Render last line number when the file ends with a newline.") }
6565 > )),
6566 > renderLineHighlight: register(new EditorStringEnumOption(
6567 > EditorOption.renderLineHighlight, 'renderLineHighlight',
6568 > 'line' as 'none' | 'gutter' | 'line' | 'all',
6569 > ['none', 'gutter', 'line', 'all'] as const,
6570 > {
6571 > enumDescriptions: [
6572 > '',
6573 > '',
6574 > '',
6575 > nls.localize('renderLineHighlight.all', "Highlights both the gutter and the current line."),
6576 > ],
6577 > description: nls.localize('renderLineHighlight', "Controls how the editor should render the current line highlight.")
6578 > }
6579 > )),
6580 > renderLineHighlightOnlyWhenFocus: register(new EditorBooleanOption(
6581 > EditorOption.renderLineHighlightOnlyWhenFocus, 'renderLineHighlightOnlyWhenFocus', false,
6582 > { description: nls.localize('renderLineHighlightOnlyWhenFocus', "Controls if the editor should render the current line highlight only when the editor is focused.") }
6583 > )),
6584 > renderValidationDecorations: register(new EditorStringEnumOption(
6585 > EditorOption.renderValidationDecorations, 'renderValidationDecorations',
6586 > 'editable' as 'editable' | 'on' | 'off',
6587 > ['editable', 'on', 'off'] as const
6588 > )),
6589 > renderWhitespace: register(new EditorStringEnumOption(
6590 > EditorOption.renderWhitespace, 'renderWhitespace',
6591 > 'selection' as 'selection' | 'none' | 'boundary' | 'trailing' | 'all',
6592 > ['none', 'boundary', 'selection', 'trailing', 'all'] as const,
6593 > {
6594 > enumDescriptions: [
6595 > '',
6596 > nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."),
6597 > nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."),
6598 > nls.localize('renderWhitespace.trailing', "Render only trailing whitespace characters."),
6599 > ''
6600 > ],
6601 > description: nls.localize('renderWhitespace', "Controls how the editor should render whitespace characters.")
6602 > }
6603 > )),
6604 > revealHorizontalRightPadding: register(new EditorIntOption(
6605 > EditorOption.revealHorizontalRightPadding, 'revealHorizontalRightPadding',
6606 > 15, 0, 1000,
6607 > )),
6608 > roundedSelection: register(new EditorBooleanOption(
6609 > EditorOption.roundedSelection, 'roundedSelection', true,
6610 > { description: nls.localize('roundedSelection', "Controls whether selections should have rounded corners.") }
6611 > )),
6612 > rulers: register(new EditorRulers()),
6613 > scrollbar: register(new EditorScrollbar()),
6614 > scrollBeyondLastColumn: register(new EditorIntOption(
6615 > EditorOption.scrollBeyondLastColumn, 'scrollBeyondLastColumn',
6616 > 4, 0, Constants.MAX_SAFE_SMALL_INTEGER,
6617 > { description: nls.localize('scrollBeyondLastColumn', "Controls the number of extra characters beyond which the editor will scroll horizontally.") }
6618 > )),
6619 > scrollBeyondLastLine: register(new EditorBooleanOption(
6620 > EditorOption.scrollBeyondLastLine, 'scrollBeyondLastLine', true,
6621 > { description: nls.localize('scrollBeyondLastLine', "Controls whether the editor will scroll beyond the last line.") }
6622 > )),
6623 > scrollOnMiddleClick: register(new EditorBooleanOption(
6624 > EditorOption.scrollOnMiddleClick, 'scrollOnMiddleClick', false,
6625 > { description: nls.localize('scrollOnMiddleClick', "Controls whether the editor will scroll when the middle button is pressed.") }
6626 > )),
6627 > scrollPredominantAxis: register(new EditorBooleanOption(
6628 > EditorOption.scrollPredominantAxis, 'scrollPredominantAxis', true,
6629 > { description: nls.localize('scrollPredominantAxis', "Scroll only along the predominant axis when scrolling both vertically and horizontally at the same time. Prevents horizontal drift when scrolling vertically on a trackpad.") }
6630 > )),
6631 > selectionClipboard: register(new EditorBooleanOption(
6632 > EditorOption.selectionClipboard, 'selectionClipboard', true,
6633 > {
6634 > description: nls.localize('selectionClipboard', "Controls whether the Linux primary clipboard should be supported."),
6635 > included: platform.isLinux
6636 > }
6637 > )),
6638 > selectionHighlight: register(new EditorBooleanOption(
6639 > EditorOption.selectionHighlight, 'selectionHighlight', true,
6640 > { description: nls.localize('selectionHighlight', "Controls whether the editor should highlight matches similar to the selection.") }
6641 > )),
6642 > selectionHighlightMaxLength: register(new EditorIntOption(
6643 > EditorOption.selectionHighlightMaxLength, 'selectionHighlightMaxLength',
6644 > 200, 0, Constants.MAX_SAFE_SMALL_INTEGER,
6645 > { description: nls.localize('selectionHighlightMaxLength', "Controls how many characters can be in the selection before similiar matches are not highlighted. Set to zero for unlimited.") }
6646 > )),
6647 > selectionHighlightMultiline: register(new EditorBooleanOption(
6648 > EditorOption.selectionHighlightMultiline, 'selectionHighlightMultiline', false,
6649 > { description: nls.localize('selectionHighlightMultiline', "Controls whether the editor should highlight selection matches that span multiple lines.") }
6650 > )),
6651 > selectOnLineNumbers: register(new EditorBooleanOption(
6652 > EditorOption.selectOnLineNumbers, 'selectOnLineNumbers', true,
6653 > )),
6654 > showFoldingControls: register(new EditorStringEnumOption(
6655 > EditorOption.showFoldingControls, 'showFoldingControls',
6656 > 'mouseover' as 'always' | 'never' | 'mouseover',
6657 > ['always', 'never', 'mouseover'] as const,
6658 > {
6659 > enumDescriptions: [
6660 > nls.localize('showFoldingControls.always', "Always show the folding controls."),
6661 > nls.localize('showFoldingControls.never', "Never show the folding controls and reduce the gutter size."),
6662 > nls.localize('showFoldingControls.mouseover', "Only show the folding controls when the mouse is over the gutter."),
6663 > ],
6664 > description: nls.localize('showFoldingControls', "Controls when the folding controls on the gutter are shown.")
6665 > }
6666 > )),
6667 > showUnused: register(new EditorBooleanOption(
6668 > EditorOption.showUnused, 'showUnused', true,
6669 > { description: nls.localize('showUnused', "Controls fading out of unused code.") }
6670 > )),
6671 > showDeprecated: register(new EditorBooleanOption(
6672 > EditorOption.showDeprecated, 'showDeprecated', true,
6673 > { description: nls.localize('showDeprecated', "Controls strikethrough deprecated variables.") }
6674 > )),
6675 > inlayHints: register(new EditorInlayHints()),
6676 > snippetSuggestions: register(new EditorStringEnumOption(
6677 > EditorOption.snippetSuggestions, 'snippetSuggestions',
6678 > 'inline' as 'top' | 'bottom' | 'inline' | 'none',
6679 > ['top', 'bottom', 'inline', 'none'] as const,
6680 > {
6681 > enumDescriptions: [
6682 > nls.localize('snippetSuggestions.top', "Show snippet suggestions on top of other suggestions."),
6683 > nls.localize('snippetSuggestions.bottom', "Show snippet suggestions below other suggestions."),
6684 > nls.localize('snippetSuggestions.inline', "Show snippets suggestions with other suggestions."),
6685 > nls.localize('snippetSuggestions.none', "Do not show snippet suggestions."),
6686 > ],
6687 > description: nls.localize('snippetSuggestions', "Controls whether snippets are shown with other suggestions and how they are sorted.")
6688 > }
6689 > )),
6690 > smartSelect: register(new SmartSelect()),
6691 > smoothScrolling: register(new EditorBooleanOption(
6692 > EditorOption.smoothScrolling, 'smoothScrolling', false,
6693 > { description: nls.localize('smoothScrolling', "Controls whether the editor will scroll using an animation.") }
6694 > )),
6695 > stopRenderingLineAfter: register(new EditorIntOption(
6696 > EditorOption.stopRenderingLineAfter, 'stopRenderingLineAfter',
6697 > 10000, -1, Constants.MAX_SAFE_SMALL_INTEGER,
6698 > )),
6699 > suggest: register(new EditorSuggest()),
6700 > inlineSuggest: register(new InlineEditorSuggest()),
6701 > inlineCompletionsAccessibilityVerbose: register(new EditorBooleanOption(EditorOption.inlineCompletionsAccessibilityVerbose, 'inlineCompletionsAccessibilityVerbose', false,
6702 > { description: nls.localize('inlineCompletionsAccessibilityVerbose', "Controls whether the accessibility hint should be provided to screen reader users when an inline completion is shown.") })),
6703 > suggestFontSize: register(new EditorIntOption(
6704 > EditorOption.suggestFontSize, 'suggestFontSize',
6705 > 0, 0, 1000,
6706 > { markdownDescription: nls.localize('suggestFontSize', "Font size for the suggest widget. When set to {0}, the value of {1} is used.", '`0`', '`#editor.fontSize#`') }
6707 > )),
6708 > suggestLineHeight: register(new EditorIntOption(
6709 > EditorOption.suggestLineHeight, 'suggestLineHeight',
6710 > 0, 0, 1000,
6711 > { markdownDescription: nls.localize('suggestLineHeight', "Line height for the suggest widget. When set to {0}, the value of {1} is used. The minimum value is 8.", '`0`', '`#editor.lineHeight#`') }
6712 > )),
6713 > suggestOnTriggerCharacters: register(new EditorBooleanOption(
6714 > EditorOption.suggestOnTriggerCharacters, 'suggestOnTriggerCharacters', true,
6715 > { description: nls.localize('suggestOnTriggerCharacters', "Controls whether suggestions should automatically show up when typing trigger characters.") }
6716 > )),
6717 > suggestSelection: register(new EditorStringEnumOption(
6718 > EditorOption.suggestSelection, 'suggestSelection',
6719 > 'first' as 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix',
6720 > ['first', 'recentlyUsed', 'recentlyUsedByPrefix'] as const,
6721 > {
6722 > markdownEnumDescriptions: [
6723 > nls.localize('suggestSelection.first', "Always select the first suggestion."),
6724 > nls.localize('suggestSelection.recentlyUsed', "Select recent suggestions unless further typing selects one, e.g. `console.| -> console.log` because `log` has been completed recently."),
6725 > nls.localize('suggestSelection.recentlyUsedByPrefix', "Select suggestions based on previous prefixes that have completed those suggestions, e.g. `co -> console` and `con -> const`."),
6726 > ],
6727 > description: nls.localize('suggestSelection', "Controls how suggestions are pre-selected when showing the suggest list.")
6728 > }
6729 > )),
6730 > tabCompletion: register(new EditorStringEnumOption(
6731 > EditorOption.tabCompletion, 'tabCompletion',
6732 > 'off' as 'on' | 'off' | 'onlySnippets',
6733 > ['on', 'off', 'onlySnippets'] as const,
6734 > {
6735 > enumDescriptions: [
6736 > nls.localize('tabCompletion.on', "Tab complete will insert the best matching suggestion when pressing tab."),
6737 > nls.localize('tabCompletion.off', "Disable tab completions."),
6738 > nls.localize('tabCompletion.onlySnippets', "Tab complete snippets when their prefix match. Works best when 'quickSuggestions' aren't enabled."),
6739 > ],
6740 > description: nls.localize('tabCompletion', "Enables tab completions.")
6741 > }
6742 > )),
6743 > tabIndex: register(new EditorIntOption(
6744 > EditorOption.tabIndex, 'tabIndex',
6745 > 0, -1, Constants.MAX_SAFE_SMALL_INTEGER
6746 > )),
6747 > trimWhitespaceOnDelete: register(new EditorBooleanOption(
6748 > EditorOption.trimWhitespaceOnDelete, 'trimWhitespaceOnDelete', false,
6749 > { description: nls.localize('trimWhitespaceOnDelete', "Controls whether the editor will also delete the next line's indentation whitespace when deleting a newline.") }
6750 > )),
6751 > unicodeHighlight: register(new UnicodeHighlight()),
6752 > unusualLineTerminators: register(new EditorStringEnumOption(
6753 > EditorOption.unusualLineTerminators, 'unusualLineTerminators',
6754 > 'prompt' as 'auto' | 'off' | 'prompt',
6755 > ['auto', 'off', 'prompt'] as const,
6756 > {
6757 > enumDescriptions: [
6758 > nls.localize('unusualLineTerminators.auto', "Unusual line terminators are automatically removed."),
6759 > nls.localize('unusualLineTerminators.off', "Unusual line terminators are ignored."),
6760 > nls.localize('unusualLineTerminators.prompt', "Unusual line terminators prompt to be removed."),
6761 > ],
6762 > description: nls.localize('unusualLineTerminators', "Remove unusual line terminators that might cause problems.")
6763 > }
6764 > )),
6765 > useShadowDOM: register(new EditorBooleanOption(
6766 > EditorOption.useShadowDOM, 'useShadowDOM', true
6767 > )),
6768 > useTabStops: register(new EditorBooleanOption(
6769 > EditorOption.useTabStops, 'useTabStops', true,
6770 > { description: nls.localize('useTabStops', "Spaces and tabs are inserted and deleted in alignment with tab stops.") }
6771 > )),
6772 > wordBreak: register(new EditorStringEnumOption(
6773 > EditorOption.wordBreak, 'wordBreak',
6774 > 'normal' as 'normal' | 'keepAll',
6775 > ['normal', 'keepAll'] as const,
6776 > {
6777 > markdownEnumDescriptions: [
6778 > nls.localize('wordBreak.normal', "Use the default line break rule."),
6779 > nls.localize('wordBreak.keepAll', "Word breaks should not be used for Chinese/Japanese/Korean (CJK) text. Non-CJK text behavior is the same as for normal."),
6780 > ],
6781 > description: nls.localize('wordBreak', "Controls the word break rules used for Chinese/Japanese/Korean (CJK) text.")
6782 > }
6783 > )),
6784 > wordSegmenterLocales: register(new WordSegmenterLocales()),
6785 > wordSeparators: register(new EditorStringOption(
6786 > EditorOption.wordSeparators, 'wordSeparators', USUAL_WORD_SEPARATORS,
6787 > { description: nls.localize('wordSeparators', "Characters that will be used as word separators when doing word related navigations or operations.") }
6788 > )),
6789 > wordWrap: register(new EditorStringEnumOption(
6790 > EditorOption.wordWrap, 'wordWrap',
6791 > 'off' as 'off' | 'on' | 'wordWrapColumn' | 'bounded',
6792 > ['off', 'on', 'wordWrapColumn', 'bounded'] as const,
6793 > {
6794 > markdownEnumDescriptions: [
6795 > nls.localize('wordWrap.off', "Lines will never wrap."),
6796 > nls.localize('wordWrap.on', "Lines will wrap at the viewport width."),
6797 > nls.localize({
6798 > key: 'wordWrap.wordWrapColumn',
6799 > comment: [
6800 > '- `editor.wordWrapColumn` refers to a different setting and should not be localized.'
6801 > ]
6802 > }, "Lines will wrap at `#editor.wordWrapColumn#`."),
6803 > nls.localize({
6804 > key: 'wordWrap.bounded',
6805 > comment: [
6806 > '- viewport means the edge of the visible window size.',
6807 > '- `editor.wordWrapColumn` refers to a different setting and should not be localized.'
6808 > ]
6809 > }, "Lines will wrap at the minimum of viewport and `#editor.wordWrapColumn#`."),
6810 > ],
6811 > description: nls.localize({
6812 > key: 'wordWrap',
6813 > comment: [
6814 > '- \'off\', \'on\', \'wordWrapColumn\' and \'bounded\' refer to values the setting can take and should not be localized.',
6815 > '- `editor.wordWrapColumn` refers to a different setting and should not be localized.'
6816 > ]
6817 > }, "Controls how lines should wrap.")
6818 > }
6819 > )),
6820 > wordWrapBreakAfterCharacters: register(new EditorStringOption(
6821 > EditorOption.wordWrapBreakAfterCharacters, 'wordWrapBreakAfterCharacters',
6822 > // allow-any-unicode-next-line
6823 > ' \t})]?|/&.,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」',
6824 > )),
6825 > wordWrapBreakBeforeCharacters: register(new EditorStringOption(
6826 > EditorOption.wordWrapBreakBeforeCharacters, 'wordWrapBreakBeforeCharacters',
6827 > // allow-any-unicode-next-line
6828 > '([{‘“〈《「『【〔([{「£¥$£¥++'
6829 > )),
6830 > wordWrapColumn: register(new EditorIntOption(
6831 > EditorOption.wordWrapColumn, 'wordWrapColumn',
6832 > 80, 1, Constants.MAX_SAFE_SMALL_INTEGER,
6833 > {
6834 > markdownDescription: nls.localize({
6835 > key: 'wordWrapColumn',
6836 > comment: [
6837 > '- `editor.wordWrap` refers to a different setting and should not be localized.',
6838 > '- \'wordWrapColumn\' and \'bounded\' refer to values the different setting can take and should not be localized.'
6839 > ]
6840 > }, "Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.")
6841 > }
6842 > )),
6843 > wordWrapOverride1: register(new EditorStringEnumOption(
6844 > EditorOption.wordWrapOverride1, 'wordWrapOverride1',
6845 > 'inherit' as 'off' | 'on' | 'inherit',
6846 > ['off', 'on', 'inherit'] as const
6847 > )),
6848 > wordWrapOverride2: register(new EditorStringEnumOption(
6849 > EditorOption.wordWrapOverride2, 'wordWrapOverride2',
6850 > 'inherit' as 'off' | 'on' | 'inherit',
6851 > ['off', 'on', 'inherit'] as const
6852 > )),
6853 > wrapOnEscapedLineFeeds: register(new EditorBooleanOption(
6854 > EditorOption.wrapOnEscapedLineFeeds, 'wrapOnEscapedLineFeeds', false,
6855 > { markdownDescription: nls.localize('wrapOnEscapedLineFeeds', "Controls whether literal `\\n` shall trigger a wordWrap when `#editor.wordWrap#` is enabled.\n\nFor example:\n```c\nchar* str=\"hello\\nworld\"\n```\nwill be displayed as\n```c\nchar* str=\"hello\\n\n world\"\n```") }
6856 > )),
6857 >
6858 > // Leave these at the end (because they have dependencies!)
6859 > effectiveCursorStyle: register(new EffectiveCursorStyle()),
6860 > editorClassName: register(new EditorClassName()),
6861 > defaultColorDecorators: register(new EditorStringEnumOption(
6862 > EditorOption.defaultColorDecorators, 'defaultColorDecorators', 'auto' as 'auto' | 'always' | 'never',
6863 > ['auto', 'always', 'never'] as const,
6864 > {
6865 > enumDescriptions: [
6866 > nls.localize('editor.defaultColorDecorators.auto', "Show default color decorators only when no extension provides colors decorators."),
6867 > nls.localize('editor.defaultColorDecorators.always', "Always show default color decorators."),
6868 > nls.localize('editor.defaultColorDecorators.never', "Never show default color decorators."),
6869 > ],
6870 > description: nls.localize('defaultColorDecorators', "Controls whether inline color decorations should be shown using the default document color provider.")
6871 > }
6872 > )),
6873 > pixelRatio: register(new EditorPixelRatio()),
6874 > tabFocusMode: register(new EditorBooleanOption(EditorOption.tabFocusMode, 'tabFocusMode', false,
6875 > { markdownDescription: nls.localize('tabFocusMode', "Controls whether the editor receives tabs or defers them to the workbench for navigation.") }
6876 > )),
6877 > layoutInfo: register(new EditorLayoutInfoComputer()),
6878 > wrappingInfo: register(new EditorWrappingInfoComputer()),
6879 > wrappingIndent: register(new WrappingIndentOption()),
6880 > wrappingStrategy: register(new WrappingStrategy()),
6881 > effectiveEditContextEnabled: register(new EffectiveEditContextEnabled()),
6882 > effectiveAllowVariableFonts: register(new EffectiveAllowVariableFonts())
6883 > };
6884 >
6885 > type EditorOptionsType = typeof EditorOptions;
6886 > type FindEditorOptionsKeyById<T extends EditorOption> = { [K in keyof EditorOptionsType]: EditorOptionsType[K]['id'] extends T ? K : never }[keyof EditorOptionsType];
6887 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
6888 > type ComputedEditorOptionValue<T extends IEditorOption<any, any>> = T extends IEditorOption<any, infer R> ? R : never;
6889 > export type FindComputedEditorOptionValueById<T extends EditorOption> = NonNullable<ComputedEditorOptionValue<EditorOptionsType[FindEditorOptionsKeyById<T>]>>;
6890 >
6891 > export type MouseMiddleClickAction = 'default' | 'openLink' | 'ctrlLeftClick';
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 1250 covered LOC · 207 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; async.ts
1197 > this.runner = runner;
1198 > this.timeout = delay;
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()) { async.ts
1215 clearTimeout(this.timeoutToken);
1216 this.timeoutToken = undefined;
1217 }
1218 > } async.ts
1219 > async.ts
1220 > /**
1221 > * Cancel previous runner (if any) & schedule a new runner.
1222 > */
1223 > schedule(delay = this.timeout): void {
1224 > this.cancel(); async.ts
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; async.ts
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/base/common/event.ts 923 covered LOC · 122 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) { event.ts
1207 > this._disposed = true;
1208 >
1209 > // It is bad to have listeners at the time of disposing an emitter, it is worst to have listeners keep the emitter
1210 > // alive via the reference that's embedded in their disposables. Therefore we loop over all remaining listeners and
1211 > // unset their subscriptions/disposables. Looping and blaming remaining listeners is done on next tick because the
1212 > // the following programming pattern is very popular:
1213 > //
1214 > // const someModel = this._disposables.add(new ModelObject()); // (1) create and register model
1215 > // this._disposables.add(someModel.onDidChange(() => { ... }); // (2) subscribe and register model-event listener
1216 > // ...later...
1217 > // this._disposables.dispose(); disposes (1) then (2): don't warn after (1) but after the "overall dispose" is done
1218 >
1219 > if (this._deliveryQueue?.current === this) {
1220 this._deliveryQueue.reset();
1221 }
1222 > if (this._listeners) { event.ts
1223 if (_enableDisposeWithListenerWarning) {
1224 const listeners = this._listeners;
1231 this._size = 0;
1232 }
1233 > this._options?.onDidRemoveLastListener?.(); event.ts
1234 > this._leakageMon?.dispose();
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) { event.ts
1245 const message = `[${this._leakageMon.name}] REFUSES to accept new listeners because it exceeded its threshold by far (${this._size} vs ${this._leakageMon.threshold})`;
1246 console.warn(message);
1254 return Disposable.None;
1255 }
1256 > event.ts
1257 > if (this._disposed) {
1258 // todo: should we warn if a listener is added to a disposed emitter? This happens often
1259 return Disposable.None;
1260 }
1261 > event.ts
1262 > if (thisArgs) {
1263 callback = callback.bind(thisArgs);
1264 }
1265 > event.ts
1266 > const contained = new UniqueContainer(callback);
1267 >
1268 > let removeMonitor: Function | undefined;
1269 > let stack: Stacktrace | undefined;
1270 > if (this._leakageMon && this._size >= Math.ceil(this._leakageMon.threshold * 0.2)) {
1271 // check and record this emitter for potential leakage
1272 contained.stack = Stacktrace.create();
1273 removeMonitor = this._leakageMon.check(contained.stack, this._size + 1);
1274 }
1275 > event.ts
1276 > if (_enableDisposeWithListenerWarning) {
1277 contained.stack = stack ?? Stacktrace.create();
1278 }
1279 > event.ts
1280 > if (!this._listeners) {
1281 > this._options?.onWillAddFirstListener?.(this);
1282 > this._listeners = contained;
1283 > this._options?.onDidAddFirstListener?.(this);
1284 > } else if (this._listeners instanceof UniqueContainer) {
1285 this._deliveryQueue ??= new EventDeliveryQueuePrivate();
1286 this._listeners = [this._listeners, contained];
1288 this._listeners.push(contained);
1289 }
1290 > this._options?.onDidAddListener?.(this); event.ts
1291 >
1292 > this._size++;
1293 >
1294 >
1295 > const result = toDisposable(() => {
1296 removeMonitor?.();
1297 this._removeListener(contained);
1298 > }); event.ts
1299 > addToDisposables(result, disposables);
1300 >
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) { event.ts
1354 return;
1355 }
1356 > event.ts
1357 > const errorHandler = this._options?.onListenerError || onUnexpectedError;
1358 > if (!errorHandler) {
1359 listener.value(value);
1360 return;
1361 }
1362 > event.ts
1363 > try {
1364 > listener.value(value);
1365 > } catch (e) {
1366 errorHandler(e);
1367 }
1368 > } event.ts
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); event.ts
1396 > } else { event.ts
1397 const dq = this._deliveryQueue!;
1398 dq.enqueue(this, event, this._listeners.length);
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) { event.ts
1947 > if (disposables instanceof DisposableStore) {
1948 disposables.add(result);
1949 > } else if (Array.isArray(disposables)) { event.ts
1950 disposables.push(result);
1951 }
1952 > } event.ts
1953 > event.ts
1954 function disposeAndRemove(result: IDisposable, disposables: DisposableStore | IDisposable[] | undefined) {
1955 if (disposables instanceof DisposableStore) {
src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts 912 covered LOC · 261 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- pieceTreeBase.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 { Position } from '../../core/position.js';
8 > import { Range } from '../../core/range.js';
9 > import { FindMatch, ITextSnapshot, SearchData } from '../../model.js';
10 > import { NodeColor, SENTINEL, TreeNode, fixInsert, leftest, rbDelete, righttest, updateTreeMetadata } from './rbTreeBase.js';
11 > import { Searcher, createFindMatch, isValidMatch } from '../textModelSearch.js';
12 >
13 > // const lfRegex = new RegExp(/\r\n|\r|\n/g);
14 > const AverageBufferSize = 65535;
15 >
16 > function createUintArray(arr: number[]): Uint32Array | Uint16Array { pieceTreeBase.ts
17 > let r;
18 > if (arr[arr.length - 1] < 65536) {
19 > r = new Uint16Array(arr.length); pieceTreeBase.ts
20 > } else { pieceTreeBase.ts
21 r = new Uint32Array(arr.length);
22 }
23 > r.set(arr, 0); pieceTreeBase.ts
24 > return r;
25 > }
27 > class LineStarts {
28 > constructor(
29 > public readonly lineStarts: Uint32Array | Uint16Array | number[], pieceTreeBase.ts
30 > public readonly cr: number,
31 > public readonly lf: number,
32 > public readonly crlf: number,
33 > public readonly isBasicASCII: boolean
34 > ) { }
36 >
37 > export function createLineStartsFast(str: string, readonly: boolean = true): Uint32Array | Uint16Array | number[] {
38 > const r: number[] = [0]; pieceTreeBase.ts
39 > let rLength = 1;
40 >
41 > for (let i = 0, len = str.length; i < len; i++) {
42 > const chr = str.charCodeAt(i);
43 >
44 > if (chr === CharCode.CarriageReturn) {
45 if (i + 1 < len && str.charCodeAt(i + 1) === CharCode.LineFeed) {
46 // \r\n... case
51 r[rLength++] = i + 1;
52 }
53 > } else if (chr === CharCode.LineFeed) { pieceTreeBase.ts
54 > r[rLength++] = i + 1; pieceTreeBase.ts
55 > }
57 > if (readonly) {
58 return createUintArray(r);
59 > } else { pieceTreeBase.ts
60 > return r; pieceTreeBase.ts
61 > }
64 > export function createLineStarts(r: number[], str: string): LineStarts {
65 > r.length = 0; pieceTreeBase.ts
66 > r[0] = 0;
67 > let rLength = 1;
68 > let cr = 0, lf = 0, crlf = 0;
69 > let isBasicASCII = true;
70 > for (let i = 0, len = str.length; i < len; i++) {
71 const chr = str.charCodeAt(i);
72
93 }
94 }
95 > const result = new LineStarts(createUintArray(r), cr, lf, crlf, isBasicASCII); pieceTreeBase.ts
96 > r.length = 0;
97 >
98 > return result;
99 > }
101 > interface NodePosition {
102 > /**
103 > * Piece Index
104 > */
105 > node: TreeNode;
106 > /**
107 > * remainder in current piece.
108 > */
109 > remainder: number;
110 > /**
111 > * node start offset in document.
112 > */
113 > nodeStartOffset: number;
114 > }
115 >
116 > interface BufferCursor {
117 > /**
118 > * Line number in current buffer
119 > */
120 > line: number;
121 > /**
122 > * Column number in current buffer
123 > */
124 > column: number;
125 > }
126 >
127 > export class Piece {
128 > readonly bufferIndex: number;
129 > readonly start: BufferCursor;
130 > readonly end: BufferCursor;
131 > readonly length: number;
132 > readonly lineFeedCnt: number;
133 >
134 > constructor(bufferIndex: number, start: BufferCursor, end: BufferCursor, lineFeedCnt: number, length: number) {
135 > this.bufferIndex = bufferIndex; pieceTreeBase.ts
136 > this.start = start;
137 > this.end = end;
138 > this.lineFeedCnt = lineFeedCnt;
139 > this.length = length;
140 > }
142 >
143 > export class StringBuffer {
144 > buffer: string;
145 > lineStarts: Uint32Array | Uint16Array | number[];
146 >
147 > constructor(buffer: string, lineStarts: Uint32Array | Uint16Array | number[]) {
148 > this.buffer = buffer; pieceTreeBase.ts
149 > this.lineStarts = lineStarts;
150 > }
152 >
153 > /**
154 > * Readonly snapshot for piece tree.
155 > * In a real multiple thread environment, to make snapshot reading always work correctly, we need to
156 > * 1. Make TreeNode.piece immutable, then reading and writing can run in parallel.
157 > * 2. TreeNode/Buffers normalization should not happen during snapshot reading.
158 > */
159 > class PieceTreeSnapshot implements ITextSnapshot {
160 > private readonly _pieces: Piece[];
161 > private _index: number;
162 > private readonly _tree: PieceTreeBase;
163 > private readonly _BOM: string;
164 >
165 > constructor(tree: PieceTreeBase, BOM: string) {
166 this._pieces = [];
167 this._tree = tree;
177 }
178 }
180 > read(): string | null {
181 if (this._pieces.length === 0) {
182 if (this._index === 0) {
197 return this._tree.getPieceContent(this._pieces[this._index++]);
198 }
200 >
201 > interface CacheEntry {
202 > node: TreeNode;
203 > nodeStartOffset: number;
204 > nodeStartLineNumber?: number;
205 > }
206 >
207 > class PieceTreeSearchCache {
208 > private readonly _limit: number;
209 > private _cache: CacheEntry[];
210 >
211 > constructor(limit: number) {
212 > this._limit = limit; pieceTreeBase.ts
213 > this._cache = [];
214 > }
216 > public get(offset: number): CacheEntry | null {
217 > for (let i = this._cache.length - 1; i >= 0; i--) { pieceTreeBase.ts
218 > const nodePos = this._cache[i]; pieceTreeBase.ts
219 > if (nodePos.nodeStartOffset <= offset && nodePos.nodeStartOffset + nodePos.node.piece.length >= offset) {
220 > return nodePos; pieceTreeBase.ts
221 > }
223 > return null; pieceTreeBase.ts
226 > public get2(lineNumber: number): { node: TreeNode; nodeStartOffset: number; nodeStartLineNumber: number } | null {
227 for (let i = this._cache.length - 1; i >= 0; i--) {
228 const nodePos = this._cache[i];
233 return null;
234 }
236 > public set(nodePosition: CacheEntry) {
237 > if (this._cache.length >= this._limit) { pieceTreeBase.ts
238 > this._cache.shift(); pieceTreeBase.ts
239 > }
240 > this._cache.push(nodePosition); pieceTreeBase.ts
241 > }
243 > public validate(offset: number) {
244 > let hasInvalidVal = false; pieceTreeBase.ts
245 > const tmp: Array<CacheEntry | null> = this._cache;
246 > for (let i = 0; i < tmp.length; i++) {
247 > const nodePos = tmp[i]!; pieceTreeBase.ts
248 > if (nodePos.node.parent === null || nodePos.nodeStartOffset >= offset) {
249 > tmp[i] = null; pieceTreeBase.ts
250 > hasInvalidVal = true;
251 > continue;
252 > }
255 > if (hasInvalidVal) {
256 > const newArr: CacheEntry[] = []; pieceTreeBase.ts
257 > for (const entry of tmp) {
258 > if (entry !== null) {
259 newArr.push(entry);
260 }
262 >
263 > this._cache = newArr;
264 > }
267 >
268 > export class PieceTreeBase {
269 > root!: TreeNode;
270 > protected _buffers!: StringBuffer[]; // 0 is change buffer, others are readonly original buffer.
271 > protected _lineCnt!: number;
272 > protected _length!: number;
273 > protected _EOL!: '\r\n' | '\n';
274 > protected _EOLLength!: number;
275 > protected _EOLNormalized!: boolean;
276 > private _lastChangeBufferPos!: BufferCursor;
277 > private _searchCache!: PieceTreeSearchCache;
278 > private _lastVisitedLine!: { lineNumber: number; value: string };
279 >
280 > constructor(chunks: StringBuffer[], eol: '\r\n' | '\n', eolNormalized: boolean) {
281 > this.create(chunks, eol, eolNormalized); pieceTreeBase.ts
282 > }
284 > create(chunks: StringBuffer[], eol: '\r\n' | '\n', eolNormalized: boolean) {
285 > this._buffers = [ pieceTreeBase.ts
286 > new StringBuffer('', [0])
287 > ];
288 > this._lastChangeBufferPos = { line: 0, column: 0 };
289 > this.root = SENTINEL;
290 > this._lineCnt = 1;
291 > this._length = 0;
292 > this._EOL = eol;
293 > this._EOLLength = eol.length;
294 > this._EOLNormalized = eolNormalized;
295 >
296 > let lastNode: TreeNode | null = null;
297 > for (let i = 0, len = chunks.length; i < len; i++) {
298 > if (chunks[i].buffer.length > 0) {
299 if (!chunks[i].lineStarts) {
300 chunks[i].lineStarts = createLineStartsFast(chunks[i].buffer);
311 lastNode = this.rbInsertRight(lastNode, piece);
312 }
314 >
315 > this._searchCache = new PieceTreeSearchCache(1);
316 > this._lastVisitedLine = { lineNumber: 0, value: '' };
317 > this.computeBufferMetadata();
318 > }
320 > normalizeEOL(eol: '\r\n' | '\n') {
321 const averageBufferSize = AverageBufferSize;
322 const min = averageBufferSize - Math.floor(averageBufferSize / 3);
351 this.create(chunks, eol, true);
352 }
354 > // #region Buffer API
355 > public getEOL(): '\r\n' | '\n' {
356 return this._EOL;
357 }
359 > public setEOL(newEOL: '\r\n' | '\n'): void {
360 this._EOL = newEOL;
361 this._EOLLength = this._EOL.length;
362 this.normalizeEOL(newEOL);
363 }
365 > public createSnapshot(BOM: string): ITextSnapshot {
366 return new PieceTreeSnapshot(this, BOM);
367 }
369 > public equal(other: PieceTreeBase): boolean {
370 if (this.getLength() !== other.getLength()) {
371 return false;
392 return ret;
393 }
395 > public getOffsetAt(lineNumber: number, column: number): number {
396 > let leftLen = 0; // inorder pieceTreeBase.ts
397 >
398 > let x = this.root;
399 >
400 > while (x !== SENTINEL) {
401 > if (x.left !== SENTINEL && x.lf_left + 1 >= lineNumber) { pieceTreeBase.ts
402 > x = x.left; pieceTreeBase.ts
403 > } else if (x.lf_left + x.piece.lineFeedCnt + 1 >= lineNumber) { pieceTreeBase.ts
404 > leftLen += x.size_left;
405 > // lineNumber >= 2
406 > const accumualtedValInCurrentIndex = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
407 > return leftLen += accumualtedValInCurrentIndex + column - 1;
408 > } else {
409 > lineNumber -= x.lf_left + x.piece.lineFeedCnt; pieceTreeBase.ts
410 > leftLen += x.size_left + x.piece.length;
411 > x = x.right;
412 > }
414
415 return leftLen;
418 > public getPositionAt(offset: number): Position {
419 > offset = Math.floor(offset); pieceTreeBase.ts
420 > offset = Math.max(0, offset);
421 >
422 > let x = this.root;
423 > let lfCnt = 0;
424 > const originalOffset = offset;
425 >
426 > while (x !== SENTINEL) {
427 > if (x.size_left !== 0 && x.size_left >= offset) {
428 > x = x.left; pieceTreeBase.ts
429 > } else if (x.size_left + x.piece.length >= offset) { pieceTreeBase.ts
430 > const out = this.getIndexOf(x, offset - x.size_left);
431 >
432 > lfCnt += x.lf_left + out.index;
433 >
434 > if (out.index === 0) {
435 > const lineStartOffset = this.getOffsetAt(lfCnt + 1, 1); pieceTreeBase.ts
436 > const column = originalOffset - lineStartOffset;
437 > return new Position(lfCnt + 1, column + 1);
438 > }
440 > return new Position(lfCnt + 1, out.remainder + 1);
441 > } else { pieceTreeBase.ts
442 > offset -= x.size_left + x.piece.length; pieceTreeBase.ts
443 > lfCnt += x.lf_left + x.piece.lineFeedCnt;
444 >
445 > if (x.right === SENTINEL) {
446 // last node
447 const lineStartOffset = this.getOffsetAt(lfCnt + 1, 1);
448 const column = originalOffset - offset - lineStartOffset;
449 return new Position(lfCnt + 1, column + 1);
450 > } else { pieceTreeBase.ts
451 > x = x.right;
452 > }
453 > }
455
456 return new Position(1, 1);
459 > public getValueInRange(range: Range, eol?: string): string {
460 if (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) {
461 return '';
481 return value;
482 }
484 > public getValueInRange2(startPosition: NodePosition, endPosition: NodePosition): string {
485 if (startPosition.node === endPosition.node) {
486 const node = startPosition.node;
512 return ret;
513 }
515 > public getLinesContent(): string[] {
516 const lines: string[] = [];
517 let linesLength = 0;
602 return lines;
603 }
605 > public getLength(): number {
606 return this._length;
607 }
609 > public getLineCount(): number {
610 return this._lineCnt;
611 }
613 > public getLineContent(lineNumber: number): string {
614 if (this._lastVisitedLine.lineNumber === lineNumber) {
615 return this._lastVisitedLine.value;
628 return this._lastVisitedLine.value;
629 }
631 > private _getCharCode(nodePos: NodePosition): number {
632 if (nodePos.remainder === nodePos.node.piece.length) {
633 // the char we want to fetch is at the head of next node.
648 }
649 }
651 > public getLineCharCode(lineNumber: number, index: number): number {
652 const nodePos = this.nodeAt2(lineNumber, index + 1);
653 return this._getCharCode(nodePos);
654 }
656 > public getLineLength(lineNumber: number): number {
657 if (lineNumber === this.getLineCount()) {
658 const startOffset = this.getOffsetAt(lineNumber, 1);
661 return this.getOffsetAt(lineNumber + 1, 1) - this.getOffsetAt(lineNumber, 1) - this._EOLLength;
662 }
664 > public getCharCode(offset: number): number {
665 const nodePos = this.nodeAt(offset);
666 return this._getCharCode(nodePos);
667 }
669 > public getNearestChunk(offset: number): string {
670 const nodePos = this.nodeAt(offset);
671 if (nodePos.remainder === nodePos.node.piece.length) {
687 }
688 }
690 > public findMatchesInNode(node: TreeNode, searcher: Searcher, startLineNumber: number, startColumn: number, startCursor: BufferCursor, endCursor: BufferCursor, searchData: SearchData, captureMatches: boolean, limitResultCount: number, resultLen: number, result: FindMatch[]) {
691 const buffer = this._buffers[node.piece.bufferIndex];
692 const startOffsetInBuffer = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start);
735 return resultLen;
736 }
738 > public findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {
739 const result: FindMatch[] = [];
740 let resultLen = 0;
809 return result;
810 }
812 > private _findMatchesInLine(searchData: SearchData, searcher: Searcher, text: string, lineNumber: number, deltaOffset: number, resultLen: number, result: FindMatch[], captureMatches: boolean, limitResultCount: number): number {
813 const wordSeparators = searchData.wordSeparators;
814 if (!captureMatches && searchData.simpleSearch) {
843 return resultLen;
844 }
846 > // #endregion
847 >
848 > // #region Piece Table
849 > public insert(offset: number, value: string, eolNormalized: boolean = false): void {
850 > this._EOLNormalized = this._EOLNormalized && eolNormalized; pieceTreeBase.ts
851 > this._lastVisitedLine.lineNumber = 0;
852 > this._lastVisitedLine.value = '';
853 >
854 > if (this.root !== SENTINEL) {
855 > const { node, remainder, nodeStartOffset } = this.nodeAt(offset); pieceTreeBase.ts
856 > const piece = node.piece;
857 > const bufferIndex = piece.bufferIndex;
858 > const insertPosInBuffer = this.positionInBuffer(node, remainder);
859 > if (node.piece.bufferIndex === 0 &&
860 > piece.end.line === this._lastChangeBufferPos.line && pieceTreeBase.ts
861 > piece.end.column === this._lastChangeBufferPos.column && pieceTreeBase.ts
862 > (nodeStartOffset + piece.length === offset) && pieceTreeBase.ts
863 value.length < AverageBufferSize
864 > ) { pieceTreeBase.ts
865 // changed buffer
866 this.appendToNode(node, value);
868 return;
869 }
871 > if (nodeStartOffset === offset) {
872 this.insertContentToNodeLeft(value, node);
873 this._searchCache.validate(offset);
874 > } else if (nodeStartOffset + node.piece.length > offset) { pieceTreeBase.ts
875 > // we are inserting into the middle of a node. pieceTreeBase.ts
876 > const nodesToDel: TreeNode[] = [];
877 > let newRightPiece = new Piece(
878 > piece.bufferIndex,
879 > insertPosInBuffer,
880 > piece.end,
881 > this.getLineFeedCnt(piece.bufferIndex, insertPosInBuffer, piece.end),
882 > this.offsetInBuffer(bufferIndex, piece.end) - this.offsetInBuffer(bufferIndex, insertPosInBuffer)
883 > );
884 >
885 > if (this.shouldCheckCRLF() && this.endWithCR(value)) {
886 const headOfRight = this.nodeCharCodeAt(node, remainder);
887
899 }
900 }
902 > // reuse node for content before insertion point.
903 > if (this.shouldCheckCRLF() && this.startWithLF(value)) {
904 > const tailOfLeft = this.nodeCharCodeAt(node, remainder - 1); pieceTreeBase.ts
905 > if (tailOfLeft === 13 /** \r */) {
906 const previousPos = this.positionInBuffer(node, remainder - 1);
907 this.deleteNodeTail(node, previousPos);
911 nodesToDel.push(node);
912 }
913 > } else { pieceTreeBase.ts
914 > this.deleteNodeTail(node, insertPosInBuffer); pieceTreeBase.ts
915 > }
916 > } else { pieceTreeBase.ts
917 > this.deleteNodeTail(node, insertPosInBuffer); pieceTreeBase.ts
918 > }
920 > const newPieces = this.createNewPieces(value);
921 > if (newRightPiece.length > 0) {
922 > this.rbInsertRight(node, newRightPiece);
923 > }
924 >
925 > let tmpNode = node;
926 > for (let k = 0; k < newPieces.length; k++) {
927 > tmpNode = this.rbInsertRight(tmpNode, newPieces[k]);
928 > }
929 > this.deleteNodes(nodesToDel);
930 > } else { pieceTreeBase.ts
931 > this.insertContentToNodeRight(value, node); pieceTreeBase.ts
932 > }
933 > } else { pieceTreeBase.ts
934 > // insert new node pieceTreeBase.ts
935 > const pieces = this.createNewPieces(value);
936 > let node = this.rbInsertLeft(null, pieces[0]);
937 >
938 > for (let k = 1; k < pieces.length; k++) {
939 node = this.rbInsertRight(node, pieces[k]);
940 }
943 > // todo, this is too brutal. Total line feed count should be updated the same way as lf_left.
944 > this.computeBufferMetadata();
945 > }
947 > public delete(offset: number, cnt: number): void {
948 > this._lastVisitedLine.lineNumber = 0; pieceTreeBase.ts
949 > this._lastVisitedLine.value = '';
950 >
951 > if (cnt <= 0 || this.root === SENTINEL) {
952 return;
953 }
955 > const startPosition = this.nodeAt(offset);
956 > const endPosition = this.nodeAt(offset + cnt);
957 > const startNode = startPosition.node;
958 > const endNode = endPosition.node;
959 >
960 > if (startNode === endNode) {
961 > const startSplitPosInBuffer = this.positionInBuffer(startNode, startPosition.remainder); pieceTreeBase.ts
962 > const endSplitPosInBuffer = this.positionInBuffer(startNode, endPosition.remainder);
963 >
964 > if (startPosition.nodeStartOffset === offset) {
965 if (cnt === startNode.piece.length) { // delete node
966 const next = startNode.next();
976 return;
977 }
979 > if (startPosition.nodeStartOffset + startNode.piece.length === offset + cnt) {
980 > this.deleteNodeTail(startNode, startSplitPosInBuffer); pieceTreeBase.ts
981 > this.validateCRLFWithNextNode(startNode);
982 > this.computeBufferMetadata();
983 > return;
984 > }
986 > // delete content in the middle, this node will be splitted to nodes
987 > this.shrinkNode(startNode, startSplitPosInBuffer, endSplitPosInBuffer);
988 > this.computeBufferMetadata();
989 > return;
990 > }
992 > const nodesToDel: TreeNode[] = [];
993 >
994 > const startSplitPosInBuffer = this.positionInBuffer(startNode, startPosition.remainder);
995 > this.deleteNodeTail(startNode, startSplitPosInBuffer);
996 > this._searchCache.validate(offset);
997 > if (startNode.piece.length === 0) {
998 nodesToDel.push(startNode);
999 }
1001 > // update last touched node
1002 > const endSplitPosInBuffer = this.positionInBuffer(endNode, endPosition.remainder);
1003 > this.deleteNodeHead(endNode, endSplitPosInBuffer);
1004 > if (endNode.piece.length === 0) {
1005 > nodesToDel.push(endNode); pieceTreeBase.ts
1006 > }
1008 > // delete nodes in between
1009 > const secondNode = startNode.next();
1010 > for (let node = secondNode; node !== SENTINEL && node !== endNode; node = node.next()) { pieceTreeBase.ts
1011 > nodesToDel.push(node); pieceTreeBase.ts
1012 > }
1014 > const prev = startNode.piece.length === 0 ? startNode.prev() : startNode; pieceTreeBase.ts
1015 > this.deleteNodes(nodesToDel);
1016 > this.validateCRLFWithNextNode(prev);
1017 > this.computeBufferMetadata();
1018 > }
1020 > private insertContentToNodeLeft(value: string, node: TreeNode) {
1021 // we are inserting content to the beginning of node
1022 const nodesToDel: TreeNode[] = [];
1052 this.deleteNodes(nodesToDel);
1053 }
1055 > private insertContentToNodeRight(value: string, node: TreeNode) {
1056 > // we are inserting to the right of this node. pieceTreeBase.ts
1057 > if (this.adjustCarriageReturnFromNext(value, node)) {
1058 // move \n to the new node.
1059 value += '\n';
1060 }
1062 > const newPieces = this.createNewPieces(value);
1063 > const newNode = this.rbInsertRight(node, newPieces[0]);
1064 > let tmpNode = newNode;
1065 >
1066 > for (let k = 1; k < newPieces.length; k++) {
1067 tmpNode = this.rbInsertRight(tmpNode, newPieces[k]);
1068 }
1070 > this.validateCRLFWithPrevNode(newNode);
1071 > }
1073 > private positionInBuffer(node: TreeNode, remainder: number): BufferCursor;
1074 > private positionInBuffer(node: TreeNode, remainder: number, ret: BufferCursor): null;
1075 > private positionInBuffer(node: TreeNode, remainder: number, ret?: BufferCursor): BufferCursor | null {
1076 > const piece = node.piece; pieceTreeBase.ts
1077 > const bufferIndex = node.piece.bufferIndex;
1078 > const lineStarts = this._buffers[bufferIndex].lineStarts;
1079 >
1080 > const startOffset = lineStarts[piece.start.line] + piece.start.column;
1081 >
1082 > const offset = startOffset + remainder;
1083 >
1084 > // binary search offset between startOffset and endOffset
1085 > let low = piece.start.line;
1086 > let high = piece.end.line;
1087 >
1088 > let mid: number = 0;
1089 > let midStop: number = 0;
1090 > let midStart: number = 0;
1091 >
1092 > while (low <= high) {
1093 > mid = low + ((high - low) / 2) | 0;
1094 > midStart = lineStarts[mid];
1095 >
1096 > if (mid === high) {
1097 > break; pieceTreeBase.ts
1098 > }
1100 > midStop = lineStarts[mid + 1];
1101 >
1102 > if (offset < midStart) {
1103 > high = mid - 1; pieceTreeBase.ts
1104 > } else if (offset >= midStop) { pieceTreeBase.ts
1105 > low = mid + 1; pieceTreeBase.ts
1106 > } else { pieceTreeBase.ts
1107 > break; pieceTreeBase.ts
1108 > }
1109 > } pieceTreeBase.ts
1110 >
1111 > if (ret) {
1112 ret.line = mid;
1113 ret.column = offset - midStart;
1114 return null;
1115 }
1117 > return {
1118 > line: mid,
1119 > column: offset - midStart
1120 > };
1121 > }
1123 > private getLineFeedCnt(bufferIndex: number, start: BufferCursor, end: BufferCursor): number {
1124 > // we don't need to worry about start: abc\r|\n, or abc|\r, or abc|\n, or abc|\r\n doesn't change the fact that, there is one line break after start. pieceTreeBase.ts
1125 > // now let's take care of end: abc\r|\n, if end is in between \r and \n, we need to add line feed count by 1
1126 > if (end.column === 0) {
1127 > return end.line - start.line; pieceTreeBase.ts
1128 > }
1130 > const lineStarts = this._buffers[bufferIndex].lineStarts;
1131 > if (end.line === lineStarts.length - 1) { // it means, there is no \n after end, otherwise, there will be one more lineStart.
1132 > return end.line - start.line; pieceTreeBase.ts
1133 > }
1135 > const nextLineStartOffset = lineStarts[end.line + 1];
1136 > const endOffset = lineStarts[end.line] + end.column;
1137 > if (nextLineStartOffset > endOffset + 1) { // there are more than 1 character after end, which means it can't be \n
1138 > return end.line - start.line; pieceTreeBase.ts
1139 > }
1140 > // endOffset + 1 === nextLineStartOffset pieceTreeBase.ts
1141 > // character at endOffset is \n, so we check the character before first
1142 > // if character at endOffset is \r, end.column is 0 and we can't get here.
1143 > const previousCharOffset = endOffset - 1; // end.column > 0 so it's okay.
1144 > const buffer = this._buffers[bufferIndex].buffer;
1145 >
1146 > if (buffer.charCodeAt(previousCharOffset) === 13) {
1147 return end.line - start.line + 1;
1148 > } else { pieceTreeBase.ts
1149 > return end.line - start.line; pieceTreeBase.ts
1150 > }
1151 > } pieceTreeBase.ts
1153 > private offsetInBuffer(bufferIndex: number, cursor: BufferCursor): number {
1154 > const lineStarts = this._buffers[bufferIndex].lineStarts; pieceTreeBase.ts
1155 > return lineStarts[cursor.line] + cursor.column;
1156 > }
1158 > private deleteNodes(nodes: TreeNode[]): void {
1159 > for (let i = 0; i < nodes.length; i++) { pieceTreeBase.ts
1160 > rbDelete(this, nodes[i]); pieceTreeBase.ts
1161 > }
1162 > } pieceTreeBase.ts
1164 > private createNewPieces(text: string): Piece[] {
1165 > if (text.length > AverageBufferSize) { pieceTreeBase.ts
1166 // the content is large, operations like substring, charCode becomes slow
1167 // so here we split it into smaller chunks, just like what we did for CR/LF normalization
1202 return newPieces;
1203 }
1205 > let startOffset = this._buffers[0].buffer.length;
1206 > const lineStarts = createLineStartsFast(text, false);
1207 >
1208 > let start = this._lastChangeBufferPos;
1209 > if (this._buffers[0].lineStarts[this._buffers[0].lineStarts.length - 1] === startOffset
1210 > && startOffset !== 0
1211 && this.startWithLF(text)
1212 && this.endWithCR(this._buffers[0].buffer) // todo, we can check this._lastChangeBufferPos's column as it's the last one
1213 > ) { pieceTreeBase.ts
1214 this._lastChangeBufferPos = { line: this._lastChangeBufferPos.line, column: this._lastChangeBufferPos.column + 1 };
1215 start = this._lastChangeBufferPos;
1222 this._buffers[0].buffer += '_' + text;
1223 startOffset += 1;
1224 > } else { pieceTreeBase.ts
1225 > if (startOffset !== 0) {
1226 > for (let i = 0; i < lineStarts.length; i++) { pieceTreeBase.ts
1227 > lineStarts[i] += startOffset;
1228 > }
1229 > }
1230 > this._buffers[0].lineStarts = (<number[]>this._buffers[0].lineStarts).concat(<number[]>lineStarts.slice(1)); pieceTreeBase.ts
1231 > this._buffers[0].buffer += text;
1232 > }
1233 >
1234 > const endOffset = this._buffers[0].buffer.length;
1235 > const endIndex = this._buffers[0].lineStarts.length - 1;
1236 > const endColumn = endOffset - this._buffers[0].lineStarts[endIndex];
1237 > const endPos = { line: endIndex, column: endColumn };
1238 > const newPiece = new Piece(
1239 > 0, /** todo@peng */
1240 > start,
1241 > endPos,
1242 > this.getLineFeedCnt(0, start, endPos),
1243 > endOffset - startOffset
1244 > );
1245 > this._lastChangeBufferPos = endPos;
1246 > return [newPiece];
1247 > }
1249 > public getLinesRawContent(): string {
1250 > return this.getContentOfSubTree(this.root); pieceTreeBase.ts
1251 > }
1253 > public getLineRawContent(lineNumber: number, endOffset: number = 0): string {
1254 let x = this.root;
1255
1322 return ret;
1323 }
1325 > private computeBufferMetadata() {
1326 > let x = this.root; pieceTreeBase.ts
1327 >
1328 > let lfCnt = 1;
1329 > let len = 0;
1330 >
1331 > while (x !== SENTINEL) {
1332 > lfCnt += x.lf_left + x.piece.lineFeedCnt; pieceTreeBase.ts
1333 > len += x.size_left + x.piece.length;
1334 > x = x.right;
1335 > }
1337 > this._lineCnt = lfCnt;
1338 > this._length = len;
1339 > this._searchCache.validate(this._length);
1340 > }
1342 > // #region node operations
1343 > private getIndexOf(node: TreeNode, accumulatedValue: number): { index: number; remainder: number } {
1344 > const piece = node.piece; pieceTreeBase.ts
1345 > const pos = this.positionInBuffer(node, accumulatedValue);
1346 > const lineCnt = pos.line - piece.start.line;
1347 >
1348 > if (this.offsetInBuffer(piece.bufferIndex, piece.end) - this.offsetInBuffer(piece.bufferIndex, piece.start) === accumulatedValue) {
1349 > // we are checking the end of this node, so a CRLF check is necessary. pieceTreeBase.ts
1350 > const realLineCnt = this.getLineFeedCnt(node.piece.bufferIndex, piece.start, pos);
1351 > if (realLineCnt !== lineCnt) {
1352 // aha yes, CRLF
1353 return { index: realLineCnt, remainder: 0 };
1354 }
1355 > } pieceTreeBase.ts
1357 > return { index: lineCnt, remainder: pos.column };
1358 > }
1360 > private getAccumulatedValue(node: TreeNode, index: number) {
1361 > if (index < 0) { pieceTreeBase.ts
1362 > return 0; pieceTreeBase.ts
1363 > }
1364 > const piece = node.piece; pieceTreeBase.ts
1365 > const lineStarts = this._buffers[piece.bufferIndex].lineStarts;
1366 > const expectedLineStartIndex = piece.start.line + index + 1;
1367 > if (expectedLineStartIndex > piece.end.line) {
1368 return lineStarts[piece.end.line] + piece.end.column - lineStarts[piece.start.line] - piece.start.column;
1369 > } else { pieceTreeBase.ts
1370 > return lineStarts[expectedLineStartIndex] - lineStarts[piece.start.line] - piece.start.column;
1371 > }
1372 > } pieceTreeBase.ts
1374 > private deleteNodeTail(node: TreeNode, pos: BufferCursor) {
1375 > const piece = node.piece; pieceTreeBase.ts
1376 > const originalLFCnt = piece.lineFeedCnt;
1377 > const originalEndOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);
1378 >
1379 > const newEnd = pos;
1380 > const newEndOffset = this.offsetInBuffer(piece.bufferIndex, newEnd);
1381 > const newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, piece.start, newEnd);
1382 >
1383 > const lf_delta = newLineFeedCnt - originalLFCnt;
1384 > const size_delta = newEndOffset - originalEndOffset;
1385 > const newLength = piece.length + size_delta;
1386 >
1387 > node.piece = new Piece(
1388 > piece.bufferIndex,
1389 > piece.start,
1390 > newEnd,
1391 > newLineFeedCnt,
1392 > newLength
1393 > );
1394 >
1395 > updateTreeMetadata(this, node, size_delta, lf_delta);
1396 > }
1398 > private deleteNodeHead(node: TreeNode, pos: BufferCursor) {
1399 > const piece = node.piece; pieceTreeBase.ts
1400 > const originalLFCnt = piece.lineFeedCnt;
1401 > const originalStartOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);
1402 >
1403 > const newStart = pos;
1404 > const newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, newStart, piece.end);
1405 > const newStartOffset = this.offsetInBuffer(piece.bufferIndex, newStart);
1406 > const lf_delta = newLineFeedCnt - originalLFCnt;
1407 > const size_delta = originalStartOffset - newStartOffset;
1408 > const newLength = piece.length + size_delta;
1409 > node.piece = new Piece(
1410 > piece.bufferIndex,
1411 > newStart,
1412 > piece.end,
1413 > newLineFeedCnt,
1414 > newLength
1415 > );
1416 >
1417 > updateTreeMetadata(this, node, size_delta, lf_delta);
1418 > }
1420 > private shrinkNode(node: TreeNode, start: BufferCursor, end: BufferCursor) {
1421 > const piece = node.piece; pieceTreeBase.ts
1422 > const originalStartPos = piece.start;
1423 > const originalEndPos = piece.end;
1424 >
1425 > // old piece, originalStartPos, start
1426 > const oldLength = piece.length;
1427 > const oldLFCnt = piece.lineFeedCnt;
1428 > const newEnd = start;
1429 > const newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, piece.start, newEnd);
1430 > const newLength = this.offsetInBuffer(piece.bufferIndex, start) - this.offsetInBuffer(piece.bufferIndex, originalStartPos);
1431 >
1432 > node.piece = new Piece(
1433 > piece.bufferIndex,
1434 > piece.start,
1435 > newEnd,
1436 > newLineFeedCnt,
1437 > newLength
1438 > );
1439 >
1440 > updateTreeMetadata(this, node, newLength - oldLength, newLineFeedCnt - oldLFCnt);
1441 >
1442 > // new right piece, end, originalEndPos
1443 > const newPiece = new Piece(
1444 > piece.bufferIndex,
1445 > end,
1446 > originalEndPos,
1447 > this.getLineFeedCnt(piece.bufferIndex, end, originalEndPos),
1448 > this.offsetInBuffer(piece.bufferIndex, originalEndPos) - this.offsetInBuffer(piece.bufferIndex, end)
1449 > );
1450 >
1451 > const newNode = this.rbInsertRight(node, newPiece);
1452 > this.validateCRLFWithPrevNode(newNode);
1453 > }
1455 > private appendToNode(node: TreeNode, value: string): void {
1456 if (this.adjustCarriageReturnFromNext(value, node)) {
1457 value += '\n';
1492 updateTreeMetadata(this, node, value.length, lf_delta);
1493 }
1495 > private nodeAt(offset: number): NodePosition {
1496 > let x = this.root; pieceTreeBase.ts
1497 > const cache = this._searchCache.get(offset);
1498 > if (cache) {
1499 > return { pieceTreeBase.ts
1500 > node: cache.node,
1501 > nodeStartOffset: cache.nodeStartOffset,
1502 > remainder: offset - cache.nodeStartOffset
1503 > };
1504 > }
1506 > let nodeStartOffset = 0;
1507 >
1508 > while (x !== SENTINEL) {
1509 > if (x.size_left > offset) {
1510 > x = x.left; pieceTreeBase.ts
1511 > } else if (x.size_left + x.piece.length >= offset) { pieceTreeBase.ts
1512 > nodeStartOffset += x.size_left;
1513 > const ret = {
1514 > node: x,
1515 > remainder: offset - x.size_left,
1516 > nodeStartOffset
1517 > };
1518 > this._searchCache.set(ret);
1519 > return ret;
1520 > } else {
1521 > offset -= x.size_left + x.piece.length; pieceTreeBase.ts
1522 > nodeStartOffset += x.size_left + x.piece.length;
1523 > x = x.right;
1524 > }
1525 > } pieceTreeBase.ts
1526
1527 return null!;
1528 > } pieceTreeBase.ts
1530 > private nodeAt2(lineNumber: number, column: number): NodePosition {
1531 let x = this.root;
1532 let nodeStartOffset = 0;
1594 return null!;
1595 }
1597 > private nodeCharCodeAt(node: TreeNode, offset: number): number {
1598 > if (node.piece.lineFeedCnt < 1) { pieceTreeBase.ts
1599 return -1;
1600 }
1601 > const buffer = this._buffers[node.piece.bufferIndex]; pieceTreeBase.ts
1602 > const newOffset = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start) + offset;
1603 > return buffer.buffer.charCodeAt(newOffset);
1604 > }
1606 > private offsetOfNode(node: TreeNode): number {
1607 if (!node) {
1608 return 0;
1619 return pos;
1620 }
1622 > // #endregion
1623 >
1624 > // #region CRLF
1625 > private shouldCheckCRLF() {
1626 > return !(this._EOLNormalized && this._EOL === '\n'); pieceTreeBase.ts
1627 > }
1629 > private startWithLF(val: string | TreeNode): boolean {
1630 > if (typeof val === 'string') { pieceTreeBase.ts
1631 > return val.charCodeAt(0) === 10; pieceTreeBase.ts
1632 > }
1634 > if (val === SENTINEL || val.piece.lineFeedCnt === 0) { pieceTreeBase.ts
1635 return false;
1636 }
1638 > const piece = val.piece;
1639 > const lineStarts = this._buffers[piece.bufferIndex].lineStarts;
1640 > const line = piece.start.line;
1641 > const startOffset = lineStarts[line] + piece.start.column;
1642 > if (line === lineStarts.length - 1) {
1643 // last line, so there is no line feed at the end of this line
1644 return false;
1645 }
1646 > const nextLineOffset = lineStarts[line + 1]; pieceTreeBase.ts
1647 > if (nextLineOffset > startOffset + 1) {
1648 > return false; pieceTreeBase.ts
1649 > }
1650 return this._buffers[piece.bufferIndex].buffer.charCodeAt(startOffset) === 10;
1651 > } pieceTreeBase.ts
1653 > private endWithCR(val: string | TreeNode): boolean {
1654 > if (typeof val === 'string') { pieceTreeBase.ts
1655 > return val.charCodeAt(val.length - 1) === 13; pieceTreeBase.ts
1656 > }
1658 > if (val === SENTINEL || val.piece.lineFeedCnt === 0) { pieceTreeBase.ts
1659 > return false; pieceTreeBase.ts
1660 > }
1662 > return this.nodeCharCodeAt(val, val.piece.length - 1) === 13;
1663 > } pieceTreeBase.ts
1665 > private validateCRLFWithPrevNode(nextNode: TreeNode) {
1666 > if (this.shouldCheckCRLF() && this.startWithLF(nextNode)) { pieceTreeBase.ts
1667 const node = nextNode.prev();
1668 if (this.endWithCR(node)) {
1670 }
1671 }
1672 > } pieceTreeBase.ts
1674 > private validateCRLFWithNextNode(node: TreeNode) {
1675 > if (this.shouldCheckCRLF() && this.endWithCR(node)) { pieceTreeBase.ts
1676 const nextNode = node.next();
1677 if (this.startWithLF(nextNode)) {
1679 }
1680 }
1681 > } pieceTreeBase.ts
1683 > private fixCRLF(prev: TreeNode, next: TreeNode) {
1684 const nodesToDel: TreeNode[] = [];
1685 // update node
1735 }
1736 }
1738 > private adjustCarriageReturnFromNext(value: string, node: TreeNode): boolean {
1739 > if (this.shouldCheckCRLF() && this.endWithCR(value)) { pieceTreeBase.ts
1740 const nextNode = node.next();
1741 if (this.startWithLF(nextNode)) {
1764 }
1765 }
1767 > return false;
1768 > } pieceTreeBase.ts
1770 > // #endregion
1771 >
1772 > // #endregion
1773 >
1774 > // #region Tree operations
1775 > iterate(node: TreeNode, callback: (node: TreeNode) => boolean): boolean {
1776 > if (node === SENTINEL) { pieceTreeBase.ts
1777 > return callback(SENTINEL);
1778 > }
1780 > const leftRet = this.iterate(node.left, callback);
1781 > if (!leftRet) {
1782 return leftRet;
1783 }
1785 > return callback(node) && this.iterate(node.right, callback);
1786 > } pieceTreeBase.ts
1788 > private getNodeContent(node: TreeNode) {
1789 > if (node === SENTINEL) { pieceTreeBase.ts
1790 > return ''; pieceTreeBase.ts
1791 > }
1792 > const buffer = this._buffers[node.piece.bufferIndex]; pieceTreeBase.ts
1793 > const piece = node.piece;
1794 > const startOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);
1795 > const endOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);
1796 > const currentContent = buffer.buffer.substring(startOffset, endOffset);
1797 > return currentContent;
1798 > }
1800 > getPieceContent(piece: Piece) {
1801 const buffer = this._buffers[piece.bufferIndex];
1802 const startOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);
1805 return currentContent;
1806 }
1808 > /**
1809 > * node node
1810 > * / \ / \
1811 > * a b <---- a b
1812 > * /
1813 > * z
1814 > */
1815 > private rbInsertRight(node: TreeNode | null, p: Piece): TreeNode {
1816 > const z = new TreeNode(p, NodeColor.Red); pieceTreeBase.ts
1817 > z.left = SENTINEL;
1818 > z.right = SENTINEL;
1819 > z.parent = SENTINEL;
1820 > z.size_left = 0;
1821 > z.lf_left = 0;
1822 >
1823 > const x = this.root;
1824 > if (x === SENTINEL) {
1825 this.root = z;
1826 z.color = NodeColor.Black;
1827 > } else if (node!.right === SENTINEL) { pieceTreeBase.ts
1828 > node!.right = z; pieceTreeBase.ts
1829 > z.parent = node!;
1830 > } else {
1831 > const nextNode = leftest(node!.right); pieceTreeBase.ts
1832 > nextNode.left = z;
1833 > z.parent = nextNode;
1834 > }
1836 > fixInsert(this, z);
1837 > return z;
1838 > }
1840 > /**
1841 > * node node
1842 > * / \ / \
1843 > * a b ----> a b
1844 > * \
1845 > * z
1846 > */
1847 > private rbInsertLeft(node: TreeNode | null, p: Piece): TreeNode {
1848 > const z = new TreeNode(p, NodeColor.Red); pieceTreeBase.ts
1849 > z.left = SENTINEL;
1850 > z.right = SENTINEL;
1851 > z.parent = SENTINEL;
1852 > z.size_left = 0;
1853 > z.lf_left = 0;
1854 >
1855 > if (this.root === SENTINEL) {
1856 > this.root = z; pieceTreeBase.ts
1857 > z.color = NodeColor.Black;
1858 > } else if (node!.left === SENTINEL) { pieceTreeBase.ts
1859 node!.left = z;
1860 z.parent = node!;
1864 z.parent = prevNode;
1865 }
1867 > fixInsert(this, z);
1868 > return z;
1869 > }
1871 > private getContentOfSubTree(node: TreeNode): string {
1872 > let str = ''; pieceTreeBase.ts
1873 >
1874 > this.iterate(node, node => {
1875 > str += this.getNodeContent(node);
1876 > return true;
1877 > });
1878 >
1879 > return str;
1880 > }
1881 > // #endregion pieceTreeBase.ts
1882 > }
src/vs/platform/contextkey/common/contextkey.ts 832 covered LOC · 218 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- contextkey.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 { Event } from '../../../base/common/event.js';
8 > import { isChrome, isEdge, isFirefox, isLinux, isMacintosh, isSafari, isWeb, isWindows } from '../../../base/common/platform.js';
9 > import { isFalsyOrWhitespace } from '../../../base/common/strings.js';
10 > import { Scanner, LexingError, Token, TokenType } from './scanner.js';
11 > import { createDecorator } from '../../instantiation/common/instantiation.js';
12 > import { localize } from '../../../nls.js';
13 > import { IDisposable } from '../../../base/common/lifecycle.js';
14 > import { illegalArgument } from '../../../base/common/errors.js';
15 >
16 > const CONSTANT_VALUES = new Map<string, boolean>();
17 > CONSTANT_VALUES.set('false', false);
18 > CONSTANT_VALUES.set('true', true);
19 > CONSTANT_VALUES.set('isMac', isMacintosh);
20 > CONSTANT_VALUES.set('isLinux', isLinux);
21 > CONSTANT_VALUES.set('isWindows', isWindows);
22 > CONSTANT_VALUES.set('isWeb', isWeb);
23 > CONSTANT_VALUES.set('isMacNative', isMacintosh && !isWeb);
24 > CONSTANT_VALUES.set('isEdge', isEdge);
25 > CONSTANT_VALUES.set('isFirefox', isFirefox);
26 > CONSTANT_VALUES.set('isChrome', isChrome);
27 > CONSTANT_VALUES.set('isSafari', isSafari);
28 >
29 > /** allow register constant context keys that are known only after startup; requires running `substituteConstants` on the context key - https://github.com/microsoft/vscode/issues/174218#issuecomment-1437972127 */
30 > export function setConstant(key: string, value: boolean) {
31 if (CONSTANT_VALUES.get(key) !== undefined) { throw illegalArgument('contextkey.setConstant(k, v) invoked with already set constant `k`'); }
32
33 CONSTANT_VALUES.set(key, value);
34 }
36 > const hasOwnProperty = Object.prototype.hasOwnProperty;
37 >
38 > export const enum ContextKeyExprType {
39 > False = 0,
40 > True = 1,
41 > Defined = 2,
42 > Not = 3,
43 > Equals = 4,
44 > NotEquals = 5,
45 > And = 6,
46 > Regex = 7,
47 > NotRegex = 8,
48 > Or = 9,
49 > In = 10,
50 > NotIn = 11,
51 > Greater = 12,
52 > GreaterEquals = 13,
53 > Smaller = 14,
54 > SmallerEquals = 15,
55 > }
56 >
57 > export interface IContextKeyExprMapper {
58 > mapDefined(key: string): ContextKeyExpression;
59 > mapNot(key: string): ContextKeyExpression;
60 > mapEquals(key: string, value: any): ContextKeyExpression;
61 > mapNotEquals(key: string, value: any): ContextKeyExpression;
62 > mapGreater(key: string, value: any): ContextKeyExpression;
63 > mapGreaterEquals(key: string, value: any): ContextKeyExpression;
64 > mapSmaller(key: string, value: any): ContextKeyExpression;
65 > mapSmallerEquals(key: string, value: any): ContextKeyExpression;
66 > mapRegex(key: string, regexp: RegExp | null): ContextKeyRegexExpr;
67 > mapIn(key: string, valueKey: string): ContextKeyInExpr;
68 > mapNotIn(key: string, valueKey: string): ContextKeyNotInExpr;
69 > }
70 >
71 > export interface IContextKeyExpression {
72 > cmp(other: ContextKeyExpression): number;
73 > equals(other: ContextKeyExpression): boolean;
74 > substituteConstants(): ContextKeyExpression | undefined;
75 > evaluate(context: IContext): boolean;
76 > serialize(): string;
77 > keys(): string[];
78 > map(mapFnc: IContextKeyExprMapper): ContextKeyExpression;
79 > negate(): ContextKeyExpression;
80 >
81 > }
82 >
83 > export type ContextKeyExpression = (
84 > ContextKeyFalseExpr | ContextKeyTrueExpr | ContextKeyDefinedExpr | ContextKeyNotExpr
85 > | ContextKeyEqualsExpr | ContextKeyNotEqualsExpr | ContextKeyRegexExpr
86 > | ContextKeyNotRegexExpr | ContextKeyAndExpr | ContextKeyOrExpr | ContextKeyInExpr
87 > | ContextKeyNotInExpr | ContextKeyGreaterExpr | ContextKeyGreaterEqualsExpr
88 > | ContextKeySmallerExpr | ContextKeySmallerEqualsExpr
89 > );
90 >
91 >
92 > /*
93 >
94 > Syntax grammar:
95 >
96 > ```ebnf
97 >
98 > expression ::= or
99 >
100 > or ::= and { '||' and }*
101 >
102 > and ::= term { '&&' term }*
103 >
104 > term ::=
105 > | '!' (KEY | true | false | parenthesized)
106 > | primary
107 >
108 > primary ::=
109 > | 'true'
110 > | 'false'
111 > | parenthesized
112 > | KEY '=~' REGEX
113 > | KEY [ ('==' | '!=' | '<' | '<=' | '>' | '>=' | 'not' 'in' | 'in') value ]
114 >
115 > parenthesized ::=
116 > | '(' expression ')'
117 >
118 > value ::=
119 > | 'true'
120 > | 'false'
121 > | 'in' // we support `in` as a value because there's an extension that uses it, ie "when": "languageId == in"
122 > | VALUE // matched by the same regex as KEY; consider putting the value in single quotes if it's a string (e.g., with spaces)
123 > | SINGLE_QUOTED_STR
124 > | EMPTY_STR // this allows "when": "foo == " which's used by existing extensions
125 >
126 > ```
127 > */
128 >
129 > export type ParserConfig = {
130 > /**
131 > * with this option enabled, the parser can recover from regex parsing errors, e.g., unescaped slashes: `/src//` is accepted as `/src\//` would be
132 > */
133 > regexParsingWithErrorRecovery: boolean;
134 > };
135 >
136 > const defaultConfig: ParserConfig = {
137 > regexParsingWithErrorRecovery: true
138 > };
139 >
140 > export type ParsingError = {
141 > message: string;
142 > offset: number;
143 > lexeme: string;
144 > additionalInfo?: string;
145 > };
146 >
147 > const errorEmptyString = localize('contextkey.parser.error.emptyString', "Empty context key expression");
148 > const hintEmptyString = localize('contextkey.parser.error.emptyString.hint', "Did you forget to write an expression? You can also put 'false' or 'true' to always evaluate to false or true, respectively.");
149 > const errorNoInAfterNot = localize('contextkey.parser.error.noInAfterNot', "'in' after 'not'.");
150 > const errorClosingParenthesis = localize('contextkey.parser.error.closingParenthesis', "closing parenthesis ')'");
151 > const errorUnexpectedToken = localize('contextkey.parser.error.unexpectedToken', "Unexpected token");
152 > const hintUnexpectedToken = localize('contextkey.parser.error.unexpectedToken.hint', "Did you forget to put && or || before the token?");
153 > const errorUnexpectedEOF = localize('contextkey.parser.error.unexpectedEOF', "Unexpected end of expression");
154 > const hintUnexpectedEOF = localize('contextkey.parser.error.unexpectedEOF.hint', "Did you forget to put a context key?");
155 >
156 > /**
157 > * A parser for context key expressions.
158 > *
159 > * Example:
160 > * ```ts
161 > * const parser = new Parser();
162 > * const expr = parser.parse('foo == "bar" && baz == true');
163 > *
164 > * if (expr === undefined) {
165 > * // there were lexing or parsing errors
166 > * // process lexing errors with `parser.lexingErrors`
167 > * // process parsing errors with `parser.parsingErrors`
168 > * } else {
169 > * // expr is a valid expression
170 > * }
171 > * ```
172 > */
173 > export class Parser {
174 > // Note: this doesn't produce an exact syntax tree but a normalized one
175 > // ContextKeyExpression's that we use as AST nodes do not expose constructors that do not normalize
176 >
177 > private static _parseError = new Error();
178 >
179 > // lifetime note: `_scanner` lives as long as the parser does, i.e., is not reset between calls to `parse`
180 > private readonly _scanner = new Scanner();
181 >
182 > // lifetime note: `_tokens`, `_current`, and `_parsingErrors` must be reset between calls to `parse`
183 > private _tokens: Token[] = [];
184 > private _current = 0; // invariant: 0 <= this._current < this._tokens.length ; any incrementation of this value must first call `_isAtEnd`
185 > private _parsingErrors: ParsingError[] = [];
186 >
187 > get lexingErrors(): Readonly<LexingError[]> {
188 return this._scanner.errors;
189 }
191 > get parsingErrors(): Readonly<ParsingError[]> {
192 return this._parsingErrors;
193 }
195 > constructor(private readonly _config: ParserConfig = defaultConfig) {
196 > }
197 >
198 > /**
199 > * Parse a context key expression.
200 > *
201 > * @param input the expression to parse
202 > * @returns the parsed expression or `undefined` if there's an error - call `lexingErrors` and `parsingErrors` to see the errors
203 > */
204 > parse(input: string): ContextKeyExpression | undefined {
205
206 if (input === '') {
231 }
232 }
234 > private _expr(): ContextKeyExpression | undefined {
235 return this._or();
236 }
238 > private _or(): ContextKeyExpression | undefined {
239 const expr = [this._and()];
240
246 return expr.length === 1 ? expr[0] : ContextKeyExpr.or(...expr);
247 }
249 > private _and(): ContextKeyExpression | undefined {
250 const expr = [this._term()];
251
257 return expr.length === 1 ? expr[0] : ContextKeyExpr.and(...expr);
258 }
260 > private _term(): ContextKeyExpression | undefined {
261 if (this._matchOne(TokenType.Neg)) {
262 const peek = this._peek();
283 return this._primary();
284 }
286 > private _primary(): ContextKeyExpression | undefined {
287
288 const peek = this._peek();
498 }
499 }
501 > private _value(): string {
502 const token = this._peek();
503 switch (token.type) {
521 }
522 }
524 > private _flagsGYRe = /g|y/g;
525 > private _removeFlagsGY(flags: string): string {
526 return flags.replaceAll(this._flagsGYRe, '');
527 }
529 > // careful: this can throw if current token is the initial one (ie index = 0)
530 > private _previous() {
531 return this._tokens[this._current - 1];
532 }
534 > private _matchOne(token: TokenType) {
535 if (this._check(token)) {
536 this._advance();
540 return false;
541 }
543 > private _advance() {
544 if (!this._isAtEnd()) {
545 this._current++;
547 return this._previous();
548 }
550 > private _consume(type: TokenType, message: string) {
551 if (this._check(type)) {
552 return this._advance();
555 throw this._errExpectedButGot(message, this._peek());
556 }
558 > private _errExpectedButGot(expected: string, got: Token, additionalInfo?: string) {
559 const message = localize('contextkey.parser.error.expectedButGot', "Expected: {0}\nReceived: '{1}'.", expected, Scanner.getLexeme(got));
560 const offset = got.offset;
563 return Parser._parseError;
564 }
566 > private _check(type: TokenType) {
567 return this._peek().type === type;
568 }
570 > private _peek() {
571 return this._tokens[this._current];
572 }
574 > private _isAtEnd() {
575 return this._peek().type === TokenType.EOF;
576 }
577 > } contextkey.ts
578 >
579 > export abstract class ContextKeyExpr {
580 >
581 > public static false(): ContextKeyExpression {
582 return ContextKeyFalseExpr.INSTANCE;
583 }
584 > public static true(): ContextKeyExpression { contextkey.ts
585 return ContextKeyTrueExpr.INSTANCE;
586 }
587 > public static has(key: string): ContextKeyExpression { contextkey.ts
588 return ContextKeyDefinedExpr.create(key);
589 }
590 > public static equals(key: string, value: any): ContextKeyExpression { contextkey.ts
591 return ContextKeyEqualsExpr.create(key, value);
592 }
593 > public static notEquals(key: string, value: any): ContextKeyExpression { contextkey.ts
594 return ContextKeyNotEqualsExpr.create(key, value);
595 }
596 > public static regex(key: string, value: RegExp): ContextKeyExpression { contextkey.ts
597 return ContextKeyRegexExpr.create(key, value);
598 }
599 > public static in(key: string, value: string): ContextKeyExpression { contextkey.ts
600 return ContextKeyInExpr.create(key, value);
601 }
602 > public static notIn(key: string, value: string): ContextKeyExpression { contextkey.ts
603 return ContextKeyNotInExpr.create(key, value);
604 }
605 > public static not(key: string): ContextKeyExpression { contextkey.ts
606 return ContextKeyNotExpr.create(key);
607 }
608 > public static and(...expr: Array<ContextKeyExpression | undefined | null>): ContextKeyExpression | undefined { contextkey.ts
609 return ContextKeyAndExpr.create(expr, null, true);
610 }
611 > public static or(...expr: Array<ContextKeyExpression | undefined | null>): ContextKeyExpression | undefined { contextkey.ts
612 return ContextKeyOrExpr.create(expr, null, true);
613 }
614 > public static greater(key: string, value: number): ContextKeyExpression { contextkey.ts
615 return ContextKeyGreaterExpr.create(key, value);
616 }
617 > public static greaterEquals(key: string, value: number): ContextKeyExpression { contextkey.ts
618 return ContextKeyGreaterEqualsExpr.create(key, value);
619 }
620 > public static smaller(key: string, value: number): ContextKeyExpression { contextkey.ts
621 return ContextKeySmallerExpr.create(key, value);
622 }
623 > public static smallerEquals(key: string, value: number): ContextKeyExpression { contextkey.ts
624 return ContextKeySmallerEqualsExpr.create(key, value);
625 }
627 > private static _parser = new Parser({ regexParsingWithErrorRecovery: false });
628 > public static deserialize(serialized: string | null | undefined): ContextKeyExpression | undefined {
629 if (serialized === undefined || serialized === null) { // an empty string needs to be handled by the parser to get a corresponding parsing error reported
630 return undefined;
634 return expr;
635 }
637 > }
638 >
639 >
640 > export function validateWhenClauses(whenClauses: string[]): any {
641
642 const parser = new Parser({ regexParsingWithErrorRecovery: false }); // we run with no recovery to guide users to use correct regexes
664 });
665 }
667 > export function expressionsAreEqualWithConstantSubstitution(a: ContextKeyExpression | null | undefined, b: ContextKeyExpression | null | undefined): boolean {
668 const aExpr = a ? a.substituteConstants() : undefined;
669 const bExpr = b ? b.substituteConstants() : undefined;
676 return aExpr.equals(bExpr);
677 }
679 function cmp(a: ContextKeyExpression, b: ContextKeyExpression): number {
680 return a.cmp(b);
681 }
683 > export class ContextKeyFalseExpr implements IContextKeyExpression {
684 > public static INSTANCE = new ContextKeyFalseExpr();
685 >
686 > public readonly type = ContextKeyExprType.False;
687 >
688 > protected constructor() {
689 > }
690 >
691 > public cmp(other: ContextKeyExpression): number {
692 return this.type - other.type;
693 }
695 > public equals(other: ContextKeyExpression): boolean {
696 return (other.type === this.type);
697 }
699 > public substituteConstants(): ContextKeyExpression | undefined {
700 return this;
701 }
703 > public evaluate(context: IContext): boolean {
704 return false;
705 }
707 > public serialize(): string {
708 return 'false';
709 }
711 > public keys(): string[] {
712 return [];
713 }
715 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
716 return this;
717 }
719 > public negate(): ContextKeyExpression {
720 return ContextKeyTrueExpr.INSTANCE;
721 }
722 > } contextkey.ts
723 >
724 > export class ContextKeyTrueExpr implements IContextKeyExpression {
725 > public static INSTANCE = new ContextKeyTrueExpr();
726 >
727 > public readonly type = ContextKeyExprType.True;
728 >
729 > protected constructor() {
730 > }
731 >
732 > public cmp(other: ContextKeyExpression): number {
733 return this.type - other.type;
734 }
736 > public equals(other: ContextKeyExpression): boolean {
737 return (other.type === this.type);
738 }
740 > public substituteConstants(): ContextKeyExpression | undefined {
741 return this;
742 }
744 > public evaluate(context: IContext): boolean {
745 return true;
746 }
748 > public serialize(): string {
749 return 'true';
750 }
752 > public keys(): string[] {
753 return [];
754 }
756 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
757 return this;
758 }
760 > public negate(): ContextKeyExpression {
761 return ContextKeyFalseExpr.INSTANCE;
762 }
763 > } contextkey.ts
764 >
765 > export class ContextKeyDefinedExpr implements IContextKeyExpression {
766 > public static create(key: string, negated: ContextKeyExpression | null = null): ContextKeyExpression {
767 > const constantValue = CONSTANT_VALUES.get(key);
768 > if (typeof constantValue === 'boolean') {
769 > return constantValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE; contextkey.ts
770 > }
771 > return new ContextKeyDefinedExpr(key, negated); contextkey.ts
772 > }
773 >
774 > public readonly type = ContextKeyExprType.Defined;
775 >
776 > protected constructor(
777 > readonly key: string, contextkey.ts
778 > private negated: ContextKeyExpression | null
779 > ) {
780 > }
782 > public cmp(other: ContextKeyExpression): number {
783 if (other.type !== this.type) {
784 return this.type - other.type;
786 return cmp1(this.key, other.key);
787 }
789 > public equals(other: ContextKeyExpression): boolean {
790 if (other.type === this.type) {
791 return (this.key === other.key);
793 return false;
794 }
796 > public substituteConstants(): ContextKeyExpression | undefined {
797 const constantValue = CONSTANT_VALUES.get(this.key);
798 if (typeof constantValue === 'boolean') {
801 return this;
802 }
804 > public evaluate(context: IContext): boolean {
805 return (!!context.getValue(this.key));
806 }
808 > public serialize(): string {
809 return this.key;
810 }
812 > public keys(): string[] {
813 return [this.key];
814 }
816 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
817 return mapFnc.mapDefined(this.key);
818 }
820 > public negate(): ContextKeyExpression {
821 if (!this.negated) {
822 this.negated = ContextKeyNotExpr.create(this.key, this);
824 return this.negated;
825 }
826 > } contextkey.ts
827 >
828 > export class ContextKeyEqualsExpr implements IContextKeyExpression {
829 >
830 > public static create(key: string, value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {
831 > if (typeof value === 'boolean') {
832 > return (value ? ContextKeyDefinedExpr.create(key, negated) : ContextKeyNotExpr.create(key, negated)); contextkey.ts
833 > }
834 > const constantValue = CONSTANT_VALUES.get(key); contextkey.ts
835 > if (typeof constantValue === 'boolean') {
836 > const trueValue = constantValue ? 'true' : 'false'; contextkey.ts
837 > return (value === trueValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE);
838 > }
839 > return new ContextKeyEqualsExpr(key, value, negated); contextkey.ts
840 > } contextkey.ts
841 >
842 > public readonly type = ContextKeyExprType.Equals;
843 >
844 > private constructor(
845 private readonly key: string,
846 private readonly value: any,
848 ) {
849 }
851 > public cmp(other: ContextKeyExpression): number {
852 if (other.type !== this.type) {
853 return this.type - other.type;
855 return cmp2(this.key, this.value, other.key, other.value);
856 }
858 > public equals(other: ContextKeyExpression): boolean {
859 if (other.type === this.type) {
860 return (this.key === other.key && this.value === other.value);
862 return false;
863 }
865 > public substituteConstants(): ContextKeyExpression | undefined {
866 const constantValue = CONSTANT_VALUES.get(this.key);
867 if (typeof constantValue === 'boolean') {
871 return this;
872 }
874 > public evaluate(context: IContext): boolean {
875 // Intentional ==
876 // eslint-disable-next-line eqeqeq
877 return (context.getValue(this.key) == this.value);
878 }
880 > public serialize(): string {
881 return `${this.key} == '${this.value}'`;
882 }
884 > public keys(): string[] {
885 return [this.key];
886 }
888 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
889 return mapFnc.mapEquals(this.key, this.value);
890 }
892 > public negate(): ContextKeyExpression {
893 if (!this.negated) {
894 this.negated = ContextKeyNotEqualsExpr.create(this.key, this.value, this);
896 return this.negated;
897 }
898 > } contextkey.ts
899 >
900 > export class ContextKeyInExpr implements IContextKeyExpression {
901 >
902 > public static create(key: string, valueKey: string): ContextKeyInExpr {
903 > return new ContextKeyInExpr(key, valueKey);
904 > }
905 >
906 > public readonly type = ContextKeyExprType.In;
907 > private negated: ContextKeyExpression | null = null;
908 >
909 > private constructor(
910 private readonly key: string,
911 private readonly valueKey: string,
912 ) {
913 }
915 > public cmp(other: ContextKeyExpression): number {
916 if (other.type !== this.type) {
917 return this.type - other.type;
919 return cmp2(this.key, this.valueKey, other.key, other.valueKey);
920 }
922 > public equals(other: ContextKeyExpression): boolean {
923 if (other.type === this.type) {
924 return (this.key === other.key && this.valueKey === other.valueKey);
926 return false;
927 }
929 > public substituteConstants(): ContextKeyExpression | undefined {
930 return this;
931 }
933 > public evaluate(context: IContext): boolean {
934 const source = context.getValue(this.valueKey);
935
964 return false;
965 }
967 > public serialize(): string {
968 return `${this.key} in '${this.valueKey}'`;
969 }
971 > public keys(): string[] {
972 return [this.key, this.valueKey];
973 }
975 > public map(mapFnc: IContextKeyExprMapper): ContextKeyInExpr {
976 return mapFnc.mapIn(this.key, this.valueKey);
977 }
979 > public negate(): ContextKeyExpression {
980 if (!this.negated) {
981 this.negated = ContextKeyNotInExpr.create(this.key, this.valueKey);
983 return this.negated;
984 }
985 > } contextkey.ts
986 >
987 > export class ContextKeyNotInExpr implements IContextKeyExpression {
988 >
989 > public static create(key: string, valueKey: string): ContextKeyNotInExpr {
990 > return new ContextKeyNotInExpr(key, valueKey);
991 > }
992 >
993 > public readonly type = ContextKeyExprType.NotIn;
994 >
995 > private readonly _negated: ContextKeyInExpr;
996 >
997 > private constructor(
998 private readonly key: string,
999 private readonly valueKey: string,
1001 this._negated = ContextKeyInExpr.create(key, valueKey);
1002 }
1003 > contextkey.ts
1004 > public cmp(other: ContextKeyExpression): number {
1005 if (other.type !== this.type) {
1006 return this.type - other.type;
1008 return this._negated.cmp(other._negated);
1009 }
1010 > contextkey.ts
1011 > public equals(other: ContextKeyExpression): boolean {
1012 if (other.type === this.type) {
1013 return this._negated.equals(other._negated);
1015 return false;
1016 }
1017 > contextkey.ts
1018 > public substituteConstants(): ContextKeyExpression | undefined {
1019 return this;
1020 }
1021 > contextkey.ts
1022 > public evaluate(context: IContext): boolean {
1023 return !this._negated.evaluate(context);
1024 }
1025 > contextkey.ts
1026 > public serialize(): string {
1027 return `${this.key} not in '${this.valueKey}'`;
1028 }
1029 > contextkey.ts
1030 > public keys(): string[] {
1031 return this._negated.keys();
1032 }
1033 > contextkey.ts
1034 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1035 return mapFnc.mapNotIn(this.key, this.valueKey);
1036 }
1037 > contextkey.ts
1038 > public negate(): ContextKeyExpression {
1039 return this._negated;
1040 }
1041 > } contextkey.ts
1042 >
1043 > export class ContextKeyNotEqualsExpr implements IContextKeyExpression {
1044 >
1045 > public static create(key: string, value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {
1046 > if (typeof value === 'boolean') {
1047 > if (value) { contextkey.ts
1048 > return ContextKeyNotExpr.create(key, negated); contextkey.ts
1049 > }
1050 > return ContextKeyDefinedExpr.create(key, negated); contextkey.ts
1051 > }
1052 > const constantValue = CONSTANT_VALUES.get(key); contextkey.ts
1053 > if (typeof constantValue === 'boolean') {
1054 > const falseValue = constantValue ? 'true' : 'false'; contextkey.ts
1055 > return (value === falseValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);
1056 > }
1057 > return new ContextKeyNotEqualsExpr(key, value, negated); contextkey.ts
1058 > } contextkey.ts
1059 >
1060 > public readonly type = ContextKeyExprType.NotEquals;
1061 >
1062 > private constructor(
1063 private readonly key: string,
1064 private readonly value: any,
1066 ) {
1067 }
1068 > contextkey.ts
1069 > public cmp(other: ContextKeyExpression): number {
1070 if (other.type !== this.type) {
1071 return this.type - other.type;
1073 return cmp2(this.key, this.value, other.key, other.value);
1074 }
1075 > contextkey.ts
1076 > public equals(other: ContextKeyExpression): boolean {
1077 if (other.type === this.type) {
1078 return (this.key === other.key && this.value === other.value);
1080 return false;
1081 }
1082 > contextkey.ts
1083 > public substituteConstants(): ContextKeyExpression | undefined {
1084 const constantValue = CONSTANT_VALUES.get(this.key);
1085 if (typeof constantValue === 'boolean') {
1089 return this;
1090 }
1091 > contextkey.ts
1092 > public evaluate(context: IContext): boolean {
1093 // Intentional !=
1094 // eslint-disable-next-line eqeqeq
1095 return (context.getValue(this.key) != this.value);
1096 }
1097 > contextkey.ts
1098 > public serialize(): string {
1099 return `${this.key} != '${this.value}'`;
1100 }
1101 > contextkey.ts
1102 > public keys(): string[] {
1103 return [this.key];
1104 }
1105 > contextkey.ts
1106 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1107 return mapFnc.mapNotEquals(this.key, this.value);
1108 }
1109 > contextkey.ts
1110 > public negate(): ContextKeyExpression {
1111 if (!this.negated) {
1112 this.negated = ContextKeyEqualsExpr.create(this.key, this.value, this);
1114 return this.negated;
1115 }
1116 > } contextkey.ts
1117 >
1118 > export class ContextKeyNotExpr implements IContextKeyExpression {
1119 >
1120 > public static create(key: string, negated: ContextKeyExpression | null = null): ContextKeyExpression {
1121 > const constantValue = CONSTANT_VALUES.get(key);
1122 > if (typeof constantValue === 'boolean') {
1123 > return (constantValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE); contextkey.ts
1124 > }
1125 > return new ContextKeyNotExpr(key, negated); contextkey.ts
1126 > }
1127 >
1128 > public readonly type = ContextKeyExprType.Not;
1129 >
1130 > private constructor(
1131 private readonly key: string,
1132 private negated: ContextKeyExpression | null
1133 ) {
1134 }
1135 > contextkey.ts
1136 > public cmp(other: ContextKeyExpression): number {
1137 if (other.type !== this.type) {
1138 return this.type - other.type;
1140 return cmp1(this.key, other.key);
1141 }
1142 > contextkey.ts
1143 > public equals(other: ContextKeyExpression): boolean {
1144 if (other.type === this.type) {
1145 return (this.key === other.key);
1147 return false;
1148 }
1149 > contextkey.ts
1150 > public substituteConstants(): ContextKeyExpression | undefined {
1151 const constantValue = CONSTANT_VALUES.get(this.key);
1152 if (typeof constantValue === 'boolean') {
1155 return this;
1156 }
1157 > contextkey.ts
1158 > public evaluate(context: IContext): boolean {
1159 return (!context.getValue(this.key));
1160 }
1161 > contextkey.ts
1162 > public serialize(): string {
1163 return `!${this.key}`;
1164 }
1165 > contextkey.ts
1166 > public keys(): string[] {
1167 return [this.key];
1168 }
1169 > contextkey.ts
1170 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1171 return mapFnc.mapNot(this.key);
1172 }
1173 > contextkey.ts
1174 > public negate(): ContextKeyExpression {
1175 if (!this.negated) {
1176 this.negated = ContextKeyDefinedExpr.create(this.key, this);
1178 return this.negated;
1179 }
1180 > } contextkey.ts
1181 >
1182 function withFloatOrStr<T extends ContextKeyExpression>(value: any, callback: (value: number | string) => T): T | ContextKeyFalseExpr {
1183 if (typeof value === 'string') {
1192 return ContextKeyFalseExpr.INSTANCE;
1193 }
1194 > contextkey.ts
1195 > export class ContextKeyGreaterExpr implements IContextKeyExpression {
1196 >
1197 > public static create(key: string, _value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {
1198 > return withFloatOrStr(_value, (value) => new ContextKeyGreaterExpr(key, value, negated));
1199 > }
1200 >
1201 > public readonly type = ContextKeyExprType.Greater;
1202 >
1203 > private constructor(
1204 private readonly key: string,
1205 private readonly value: number | string,
1206 private negated: ContextKeyExpression | null
1207 ) { }
1208 > contextkey.ts
1209 > public cmp(other: ContextKeyExpression): number {
1210 if (other.type !== this.type) {
1211 return this.type - other.type;
1213 return cmp2(this.key, this.value, other.key, other.value);
1214 }
1215 > contextkey.ts
1216 > public equals(other: ContextKeyExpression): boolean {
1217 if (other.type === this.type) {
1218 return (this.key === other.key && this.value === other.value);
1220 return false;
1221 }
1222 > contextkey.ts
1223 > public substituteConstants(): ContextKeyExpression | undefined {
1224 return this;
1225 }
1226 > contextkey.ts
1227 > public evaluate(context: IContext): boolean {
1228 if (typeof this.value === 'string') {
1229 return false;
1231 return (parseFloat(context.getValue<any>(this.key)) > this.value);
1232 }
1233 > contextkey.ts
1234 > public serialize(): string {
1235 return `${this.key} > ${this.value}`;
1236 }
1237 > contextkey.ts
1238 > public keys(): string[] {
1239 return [this.key];
1240 }
1241 > contextkey.ts
1242 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1243 return mapFnc.mapGreater(this.key, this.value);
1244 }
1245 > contextkey.ts
1246 > public negate(): ContextKeyExpression {
1247 if (!this.negated) {
1248 this.negated = ContextKeySmallerEqualsExpr.create(this.key, this.value, this);
1250 return this.negated;
1251 }
1252 > } contextkey.ts
1253 >
1254 > export class ContextKeyGreaterEqualsExpr implements IContextKeyExpression {
1255 >
1256 > public static create(key: string, _value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {
1257 > return withFloatOrStr(_value, (value) => new ContextKeyGreaterEqualsExpr(key, value, negated));
1258 > }
1259 >
1260 > public readonly type = ContextKeyExprType.GreaterEquals;
1261 >
1262 > private constructor(
1263 private readonly key: string,
1264 private readonly value: number | string,
1265 private negated: ContextKeyExpression | null
1266 ) { }
1267 > contextkey.ts
1268 > public cmp(other: ContextKeyExpression): number {
1269 if (other.type !== this.type) {
1270 return this.type - other.type;
1272 return cmp2(this.key, this.value, other.key, other.value);
1273 }
1274 > contextkey.ts
1275 > public equals(other: ContextKeyExpression): boolean {
1276 if (other.type === this.type) {
1277 return (this.key === other.key && this.value === other.value);
1279 return false;
1280 }
1281 > contextkey.ts
1282 > public substituteConstants(): ContextKeyExpression | undefined {
1283 return this;
1284 }
1285 > contextkey.ts
1286 > public evaluate(context: IContext): boolean {
1287 if (typeof this.value === 'string') {
1288 return false;
1290 return (parseFloat(context.getValue<any>(this.key)) >= this.value);
1291 }
1292 > contextkey.ts
1293 > public serialize(): string {
1294 return `${this.key} >= ${this.value}`;
1295 }
1296 > contextkey.ts
1297 > public keys(): string[] {
1298 return [this.key];
1299 }
1300 > contextkey.ts
1301 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1302 return mapFnc.mapGreaterEquals(this.key, this.value);
1303 }
1304 > contextkey.ts
1305 > public negate(): ContextKeyExpression {
1306 if (!this.negated) {
1307 this.negated = ContextKeySmallerExpr.create(this.key, this.value, this);
1309 return this.negated;
1310 }
1311 > } contextkey.ts
1312 >
1313 > export class ContextKeySmallerExpr implements IContextKeyExpression {
1314 >
1315 > public static create(key: string, _value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {
1316 > return withFloatOrStr(_value, (value) => new ContextKeySmallerExpr(key, value, negated));
1317 > }
1318 >
1319 > public readonly type = ContextKeyExprType.Smaller;
1320 >
1321 > private constructor(
1322 private readonly key: string,
1323 private readonly value: number | string,
1325 ) {
1326 }
1327 > contextkey.ts
1328 > public cmp(other: ContextKeyExpression): number {
1329 if (other.type !== this.type) {
1330 return this.type - other.type;
1332 return cmp2(this.key, this.value, other.key, other.value);
1333 }
1334 > contextkey.ts
1335 > public equals(other: ContextKeyExpression): boolean {
1336 if (other.type === this.type) {
1337 return (this.key === other.key && this.value === other.value);
1339 return false;
1340 }
1341 > contextkey.ts
1342 > public substituteConstants(): ContextKeyExpression | undefined {
1343 return this;
1344 }
1345 > contextkey.ts
1346 > public evaluate(context: IContext): boolean {
1347 if (typeof this.value === 'string') {
1348 return false;
1350 return (parseFloat(context.getValue<any>(this.key)) < this.value);
1351 }
1352 > contextkey.ts
1353 > public serialize(): string {
1354 return `${this.key} < ${this.value}`;
1355 }
1356 > contextkey.ts
1357 > public keys(): string[] {
1358 return [this.key];
1359 }
1360 > contextkey.ts
1361 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1362 return mapFnc.mapSmaller(this.key, this.value);
1363 }
1364 > contextkey.ts
1365 > public negate(): ContextKeyExpression {
1366 if (!this.negated) {
1367 this.negated = ContextKeyGreaterEqualsExpr.create(this.key, this.value, this);
1369 return this.negated;
1370 }
1371 > } contextkey.ts
1372 >
1373 > export class ContextKeySmallerEqualsExpr implements IContextKeyExpression {
1374 >
1375 > public static create(key: string, _value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {
1376 > return withFloatOrStr(_value, (value) => new ContextKeySmallerEqualsExpr(key, value, negated));
1377 > }
1378 >
1379 > public readonly type = ContextKeyExprType.SmallerEquals;
1380 >
1381 > private constructor(
1382 private readonly key: string,
1383 private readonly value: number | string,
1385 ) {
1386 }
1387 > contextkey.ts
1388 > public cmp(other: ContextKeyExpression): number {
1389 if (other.type !== this.type) {
1390 return this.type - other.type;
1392 return cmp2(this.key, this.value, other.key, other.value);
1393 }
1394 > contextkey.ts
1395 > public equals(other: ContextKeyExpression): boolean {
1396 if (other.type === this.type) {
1397 return (this.key === other.key && this.value === other.value);
1399 return false;
1400 }
1401 > contextkey.ts
1402 > public substituteConstants(): ContextKeyExpression | undefined {
1403 return this;
1404 }
1405 > contextkey.ts
1406 > public evaluate(context: IContext): boolean {
1407 if (typeof this.value === 'string') {
1408 return false;
1410 return (parseFloat(context.getValue<any>(this.key)) <= this.value);
1411 }
1412 > contextkey.ts
1413 > public serialize(): string {
1414 return `${this.key} <= ${this.value}`;
1415 }
1416 > contextkey.ts
1417 > public keys(): string[] {
1418 return [this.key];
1419 }
1420 > contextkey.ts
1421 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1422 return mapFnc.mapSmallerEquals(this.key, this.value);
1423 }
1424 > contextkey.ts
1425 > public negate(): ContextKeyExpression {
1426 if (!this.negated) {
1427 this.negated = ContextKeyGreaterExpr.create(this.key, this.value, this);
1429 return this.negated;
1430 }
1431 > } contextkey.ts
1432 >
1433 > export class ContextKeyRegexExpr implements IContextKeyExpression {
1434 >
1435 > public static create(key: string, regexp: RegExp | null): ContextKeyRegexExpr {
1436 > return new ContextKeyRegexExpr(key, regexp);
1437 > }
1438 >
1439 > public readonly type = ContextKeyExprType.Regex;
1440 > private negated: ContextKeyExpression | null = null;
1441 >
1442 > private constructor(
1443 private readonly key: string,
1444 private readonly regexp: RegExp | null
1446 //
1447 }
1448 > contextkey.ts
1449 > public cmp(other: ContextKeyExpression): number {
1450 if (other.type !== this.type) {
1451 return this.type - other.type;
1467 return 0;
1468 }
1469 > contextkey.ts
1470 > public equals(other: ContextKeyExpression): boolean {
1471 if (other.type === this.type) {
1472 const thisSource = this.regexp ? this.regexp.source : '';
1476 return false;
1477 }
1478 > contextkey.ts
1479 > public substituteConstants(): ContextKeyExpression | undefined {
1480 return this;
1481 }
1482 > contextkey.ts
1483 > public evaluate(context: IContext): boolean {
1484 const value = context.getValue<any>(this.key);
1485 return this.regexp ? this.regexp.test(value) : false;
1486 }
1487 > contextkey.ts
1488 > public serialize(): string {
1489 const value = this.regexp
1490 ? `/${this.regexp.source}/${this.regexp.flags}`
1492 return `${this.key} =~ ${value}`;
1493 }
1494 > contextkey.ts
1495 > public keys(): string[] {
1496 return [this.key];
1497 }
1498 > contextkey.ts
1499 > public map(mapFnc: IContextKeyExprMapper): ContextKeyRegexExpr {
1500 return mapFnc.mapRegex(this.key, this.regexp);
1501 }
1502 > contextkey.ts
1503 > public negate(): ContextKeyExpression {
1504 if (!this.negated) {
1505 this.negated = ContextKeyNotRegexExpr.create(this);
1507 return this.negated;
1508 }
1509 > } contextkey.ts
1510 >
1511 > export class ContextKeyNotRegexExpr implements IContextKeyExpression {
1512 >
1513 > public static create(actual: ContextKeyRegexExpr): ContextKeyExpression {
1514 > return new ContextKeyNotRegexExpr(actual);
1515 > }
1516 >
1517 > public readonly type = ContextKeyExprType.NotRegex;
1518 >
1519 > private constructor(private readonly _actual: ContextKeyRegexExpr) {
1520 //
1521 }
1522 > contextkey.ts
1523 > public cmp(other: ContextKeyExpression): number {
1524 if (other.type !== this.type) {
1525 return this.type - other.type;
1527 return this._actual.cmp(other._actual);
1528 }
1529 > contextkey.ts
1530 > public equals(other: ContextKeyExpression): boolean {
1531 if (other.type === this.type) {
1532 return this._actual.equals(other._actual);
1534 return false;
1535 }
1536 > contextkey.ts
1537 > public substituteConstants(): ContextKeyExpression | undefined {
1538 return this;
1539 }
1540 > contextkey.ts
1541 > public evaluate(context: IContext): boolean {
1542 return !this._actual.evaluate(context);
1543 }
1544 > contextkey.ts
1545 > public serialize(): string {
1546 return `!(${this._actual.serialize()})`;
1547 }
1548 > contextkey.ts
1549 > public keys(): string[] {
1550 return this._actual.keys();
1551 }
1552 > contextkey.ts
1553 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1554 return new ContextKeyNotRegexExpr(this._actual.map(mapFnc));
1555 }
1556 > contextkey.ts
1557 > public negate(): ContextKeyExpression {
1558 return this._actual;
1559 }
1560 > } contextkey.ts
1561 >
1562 > /**
1563 > * @returns the same instance if nothing changed.
1564 > */
1565 function eliminateConstantsInArray(arr: ContextKeyExpression[]): (ContextKeyExpression | undefined)[] {
1566 // Allocate array only if there is a difference
1591 return newArr;
1592 }
1593 > contextkey.ts
1594 > export class ContextKeyAndExpr implements IContextKeyExpression {
1595 >
1596 > public static create(_expr: ReadonlyArray<ContextKeyExpression | null | undefined>, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {
1597 > return ContextKeyAndExpr._normalizeArr(_expr, negated, extraRedundantCheck);
1598 > }
1599 >
1600 > public readonly type = ContextKeyExprType.And;
1601 >
1602 > private constructor(
1603 public readonly expr: ContextKeyExpression[],
1604 private negated: ContextKeyExpression | null
1605 ) {
1606 }
1607 > contextkey.ts
1608 > public cmp(other: ContextKeyExpression): number {
1609 if (other.type !== this.type) {
1610 return this.type - other.type;
1624 return 0;
1625 }
1626 > contextkey.ts
1627 > public equals(other: ContextKeyExpression): boolean {
1628 if (other.type === this.type) {
1629 if (this.expr.length !== other.expr.length) {
1639 return false;
1640 }
1641 > contextkey.ts
1642 > public substituteConstants(): ContextKeyExpression | undefined {
1643 const exprArr = eliminateConstantsInArray(this.expr);
1644 if (exprArr === this.expr) {
1648 return ContextKeyAndExpr.create(exprArr, this.negated, false);
1649 }
1650 > contextkey.ts
1651 > public evaluate(context: IContext): boolean {
1652 for (let i = 0, len = this.expr.length; i < len; i++) {
1653 if (!this.expr[i].evaluate(context)) {
1657 return true;
1658 }
1659 > contextkey.ts
1660 > private static _normalizeArr(arr: ReadonlyArray<ContextKeyExpression | null | undefined>, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {
1661 const expr: ContextKeyExpression[] = [];
1662 let hasTrue = false;
1762 return new ContextKeyAndExpr(expr, negated);
1763 }
1764 > contextkey.ts
1765 > public serialize(): string {
1766 return this.expr.map(e => e.serialize()).join(' && ');
1767 }
1768 > contextkey.ts
1769 > public keys(): string[] {
1770 const result: string[] = [];
1771 for (const expr of this.expr) {
1774 return result;
1775 }
1776 > contextkey.ts
1777 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1778 return new ContextKeyAndExpr(this.expr.map(expr => expr.map(mapFnc)), null);
1779 }
1780 > contextkey.ts
1781 > public negate(): ContextKeyExpression {
1782 if (!this.negated) {
1783 const result: ContextKeyExpression[] = [];
1789 return this.negated;
1790 }
1791 > } contextkey.ts
1792 >
1793 > export class ContextKeyOrExpr implements IContextKeyExpression {
1794 >
1795 > public static create(_expr: ReadonlyArray<ContextKeyExpression | null | undefined>, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {
1796 > return ContextKeyOrExpr._normalizeArr(_expr, negated, extraRedundantCheck);
1797 > }
1798 >
1799 > public readonly type = ContextKeyExprType.Or;
1800 >
1801 > private constructor(
1802 public readonly expr: ContextKeyExpression[],
1803 private negated: ContextKeyExpression | null
1804 ) {
1805 }
1806 > contextkey.ts
1807 > public cmp(other: ContextKeyExpression): number {
1808 if (other.type !== this.type) {
1809 return this.type - other.type;
1823 return 0;
1824 }
1825 > contextkey.ts
1826 > public equals(other: ContextKeyExpression): boolean {
1827 if (other.type === this.type) {
1828 if (this.expr.length !== other.expr.length) {
1838 return false;
1839 }
1840 > contextkey.ts
1841 > public substituteConstants(): ContextKeyExpression | undefined {
1842 const exprArr = eliminateConstantsInArray(this.expr);
1843 if (exprArr === this.expr) {
1847 return ContextKeyOrExpr.create(exprArr, this.negated, false);
1848 }
1849 > contextkey.ts
1850 > public evaluate(context: IContext): boolean {
1851 for (let i = 0, len = this.expr.length; i < len; i++) {
1852 if (this.expr[i].evaluate(context)) {
1856 return false;
1857 }
1858 > contextkey.ts
1859 > private static _normalizeArr(arr: ReadonlyArray<ContextKeyExpression | null | undefined>, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {
1860 let expr: ContextKeyExpression[] = [];
1861 let hasFalse = false;
1932 return new ContextKeyOrExpr(expr, negated);
1933 }
1934 > contextkey.ts
1935 > public serialize(): string {
1936 return this.expr.map(e => e.serialize()).join(' || ');
1937 }
1938 > contextkey.ts
1939 > public keys(): string[] {
1940 const result: string[] = [];
1941 for (const expr of this.expr) {
1944 return result;
1945 }
1946 > contextkey.ts
1947 > public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression {
1948 return new ContextKeyOrExpr(this.expr.map(expr => expr.map(mapFnc)), null);
1949 }
1950 > contextkey.ts
1951 > public negate(): ContextKeyExpression {
1952 if (!this.negated) {
1953 const result: ContextKeyExpression[] = [];
1976 return this.negated;
1977 }
1978 > } contextkey.ts
1979 >
1980 > export interface ContextKeyInfo {
1981 > readonly key: string;
1982 > readonly type?: string;
1983 > readonly description?: string;
1984 > }
1985 >
1986 > export class RawContextKey<T extends ContextKeyValue> extends ContextKeyDefinedExpr {
1987 >
1988 > private static _info: ContextKeyInfo[] = [];
1989 >
1990 > static all(): IterableIterator<ContextKeyInfo> {
1991 return RawContextKey._info.values();
1992 }
1993 > contextkey.ts
1994 > private readonly _defaultValue: T | undefined;
1995 >
1996 > constructor(key: string, defaultValue: T | undefined, metaOrHide?: string | true | { type: string; description: string }) {
1997 > super(key, null); contextkey.ts
1998 > this._defaultValue = defaultValue;
1999 >
2000 > // collect all context keys into a central place
2001 > if (typeof metaOrHide === 'object') {
2002 RawContextKey._info.push({ ...metaOrHide, key });
2003 > } else if (metaOrHide !== true) { contextkey.ts
2004 > RawContextKey._info.push({ key, description: metaOrHide, type: defaultValue !== null && defaultValue !== undefined ? typeof defaultValue : undefined }); contextkey.ts
2005 > }
2006 > } contextkey.ts
2007 > contextkey.ts
2008 > public bindTo(target: IContextKeyService): IContextKey<T> {
2009 return target.createKey(this.key, this._defaultValue);
2010 }
2011 > contextkey.ts
2012 > public getValue(target: IContextKeyService): T | undefined {
2013 return target.getContextKeyValue<T>(this.key);
2014 }
2015 > contextkey.ts
2016 > public toNegated(): ContextKeyExpression {
2017 return this.negate();
2018 }
2019 > contextkey.ts
2020 > public isEqualTo(value: any): ContextKeyExpression {
2021 return ContextKeyEqualsExpr.create(this.key, value);
2022 }
2023 > contextkey.ts
2024 > public notEqualsTo(value: any): ContextKeyExpression {
2025 return ContextKeyNotEqualsExpr.create(this.key, value);
2026 }
2027 > contextkey.ts
2028 > public greater(value: any): ContextKeyExpression {
2029 return ContextKeyGreaterExpr.create(this.key, value);
2030 }
2031 > } contextkey.ts
2032 >
2033 > export type ContextKeyValue = null | undefined | boolean | number | string
2034 > | Array<null | undefined | boolean | number | string>
2035 > | Record<string, null | undefined | boolean | number | string>;
2036 >
2037 > export interface IContext {
2038 > getValue<T extends ContextKeyValue = ContextKeyValue>(key: string): T | undefined;
2039 > }
2040 >
2041 > export interface IContextKey<T extends ContextKeyValue = ContextKeyValue> {
2042 > set(value: T): void;
2043 > reset(): void;
2044 > get(): T | undefined;
2045 > }
2046 >
2047 > export interface IContextKeyServiceTarget {
2048 > parentElement: IContextKeyServiceTarget | null;
2049 > setAttribute(attr: string, value: string): void;
2050 > removeAttribute(attr: string): void;
2051 > hasAttribute(attr: string): boolean;
2052 > getAttribute(attr: string): string | null;
2053 > }
2054 >
2055 > export const IContextKeyService = createDecorator<IContextKeyService>('contextKeyService');
2056 >
2057 > export interface IReadableSet<T> {
2058 > has(value: T): boolean;
2059 > }
2060 >
2061 > export interface IContextKeyChangeEvent {
2062 > affectsSome(keys: IReadableSet<string>): boolean;
2063 > allKeysContainedIn(keys: IReadableSet<string>): boolean;
2064 > }
2065 >
2066 > export type IScopedContextKeyService = IContextKeyService & IDisposable;
2067 >
2068 > export interface IContextKeyService {
2069 > readonly _serviceBrand: undefined;
2070 >
2071 > readonly onDidChangeContext: Event<IContextKeyChangeEvent>;
2072 > bufferChangeEvents(callback: Function): void;
2073 >
2074 > createKey<T extends ContextKeyValue>(key: string, defaultValue: T | undefined): IContextKey<T>;
2075 > contextMatchesRules(rules: ContextKeyExpression | undefined): boolean;
2076 > getContextKeyValue<T>(key: string): T | undefined;
2077 >
2078 > createScoped(target: IContextKeyServiceTarget): IScopedContextKeyService;
2079 > createOverlay(overlay: Iterable<[string, any]>): IContextKeyService;
2080 > getContext(target: IContextKeyServiceTarget | null): IContext;
2081 >
2082 > updateParent(parentContextKeyService: IContextKeyService): void;
2083 > }
2084 >
2085 function cmp1(key1: string, key2: string): number {
2086 if (key1 < key2) {
2092 return 0;
2093 }
2094 > contextkey.ts
2095 function cmp2(key1: string, value1: any, key2: string, value2: any): number {
2096 if (key1 < key2) {
2108 return 0;
2109 }
2110 > contextkey.ts
2111 > /**
2112 > * Returns true if it is provable `p` implies `q`.
2113 > */
2114 > export function implies(p: ContextKeyExpression, q: ContextKeyExpression): boolean {
2115
2116 if (p.type === ContextKeyExprType.False || q.type === ContextKeyExprType.True) {
2152 return p.equals(q);
2153 }
2154 > contextkey.ts
2155 > /**
2156 > * Returns true if all elements in `p` are also present in `q`.
2157 > * The two arrays are assumed to be sorted
2158 > */
2159 function allElementsIncluded(p: ContextKeyExpression[], q: ContextKeyExpression[]): boolean {
2160 let pIndex = 0;
2175 return (pIndex === p.length);
2176 }
2177 > contextkey.ts
2178 function getTerminals(node: ContextKeyExpression) {
2179 if (node.type === ContextKeyExprType.Or) {
src/vs/editor/common/model/textModel.ts 780 covered LOC · 190 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModel.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 { pushMany } from '../../../base/common/arrays.js';
7 > import { VSBuffer, VSBufferReadableStream } from '../../../base/common/buffer.js';
8 > import { CharCode } from '../../../base/common/charCode.js';
9 > import { SetWithKey } from '../../../base/common/collections.js';
10 > import { Color } from '../../../base/common/color.js';
11 > import { BugIndicatingError, illegalArgument, onUnexpectedError } from '../../../base/common/errors.js';
12 > import { Emitter, Event } from '../../../base/common/event.js';
13 > import { IMarkdownString } from '../../../base/common/htmlContent.js';
14 > import { Disposable, IDisposable, MutableDisposable } from '../../../base/common/lifecycle.js';
15 > import { listenStream } from '../../../base/common/stream.js';
16 > import * as strings from '../../../base/common/strings.js';
17 > import { ThemeColor } from '../../../base/common/themables.js';
18 > import { Constants } from '../../../base/common/uint.js';
19 > import { URI } from '../../../base/common/uri.js';
20 > import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
21 > import { isDark } from '../../../platform/theme/common/theme.js';
22 > import { IColorTheme } from '../../../platform/theme/common/themeService.js';
23 > import { IUndoRedoService, ResourceEditStackSnapshot, UndoRedoGroup } from '../../../platform/undoRedo/common/undoRedo.js';
24 > import { ISingleEditOperation } from '../core/editOperation.js';
25 > import { TextEdit } from '../core/edits/textEdit.js';
26 > import { countEOL } from '../core/misc/eolCounter.js';
27 > import { normalizeIndentation } from '../core/misc/indentation.js';
28 > import { EDITOR_MODEL_DEFAULTS } from '../core/misc/textModelDefaults.js';
29 > import { IPosition, Position } from '../core/position.js';
30 > import { IRange, Range } from '../core/range.js';
31 > import { Selection } from '../core/selection.js';
32 > import { TextChange } from '../core/textChange.js';
33 > import { IWordAtPosition } from '../core/wordHelper.js';
34 > import { FormattingOptions } from '../languages.js';
35 > import { ILanguageSelection, ILanguageService } from '../languages/language.js';
36 > import { ILanguageConfigurationService } from '../languages/languageConfigurationRegistry.js';
37 > import * as model from '../model.js';
38 > import { IBracketPairsTextModelPart } from '../textModelBracketPairs.js';
39 > import { EditSources, TextModelEditSource } from '../textModelEditSource.js';
40 > import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelOptionsChangedEvent, InternalModelContentChangeEvent, LineInjectedText, ModelFontChanged, ModelFontChangedEvent, ModelInjectedTextChangedEvent, ModelLineHeightChanged, ModelLineHeightChangedEvent, ModelRawChange, ModelRawContentChangedEvent, ModelRawEOLChanged, ModelRawFlush, ModelRawLineChanged, ModelRawLinesDeleted, ModelRawLinesInserted } from '../textModelEvents.js';
41 > import { IGuidesTextModelPart } from '../textModelGuides.js';
42 > import { ITokenizationTextModelPart } from '../tokenizationTextModelPart.js';
43 > import { LineTokens, TokenArray } from '../tokens/lineTokens.js';
44 > import { BracketPairsTextModelPart } from './bracketPairsTextModelPart/bracketPairsImpl.js';
45 > import { ColorizedBracketPairsDecorationProvider } from './bracketPairsTextModelPart/colorizedBracketPairsDecorationProvider.js';
46 > import { EditStack } from './editStack.js';
47 > import { GuidesTextModelPart } from './guidesTextModelPart.js';
48 > import { guessIndentation } from './indentationGuesser.js';
49 > import { IntervalNode, IntervalTree, recomputeMaxEnd } from './intervalTree.js';
50 > import { PieceTreeTextBuffer } from './pieceTreeTextBuffer/pieceTreeTextBuffer.js';
51 > import { PieceTreeTextBufferBuilder } from './pieceTreeTextBuffer/pieceTreeTextBufferBuilder.js';
52 > import { SearchParams, TextModelSearch } from './textModelSearch.js';
53 > import { AttachedViews } from './tokens/abstractSyntaxTokenBackend.js';
54 > import { TokenizationFontDecorationProvider } from './tokens/tokenizationFontDecorationsProvider.js';
55 > import { LineFontChangingDecoration, LineHeightChangingDecoration } from './decorationProvider.js';
56 > import { TokenizationTextModelPart } from './tokens/tokenizationTextModelPart.js';
57 > import { IViewModel } from '../viewModel.js';
58 >
59 > export function createTextBufferFactory(text: string): model.ITextBufferFactory {
60 const builder = new PieceTreeTextBufferBuilder();
61 builder.acceptChunk(text);
62 return builder.finish();
63 }
65 > interface ITextStream {
66 > on(event: 'data', callback: (data: string) => void): void;
67 > on(event: 'error', callback: (err: Error) => void): void;
68 > on(event: 'end', callback: () => void): void;
69 > on(event: string, callback: (...args: unknown[]) => void): void;
70 > }
71 >
72 > export function createTextBufferFactoryFromStream(stream: ITextStream): Promise<model.ITextBufferFactory>;
73 > export function createTextBufferFactoryFromStream(stream: VSBufferReadableStream): Promise<model.ITextBufferFactory>;
74 > export function createTextBufferFactoryFromStream(stream: ITextStream | VSBufferReadableStream): Promise<model.ITextBufferFactory> {
75 return new Promise<model.ITextBufferFactory>((resolve, reject) => {
76 const builder = new PieceTreeTextBufferBuilder();
97 });
98 }
100 > export function createTextBufferFactoryFromSnapshot(snapshot: model.ITextSnapshot): model.ITextBufferFactory {
101 const builder = new PieceTreeTextBufferBuilder();
102
108 return builder.finish();
109 }
110 > textModel.ts
111 > export function createTextBuffer(value: string | model.ITextBufferFactory | model.ITextSnapshot, defaultEOL: model.DefaultEndOfLine): { textBuffer: model.ITextBuffer; disposable: IDisposable } {
112 let factory: model.ITextBufferFactory;
113 if (typeof value === 'string') {
120 return factory.create(defaultEOL);
121 }
122 > textModel.ts
123 > let MODEL_ID = 0;
124 >
125 > const LIMIT_FIND_COUNT = 999;
126 > const LONG_LINE_BOUNDARY = 10000;
127 > const LINE_HEIGHT_CEILING = 300;
128 >
129 > class TextModelSnapshot implements model.ITextSnapshot {
130 >
131 > private readonly _source: model.ITextSnapshot;
132 > private _eos: boolean;
133 >
134 > constructor(source: model.ITextSnapshot) {
135 this._source = source;
136 this._eos = false;
137 }
138 > textModel.ts
139 > public read(): string | null {
140 if (this._eos) {
141 return null;
169 } while (true);
170 }
171 > } textModel.ts
172 >
173 > const invalidFunc = () => { throw new Error(`Invalid change accessor`); };
174 >
175 > const enum StringOffsetValidationType {
176 > /**
177 > * Even allowed in surrogate pairs
178 > */
179 > Relaxed = 0,
180 > /**
181 > * Not allowed in surrogate pairs
182 > */
183 > SurrogatePairs = 1,
184 > }
185 >
186 > export class TextModel extends Disposable implements model.ITextModel, IDecorationsTreesHost {
187 >
188 > static _MODEL_SYNC_LIMIT = 50 * 1024 * 1024; // 50 MB, // used in tests
189 > private static readonly LARGE_FILE_SIZE_THRESHOLD = 20 * 1024 * 1024; // 20 MB;
190 > private static readonly LARGE_FILE_LINE_COUNT_THRESHOLD = 300 * 1000; // 300K lines
191 > private static readonly LARGE_FILE_HEAP_OPERATION_THRESHOLD = 256 * 1024 * 1024; // 256M characters, usually ~> 512MB memory usage
192 >
193 > public static DEFAULT_CREATION_OPTIONS: model.ITextModelCreationOptions = {
194 > isForSimpleWidget: false,
195 > tabSize: EDITOR_MODEL_DEFAULTS.tabSize,
196 > indentSize: EDITOR_MODEL_DEFAULTS.indentSize,
197 > insertSpaces: EDITOR_MODEL_DEFAULTS.insertSpaces,
198 > detectIndentation: false,
199 > defaultEOL: model.DefaultEndOfLine.LF,
200 > trimAutoWhitespace: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace,
201 > largeFileOptimizations: EDITOR_MODEL_DEFAULTS.largeFileOptimizations,
202 > bracketPairColorizationOptions: EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions,
203 > };
204 >
205 > public static resolveOptions(textBuffer: model.ITextBuffer, options: model.ITextModelCreationOptions): model.TextModelResolvedOptions {
206 if (options.detectIndentation) {
207 const guessedIndentation = guessIndentation(textBuffer, options.tabSize, options.insertSpaces);
218 return new model.TextModelResolvedOptions(options);
219 }
220 > textModel.ts
221 > //#region Events
222 > private readonly _onWillDispose: Emitter<void> = this._register(new Emitter<void>());
223 > public readonly onWillDispose: Event<void> = this._onWillDispose.event;
224 >
225 > private readonly _onDidChangeDecorations: DidChangeDecorationsEmitter = this._register(new DidChangeDecorationsEmitter((affectedInjectedTextLines, affectedLineHeights, affectedFontLines) => this.handleBeforeFireDecorationsChangedEvent(affectedInjectedTextLines, affectedLineHeights, affectedFontLines)));
226 > public readonly onDidChangeDecorations: Event<IModelDecorationsChangedEvent> = this._onDidChangeDecorations.event;
227 >
228 > public get onDidChangeLanguage() { return this._tokenizationTextModelPart.onDidChangeLanguage; }
229 > public get onDidChangeLanguageConfiguration() { return this._tokenizationTextModelPart.onDidChangeLanguageConfiguration; }
230 > public get onDidChangeTokens() { return this._tokenizationTextModelPart.onDidChangeTokens; }
231 >
232 > private readonly _onDidChangeOptions: Emitter<IModelOptionsChangedEvent> = this._register(new Emitter<IModelOptionsChangedEvent>());
233 > public get onDidChangeOptions(): Event<IModelOptionsChangedEvent> { return this._onDidChangeOptions.event; }
234 >
235 > private readonly _onDidChangeAttached: Emitter<void> = this._register(new Emitter<void>());
236 > public get onDidChangeAttached(): Event<void> { return this._onDidChangeAttached.event; }
237 >
238 > private readonly _onDidChangeLineHeight: Emitter<ModelLineHeightChangedEvent> = this._register(new Emitter<ModelLineHeightChangedEvent>());
239 > public get onDidChangeLineHeight(): Event<ModelLineHeightChangedEvent> { return this._onDidChangeLineHeight.event; }
240 >
241 > private readonly _onDidChangeFont: Emitter<ModelFontChangedEvent> = this._register(new Emitter<ModelFontChangedEvent>());
242 > public get onDidChangeFont(): Event<ModelFontChangedEvent> { return this._onDidChangeFont.event; }
243 >
244 > private readonly _eventEmitter: DidChangeContentEmitter = this._register(new DidChangeContentEmitter());
245 > public onDidChangeContent(listener: (e: IModelContentChangedEvent) => void): IDisposable {
246 return this._eventEmitter.event((e: InternalModelContentChangeEvent) => listener(e.contentChangedEvent));
247 }
248 > //#endregion textModel.ts
249 >
250 > public readonly id: string;
251 > public readonly isForSimpleWidget: boolean;
252 > private readonly _associatedResource: URI;
253 > private _attachedEditorCount: number;
254 > private _buffer: model.ITextBuffer;
255 > private _bufferDisposable: IDisposable;
256 > private _options: model.TextModelResolvedOptions;
257 > private readonly _languageSelectionListener = this._register(new MutableDisposable<IDisposable>());
258 >
259 > private _isDisposed: boolean;
260 > private __isDisposing: boolean;
261 > public _isDisposing(): boolean { return this.__isDisposing; }
262 > private _versionId: number;
263 > /**
264 > * Unlike, versionId, this can go down (via undo) or go to previous values (via redo)
265 > */
266 > private _alternativeVersionId: number;
267 > private _initialUndoRedoSnapshot: ResourceEditStackSnapshot | null;
268 > private readonly _isTooLargeForSyncing: boolean;
269 > private readonly _isTooLargeForTokenization: boolean;
270 > private readonly _isTooLargeForHeapOperation: boolean;
271 >
272 > //#region Editing
273 > private readonly _commandManager: EditStack;
274 > private _isUndoing: boolean;
275 > private _isRedoing: boolean;
276 > private _trimAutoWhitespaceLines: number[] | null;
277 > //#endregion
278 >
279 > //#region Decorations
280 > /**
281 > * Used to workaround broken clients that might attempt using a decoration id generated by a different model.
282 > * It is not globally unique in order to limit it to one character.
283 > */
284 > private readonly _instanceId: string;
285 > private _deltaDecorationCallCnt: number = 0;
286 > private _lastDecorationId: number;
287 > private _decorations: { [decorationId: string]: IntervalNode };
288 > private _decorationsTree: DecorationsTrees;
289 > private readonly _decorationProvider: ColorizedBracketPairsDecorationProvider;
290 > private readonly _fontTokenDecorationsProvider: TokenizationFontDecorationProvider;
291 > //#endregion
292 >
293 > private readonly _tokenizationTextModelPart: TokenizationTextModelPart;
294 > public get tokenization(): ITokenizationTextModelPart { return this._tokenizationTextModelPart; }
295 >
296 > private readonly _bracketPairs: BracketPairsTextModelPart;
297 > public get bracketPairs(): IBracketPairsTextModelPart { return this._bracketPairs; }
298 >
299 > private readonly _guidesTextModelPart: GuidesTextModelPart;
300 > public get guides(): IGuidesTextModelPart { return this._guidesTextModelPart; }
301 >
302 > private readonly _attachedViews = this._register(new AttachedViews());
303 > private readonly _viewModels = new Set<IViewModel>();
304 >
305 > constructor(
306 source: string | model.ITextBufferFactory,
307 languageIdOrSelection: string | ILanguageSelection,
411 }));
412 }
413 > textModel.ts
414 > public override dispose(): void {
415 this.__isDisposing = true;
416 this._onWillDispose.fire();
427 this._bufferDisposable = Disposable.None;
428 }
429 > textModel.ts
430 > _hasListeners(): boolean {
431 return (
432 this._onWillDispose.hasListeners()
440 );
441 }
442 > textModel.ts
443 > private _assertNotDisposed(): void {
444 if (this._isDisposed) {
445 throw new BugIndicatingError('Model is disposed!');
446 }
447 }
448 > textModel.ts
449 > public registerViewModel(viewModel: IViewModel): void {
450 this._viewModels.add(viewModel);
451 }
452 > textModel.ts
453 > public unregisterViewModel(viewModel: IViewModel): void {
454 this._viewModels.delete(viewModel);
455 }
456 > textModel.ts
457 > public equalsTextBuffer(other: model.ITextBuffer): boolean {
458 this._assertNotDisposed();
459 return this._buffer.equals(other);
460 }
461 > textModel.ts
462 > public getTextBuffer(): model.ITextBuffer {
463 this._assertNotDisposed();
464 return this._buffer;
465 }
466 > textModel.ts
467 > private _emitContentChangedEvent(rawChange: ModelRawContentChangedEvent, change: IModelContentChangedEvent, resultingSelection: Selection[] | null = null): void {
468 if (this.__isDisposing) {
469 // Do not confuse listeners by emitting any event after disposing
481 this._eventEmitter.fire(contentChangeEvent);
482 }
483 > textModel.ts
484 > public setValue(value: string | model.ITextSnapshot, reason = EditSources.setValue()): void {
485 this._assertNotDisposed();
486
492 this._setValueFromTextBuffer(textBuffer, disposable, reason);
493 }
494 > textModel.ts
495 > private _createContentChanged2(range: Range, rangeOffset: number, rangeLength: number, rangeEndPosition: Position, text: string, isUndoing: boolean, isRedoing: boolean, isFlush: boolean, isEolChange: boolean, reason: TextModelEditSource): IModelContentChangedEvent {
496 return {
497 changes: [{
511 };
512 }
513 > textModel.ts
514 > private _setValueFromTextBuffer(textBuffer: model.ITextBuffer, textBufferDisposable: IDisposable, reason: TextModelEditSource): void {
515 this._assertNotDisposed();
516 const oldFullModelRange = this.getFullModelRange();
544 );
545 }
546 > textModel.ts
547 > public setEOL(eol: model.EndOfLineSequence): void {
548 this._assertNotDisposed();
549 const newEOL = (eol === model.EndOfLineSequence.CRLF ? '\r\n' : '\n');
575 );
576 }
577 > textModel.ts
578 > private _onBeforeEOLChange(): void {
579 // Ensure all decorations get their `range` set.
580 this._decorationsTree.ensureAllNodesHaveRanges(this);
581 }
582 > textModel.ts
583 > private _onAfterEOLChange(): void {
584 // Transform back `range` to offsets
585 const versionId = this.getVersionId();
604 }
605 }
606 > textModel.ts
607 > public onBeforeAttached(): model.IAttachedView {
608 this._attachedEditorCount++;
609 if (this._attachedEditorCount === 1) {
613 return this._attachedViews.attachView();
614 }
615 > textModel.ts
616 > public onBeforeDetached(view: model.IAttachedView): void {
617 this._attachedEditorCount--;
618 if (this._attachedEditorCount === 0) {
622 this._attachedViews.detachView(view);
623 }
624 > textModel.ts
625 > public isAttachedToEditor(): boolean {
626 return this._attachedEditorCount > 0;
627 }
628 > textModel.ts
629 > public getAttachedEditorCount(): number {
630 return this._attachedEditorCount;
631 }
632 > textModel.ts
633 > public isTooLargeForSyncing(): boolean {
634 return this._isTooLargeForSyncing;
635 }
636 > textModel.ts
637 > public isTooLargeForTokenization(): boolean {
638 return this._isTooLargeForTokenization;
639 }
640 > textModel.ts
641 > public isTooLargeForHeapOperation(): boolean {
642 return this._isTooLargeForHeapOperation;
643 }
644 > textModel.ts
645 > public isDisposed(): boolean {
646 return this._isDisposed;
647 }
648 > textModel.ts
649 > public isDominatedByLongLines(): boolean {
650 this._assertNotDisposed();
651 if (this.isTooLargeForTokenization()) {
668 return (longLineCharCount > smallLineCharCount);
669 }
670 > textModel.ts
671 > public get uri(): URI {
672 return this._associatedResource;
673 }
674 > textModel.ts
675 > //#region Options
676 >
677 > public getOptions(): model.TextModelResolvedOptions {
678 this._assertNotDisposed();
679 return this._options;
680 }
681 > textModel.ts
682 > public getFormattingOptions(): FormattingOptions {
683 return {
684 tabSize: this._options.indentSize,
686 };
687 }
688 > textModel.ts
689 > public updateOptions(_newOpts: model.ITextModelUpdateOptions): void {
690 this._assertNotDisposed();
691 const tabSize = (typeof _newOpts.tabSize !== 'undefined') ? _newOpts.tabSize : this._options.tabSize;
715 this._onDidChangeOptions.fire(e);
716 }
717 > textModel.ts
718 > public detectIndentation(defaultInsertSpaces: boolean, defaultTabSize: number): void {
719 this._assertNotDisposed();
720 const guessedIndentation = guessIndentation(this._buffer, defaultTabSize, defaultInsertSpaces);
725 });
726 }
727 > textModel.ts
728 > public normalizeIndentation(str: string): string {
729 this._assertNotDisposed();
730 return normalizeIndentation(str, this._options.indentSize, this._options.insertSpaces);
731 }
732 > textModel.ts
733 > //#endregion
734 >
735 > //#region Reading
736 >
737 > public getVersionId(): number {
738 this._assertNotDisposed();
739 return this._versionId;
740 }
741 > textModel.ts
742 > public mightContainRTL(): boolean {
743 return this._buffer.mightContainRTL();
744 }
745 > textModel.ts
746 > public mightContainUnusualLineTerminators(): boolean {
747 return this._buffer.mightContainUnusualLineTerminators();
748 }
749 > textModel.ts
750 > public removeUnusualLineTerminators(selections: Selection[] | null = null): void {
751 const matches = this.findMatches(strings.UNUSUAL_LINE_TERMINATORS.source, false, true, false, null, false, Constants.MAX_SAFE_SMALL_INTEGER);
752 this._buffer.resetMightContainUnusualLineTerminators();
753 this.pushEditOperations(selections, matches.map(m => ({ range: m.range, text: null })), () => null);
754 }
755 > textModel.ts
756 > public mightContainNonBasicASCII(): boolean {
757 return this._buffer.mightContainNonBasicASCII();
758 }
759 > textModel.ts
760 > public getAlternativeVersionId(): number {
761 this._assertNotDisposed();
762 return this._alternativeVersionId;
763 }
764 > textModel.ts
765 > public getInitialUndoRedoSnapshot(): ResourceEditStackSnapshot | null {
766 this._assertNotDisposed();
767 return this._initialUndoRedoSnapshot;
768 }
769 > textModel.ts
770 > public getOffsetAt(rawPosition: IPosition): number {
771 this._assertNotDisposed();
772 const position = this._validatePosition(rawPosition.lineNumber, rawPosition.column, StringOffsetValidationType.Relaxed);
773 return this._buffer.getOffsetAt(position.lineNumber, position.column);
774 }
775 > textModel.ts
776 > public getPositionAt(rawOffset: number): Position {
777 this._assertNotDisposed();
778 const offset = (Math.min(this._buffer.getLength(), Math.max(0, rawOffset)));
779 return this._buffer.getPositionAt(offset);
780 }
781 > textModel.ts
782 > private _increaseVersionId(): void {
783 this._versionId = this._versionId + 1;
784 this._alternativeVersionId = this._versionId;
785 }
786 > textModel.ts
787 > public _overwriteVersionId(versionId: number): void {
788 this._versionId = versionId;
789 }
790 > textModel.ts
791 > public _overwriteAlternativeVersionId(newAlternativeVersionId: number): void {
792 this._alternativeVersionId = newAlternativeVersionId;
793 }
794 > textModel.ts
795 > public _overwriteInitialUndoRedoSnapshot(newInitialUndoRedoSnapshot: ResourceEditStackSnapshot | null): void {
796 this._initialUndoRedoSnapshot = newInitialUndoRedoSnapshot;
797 }
798 > textModel.ts
799 > public getValue(eol?: model.EndOfLinePreference, preserveBOM: boolean = false): string {
800 this._assertNotDisposed();
801 if (this.isTooLargeForHeapOperation()) {
812 return fullModelValue;
813 }
814 > textModel.ts
815 > public createSnapshot(preserveBOM: boolean = false): model.ITextSnapshot {
816 return new TextModelSnapshot(this._buffer.createSnapshot(preserveBOM));
817 }
818 > textModel.ts
819 > public getValueLength(eol?: model.EndOfLinePreference, preserveBOM: boolean = false): number {
820 this._assertNotDisposed();
821 const fullModelRange = this.getFullModelRange();
828 return fullModelValue;
829 }
830 > textModel.ts
831 > public getValueInRange(rawRange: IRange, eol: model.EndOfLinePreference = model.EndOfLinePreference.TextDefined): string {
832 this._assertNotDisposed();
833 return this._buffer.getValueInRange(this.validateRange(rawRange), eol);
834 }
835 > textModel.ts
836 > public getValueLengthInRange(rawRange: IRange, eol: model.EndOfLinePreference = model.EndOfLinePreference.TextDefined): number {
837 this._assertNotDisposed();
838 return this._buffer.getValueLengthInRange(this.validateRange(rawRange), eol);
839 }
840 > textModel.ts
841 > public getCharacterCountInRange(rawRange: IRange, eol: model.EndOfLinePreference = model.EndOfLinePreference.TextDefined): number {
842 this._assertNotDisposed();
843 return this._buffer.getCharacterCountInRange(this.validateRange(rawRange), eol);
844 }
845 > textModel.ts
846 > public getLineCount(): number {
847 this._assertNotDisposed();
848 return this._buffer.getLineCount();
849 }
850 > textModel.ts
851 > public getLineContent(lineNumber: number): string {
852 this._assertNotDisposed();
853 if (lineNumber < 1 || lineNumber > this.getLineCount()) {
857 return this._buffer.getLineContent(lineNumber);
858 }
859 > textModel.ts
860 > public getLineLength(lineNumber: number): number {
861 this._assertNotDisposed();
862 if (lineNumber < 1 || lineNumber > this.getLineCount()) {
866 return this._buffer.getLineLength(lineNumber);
867 }
868 > textModel.ts
869 > public getLinesContent(): string[] {
870 this._assertNotDisposed();
871 if (this.isTooLargeForHeapOperation()) {
875 return this._buffer.getLinesContent();
876 }
877 > textModel.ts
878 > public getEOL(): string {
879 this._assertNotDisposed();
880 return this._buffer.getEOL();
881 }
882 > textModel.ts
883 > public getEndOfLineSequence(): model.EndOfLineSequence {
884 this._assertNotDisposed();
885 return (
889 );
890 }
891 > textModel.ts
892 > public getLineMinColumn(lineNumber: number): number {
893 this._assertNotDisposed();
894 return 1;
895 }
896 > textModel.ts
897 > public getLineMaxColumn(lineNumber: number): number {
898 this._assertNotDisposed();
899 if (lineNumber < 1 || lineNumber > this.getLineCount()) {
902 return this._buffer.getLineLength(lineNumber) + 1;
903 }
904 > textModel.ts
905 > public getLineFirstNonWhitespaceColumn(lineNumber: number): number {
906 this._assertNotDisposed();
907 if (lineNumber < 1 || lineNumber > this.getLineCount()) {
910 return this._buffer.getLineFirstNonWhitespaceColumn(lineNumber);
911 }
912 > textModel.ts
913 > public getLineLastNonWhitespaceColumn(lineNumber: number): number {
914 this._assertNotDisposed();
915 if (lineNumber < 1 || lineNumber > this.getLineCount()) {
918 return this._buffer.getLineLastNonWhitespaceColumn(lineNumber);
919 }
920 > textModel.ts
921 > /**
922 > * Validates `range` is within buffer bounds, but allows it to sit in between surrogate pairs, etc.
923 > * Will try to not allocate if possible.
924 > */
925 > public _validateRangeRelaxedNoAllocations(range: IRange): Range {
926 const linesCount = this._buffer.getLineCount();
927
983 return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
984 }
985 > textModel.ts
986 > private _isValidPosition(lineNumber: number, column: number, validationType: StringOffsetValidationType): boolean {
987 if (typeof lineNumber !== 'number' || typeof column !== 'number') {
988 return false;
1025 return true;
1026 }
1027 > textModel.ts
1028 > private _validatePosition(_lineNumber: number, _column: number, validationType: StringOffsetValidationType): Position {
1029 const lineNumber = Math.floor((typeof _lineNumber === 'number' && !isNaN(_lineNumber)) ? _lineNumber : 1);
1030 const column = Math.floor((typeof _column === 'number' && !isNaN(_column)) ? _column : 1);
1060 return new Position(lineNumber, column);
1061 }
1062 > textModel.ts
1063 > public validatePosition(position: IPosition): Position {
1064 const validationType = StringOffsetValidationType.SurrogatePairs;
1065 this._assertNotDisposed();
1074 return this._validatePosition(position.lineNumber, position.column, validationType);
1075 }
1076 > textModel.ts
1077 > public isValidRange(range: Range): boolean {
1078 return this._isValidRange(range, StringOffsetValidationType.SurrogatePairs);
1079 }
1080 > textModel.ts
1081 > private _isValidRange(range: Range, validationType: StringOffsetValidationType): boolean {
1082 const startLineNumber = range.startLineNumber;
1083 const startColumn = range.startColumn;
1107 return true;
1108 }
1109 > textModel.ts
1110 > public validateRange(_range: IRange): Range {
1111 const validationType = StringOffsetValidationType.SurrogatePairs;
1112 this._assertNotDisposed();
1159 return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
1160 }
1161 > textModel.ts
1162 > public modifyPosition(rawPosition: IPosition, offset: number): Position {
1163 this._assertNotDisposed();
1164 const candidate = this.getOffsetAt(rawPosition) + offset;
1165 return this.getPositionAt(Math.min(this._buffer.getLength(), Math.max(0, candidate)));
1166 }
1167 > textModel.ts
1168 > public getFullModelRange(): Range {
1169 this._assertNotDisposed();
1170 const lineCount = this.getLineCount();
1171 return new Range(1, 1, lineCount, this.getLineMaxColumn(lineCount));
1172 }
1173 > textModel.ts
1174 > private findMatchesLineByLine(searchRange: Range, searchData: model.SearchData, captureMatches: boolean, limitResultCount: number): model.FindMatch[] {
1175 return this._buffer.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
1176 }
1177 > textModel.ts
1178 > public findMatches(searchString: string, rawSearchScope: boolean | IRange | IRange[] | null, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean, limitResultCount: number = LIMIT_FIND_COUNT): model.FindMatch[] {
1179 this._assertNotDisposed();
1180
1224 return uniqueSearchRanges.map(matchMapper).reduce((arr, matches: model.FindMatch[]) => arr.concat(matches), []);
1225 }
1226 > textModel.ts
1227 > public findNextMatch(searchString: string, rawSearchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string, captureMatches: boolean): model.FindMatch | null {
1228 this._assertNotDisposed();
1229 const searchStart = this.validatePosition(rawSearchStart);
1256 return TextModelSearch.findNextMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
1257 }
1258 > textModel.ts
1259 > public findPreviousMatch(searchString: string, rawSearchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string, captureMatches: boolean): model.FindMatch | null {
1260 this._assertNotDisposed();
1261 const searchStart = this.validatePosition(rawSearchStart);
1262 return TextModelSearch.findPreviousMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
1263 }
1264 > textModel.ts
1265 > //#endregion
1266 >
1267 > //#region Editing
1268 >
1269 > public pushStackElement(): void {
1270 this._commandManager.pushStackElement();
1271 }
1272 > textModel.ts
1273 > public popStackElement(): void {
1274 this._commandManager.popStackElement();
1275 }
1276 > textModel.ts
1277 > public pushEOL(eol: model.EndOfLineSequence): void {
1278 const currentEOL = (this.getEOL() === '\n' ? model.EndOfLineSequence.LF : model.EndOfLineSequence.CRLF);
1279 if (currentEOL === eol) {
1292 }
1293 }
1294 > textModel.ts
1295 > private _validateEditOperation(rawOperation: model.IIdentifiedSingleEditOperation): model.ValidAnnotatedEditOperation {
1296 if (rawOperation instanceof model.ValidAnnotatedEditOperation) {
1297 return rawOperation;
1325 );
1326 }
1327 > textModel.ts
1328 > private _validateEditOperations(rawOperations: readonly model.IIdentifiedSingleEditOperation[]): model.ValidAnnotatedEditOperation[] {
1329 const result: model.ValidAnnotatedEditOperation[] = [];
1330 for (let i = 0, len = rawOperations.length; i < len; i++) {
1333 return result;
1334 }
1335 > textModel.ts
1336 > public edit(edit: TextEdit, options?: { reason?: TextModelEditSource }): void {
1337 this.pushEditOperations(null, edit.replacements.map(r => ({ range: r.range, text: r.text })), null);
1338 }
1339 > textModel.ts
1340 > public pushEditOperations(beforeCursorState: Selection[] | null, editOperations: model.IIdentifiedSingleEditOperation[], cursorStateComputer: model.ICursorStateComputer | null, group?: UndoRedoGroup, reason?: TextModelEditSource): Selection[] | null {
1341 try {
1342 this._onDidChangeDecorations.beginDeferredEmit();
1348 }
1349 }
1350 > textModel.ts
1351 > private _pushEditOperations(beforeCursorState: Selection[] | null, editOperations: model.ValidAnnotatedEditOperation[], cursorStateComputer: model.ICursorStateComputer | null, group?: UndoRedoGroup, reason?: TextModelEditSource): Selection[] | null {
1352 if (this._options.trimAutoWhitespace && this._trimAutoWhitespaceLines) {
1353 // Go through each saved line number and insert a trim whitespace edit
1438 return this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer, group, reason);
1439 }
1440 > textModel.ts
1441 > _applyUndo(changes: TextChange[], eol: model.EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void {
1442 const edits = changes.map<ISingleEditOperation>((change) => {
1443 const rangeStart = this.getPositionAt(change.newPosition);
1450 this._applyUndoRedoEdits(edits, eol, true, false, resultingAlternativeVersionId, resultingSelection);
1451 }
1452 > textModel.ts
1453 > _applyRedo(changes: TextChange[], eol: model.EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void {
1454 const edits = changes.map<ISingleEditOperation>((change) => {
1455 const rangeStart = this.getPositionAt(change.oldPosition);
1462 this._applyUndoRedoEdits(edits, eol, false, true, resultingAlternativeVersionId, resultingSelection);
1463 }
1464 > textModel.ts
1465 > private _applyUndoRedoEdits(edits: ISingleEditOperation[], eol: model.EndOfLineSequence, isUndoing: boolean, isRedoing: boolean, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void {
1466 try {
1467 this._onDidChangeDecorations.beginDeferredEmit();
1480 }
1481 }
1482 > textModel.ts
1483 > public applyEdits(operations: readonly model.IIdentifiedSingleEditOperation[]): void;
1484 > public applyEdits(operations: readonly model.IIdentifiedSingleEditOperation[], computeUndoEdits: false): void;
1485 > public applyEdits(operations: readonly model.IIdentifiedSingleEditOperation[], computeUndoEdits: true): model.IValidEditOperation[];
1486 > /** @internal */
1487 > public applyEdits(operations: readonly model.IIdentifiedSingleEditOperation[], computeUndoEdits: false, reason: TextModelEditSource): void;
1488 > /** @internal */
1489 > public applyEdits(operations: readonly model.IIdentifiedSingleEditOperation[], computeUndoEdits: true, reason: TextModelEditSource): model.IValidEditOperation[];
1490 > public applyEdits(rawOperations: readonly model.IIdentifiedSingleEditOperation[], computeUndoEdits?: boolean, reason?: TextModelEditSource): void | model.IValidEditOperation[] {
1491 try {
1492 this._onDidChangeDecorations.beginDeferredEmit();
1500 }
1501 }
1502 > textModel.ts
1503 > private _doApplyEdits(rawOperations: model.ValidAnnotatedEditOperation[], computeUndoEdits: boolean, reason: TextModelEditSource, resultingSelection: Selection[] | null = null): void | model.IValidEditOperation[] {
1504
1505 const oldLineCount = this._buffer.getLineCount();
1601 return (result.reverseEdits === null ? undefined : result.reverseEdits);
1602 }
1603 > textModel.ts
1604 > public undo(): void | Promise<void> {
1605 return this._undoRedoService.undo(this.uri);
1606 }
1607 > textModel.ts
1608 > public canUndo(): boolean {
1609 return this._undoRedoService.canUndo(this.uri);
1610 }
1611 > textModel.ts
1612 > public redo(): void | Promise<void> {
1613 return this._undoRedoService.redo(this.uri);
1614 }
1615 > textModel.ts
1616 > public canRedo(): boolean {
1617 return this._undoRedoService.canRedo(this.uri);
1618 }
1619 > textModel.ts
1620 > //#endregion
1621 >
1622 > //#region Decorations
1623 >
1624 > private handleBeforeFireDecorationsChangedEvent(affectedInjectedTextLines: Set<number> | null, affectedLineHeights: Set<LineHeightChangingDecoration> | null, affectedFontLines: Set<LineFontChangingDecoration> | null): void {
1625 // This is called before the decoration changed event is fired.
1626
1633 this._fireOnDidChangeFont(affectedFontLines);
1634 }
1635 > textModel.ts
1636 > private _fireOnDidChangeLineHeight(affectedLineHeights: Set<LineHeightChangingDecoration> | null): void {
1637 if (affectedLineHeights && affectedLineHeights.size > 0) {
1638 const affectedLines = Array.from(affectedLineHeights);
1641 }
1642 }
1643 > textModel.ts
1644 > private _fireOnDidChangeFont(affectedFontLines: Set<LineFontChangingDecoration> | null): void {
1645 if (affectedFontLines && affectedFontLines.size > 0) {
1646 const affectedLines = Array.from(affectedFontLines);
1649 }
1650 }
1651 > textModel.ts
1652 > private _onDidChangeContentOrInjectedText(e: InternalModelContentChangeEvent | ModelInjectedTextChangedEvent): void {
1653 for (const viewModel of this._viewModels) {
1654 try {
1666 }
1667 }
1668 > textModel.ts
1669 > public changeDecorations<T>(callback: (changeAccessor: model.IModelDecorationsChangeAccessor) => T, ownerId: number = 0): T | null {
1670 this._assertNotDisposed();
1671
1677 }
1678 }
1679 > textModel.ts
1680 > private _changeDecorations<T>(ownerId: number, callback: (changeAccessor: model.IModelDecorationsChangeAccessor) => T): T | null {
1681 const changeAccessor: model.IModelDecorationsChangeAccessor = {
1682 addDecoration: (range: IRange, options: model.IModelDecorationOptions): string => {
1714 return result;
1715 }
1716 > textModel.ts
1717 > public deltaDecorations(oldDecorations: string[], newDecorations: model.IModelDeltaDecoration[], ownerId: number = 0): string[] {
1718 this._assertNotDisposed();
1719 if (!oldDecorations) {
1738 }
1739 }
1740 > textModel.ts
1741 > _getTrackedRange(id: string): Range | null {
1742 return this.getDecorationRange(id);
1743 }
1744 > textModel.ts
1745 > _setTrackedRange(id: string | null, newRange: null, newStickiness: model.TrackedRangeStickiness): null;
1746 > _setTrackedRange(id: string | null, newRange: Range, newStickiness: model.TrackedRangeStickiness): string;
1747 > _setTrackedRange(id: string | null, newRange: Range | null, newStickiness: model.TrackedRangeStickiness): string | null {
1748 const node = (id ? this._decorations[id] : null);
1749
1774 return node.id;
1775 }
1776 > textModel.ts
1777 > public removeAllDecorationsWithOwnerId(ownerId: number): void {
1778 if (this._isDisposed) {
1779 return;
1787 }
1788 }
1789 > textModel.ts
1790 > public getDecorationOptions(decorationId: string): model.IModelDecorationOptions | null {
1791 const node = this._decorations[decorationId];
1792 if (!node) {
1795 return node.options;
1796 }
1797 > textModel.ts
1798 > public getDecorationRange(decorationId: string): Range | null {
1799 const node = this._decorations[decorationId];
1800 if (!node) {
1803 return this._decorationsTree.getNodeRange(this, node);
1804 }
1805 > textModel.ts
1806 > public getLineDecorations(lineNumber: number, ownerId: number = 0, filterOutValidation: boolean = false, filterFontDecorations: boolean = false): model.IModelDecoration[] {
1807 if (lineNumber < 1 || lineNumber > this.getLineCount()) {
1808 return [];
1810 return this.getLinesDecorations(lineNumber, lineNumber, ownerId, filterOutValidation, filterFontDecorations);
1811 }
1812 > textModel.ts
1813 > public getLinesDecorations(_startLineNumber: number, _endLineNumber: number, ownerId: number = 0, filterOutValidation: boolean = false, filterFontDecorations: boolean = false, onlyMarginDecorations: boolean = false): model.IModelDecoration[] {
1814 const lineCount = this.getLineCount();
1815 const startLineNumber = Math.min(lineCount, Math.max(1, _startLineNumber));
1823 return decorations;
1824 }
1825 > textModel.ts
1826 > public getDecorationsInRange(range: IRange, ownerId: number = 0, filterOutValidation: boolean = false, filterFontDecorations: boolean = false, onlyMinimapDecorations: boolean = false, onlyMarginDecorations: boolean = false): model.IModelDecoration[] {
1827 const validatedRange = this.validateRange(range);
1828
1832 return decorations;
1833 }
1834 > textModel.ts
1835 > public getOverviewRulerDecorations(ownerId: number = 0, filterOutValidation: boolean = false, filterFontDecorations: boolean = false): model.IModelDecoration[] {
1836 return this._decorationsTree.getAll(this, ownerId, filterOutValidation, filterFontDecorations, true, false);
1837 }
1838 > textModel.ts
1839 > public getInjectedTextDecorations(ownerId: number = 0): model.IModelDecoration[] {
1840 return this._decorationsTree.getAllInjectedText(this, ownerId);
1841 }
1842 > textModel.ts
1843 > public getCustomLineHeightsDecorations(ownerId: number = 0): model.IModelDecoration[] {
1844 const decs = this._decorationsTree.getAllCustomLineHeights(this, ownerId);
1845 pushMany(decs, this._fontTokenDecorationsProvider.getAllDecorations(ownerId));
1846 return decs;
1847 }
1848 > textModel.ts
1849 > public getCustomLineHeightsDecorationsInRange(range: Range, ownerId: number = 0): model.IModelDecoration[] {
1850 const decs = this._decorationsTree.getCustomLineHeightsInInterval(this, this.getOffsetAt(range.getStartPosition()), this.getOffsetAt(range.getEndPosition()), ownerId);
1851 pushMany(decs, this._fontTokenDecorationsProvider.getDecorationsInRange(range, ownerId));
1852 return decs;
1853 }
1854 > textModel.ts
1855 > public getLineInjectedText(lineNumber: number, ownerId: number = 0): LineInjectedText[] {
1856 const startOffset = this._buffer.getOffsetAt(lineNumber, 1);
1857 const endOffset = startOffset + this._buffer.getLineLength(lineNumber);
1860 return LineInjectedText.fromDecorations(result).filter(t => t.lineNumber === lineNumber);
1861 }
1862 > textModel.ts
1863 > public getFontDecorationsInRange(range: IRange, ownerId: number = 0): model.IModelDecoration[] {
1864 const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
1865 const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
1866 return this._decorationsTree.getFontDecorationsInInterval(this, startOffset, endOffset, ownerId);
1867 }
1868 > textModel.ts
1869 > public getAllDecorations(ownerId: number = 0, filterOutValidation: boolean = false, filterFontDecorations: boolean = false): model.IModelDecoration[] {
1870 let result = this._decorationsTree.getAll(this, ownerId, filterOutValidation, filterFontDecorations, false, false);
1871 result = result.concat(this._decorationProvider.getAllDecorations(ownerId, filterOutValidation));
1873 return result;
1874 }
1875 > textModel.ts
1876 > public getAllMarginDecorations(ownerId: number = 0): model.IModelDecoration[] {
1877 return this._decorationsTree.getAll(this, ownerId, false, false, false, true);
1878 }
1879 > textModel.ts
1880 > private _getDecorationsInRange(filterRange: Range, filterOwnerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, onlyMarginDecorations: boolean): model.IModelDecoration[] {
1881 const startOffset = this._buffer.getOffsetAt(filterRange.startLineNumber, filterRange.startColumn);
1882 const endOffset = this._buffer.getOffsetAt(filterRange.endLineNumber, filterRange.endColumn);
1883 return this._decorationsTree.getAllInInterval(this, startOffset, endOffset, filterOwnerId, filterOutValidation, filterFontDecorations, onlyMarginDecorations);
1884 }
1885 > textModel.ts
1886 > public getRangeAt(start: number, end: number): Range {
1887 return this._buffer.getRangeAt(start, end - start);
1888 }
1889 > textModel.ts
1890 > private _changeDecorationImpl(ownerId: number, decorationId: string, _range: IRange): void {
1891 const node = this._decorations[decorationId];
1892 if (!node) {
1933 }
1934 }
1935 > textModel.ts
1936 > private _changeDecorationOptionsImpl(ownerId: number, decorationId: string, options: ModelDecorationOptions): void {
1937 const node = this._decorations[decorationId];
1938 if (!node) {
1973 }
1974 }
1975 > textModel.ts
1976 > private _deltaDecorationsImpl(ownerId: number, oldDecorationsIds: string[], newDecorations: model.IModelDeltaDecoration[], suppressEvents: boolean = false): string[] {
1977 const versionId = this.getVersionId();
1978
2077 }
2078 }
2079 > textModel.ts
2080 > //#endregion
2081 >
2082 > //#region Tokenization
2083 >
2084 > // TODO move them to the tokenization part.
2085 > public getLanguageId(): string {
2086 return this.tokenization.getLanguageId();
2087 }
2088 > textModel.ts
2089 > public setLanguage(languageIdOrSelection: string | ILanguageSelection, source?: string): void {
2090 if (typeof languageIdOrSelection === 'string') {
2091 this._languageSelectionListener.clear();
2096 }
2097 }
2098 > textModel.ts
2099 > private _setLanguage(languageId: string, source?: string): void {
2100 this.tokenization.setLanguageId(languageId, source);
2101 this._languageService.requestRichLanguageFeatures(languageId);
2102 }
2103 > textModel.ts
2104 > public getLanguageIdAtPosition(lineNumber: number, column: number): string {
2105 return this.tokenization.getLanguageIdAtPosition(lineNumber, column);
2106 }
2107 > textModel.ts
2108 > public getWordAtPosition(position: IPosition): IWordAtPosition | null {
2109 return this._tokenizationTextModelPart.getWordAtPosition(position);
2110 }
2111 > textModel.ts
2112 > public getWordUntilPosition(position: IPosition): IWordAtPosition {
2113 return this._tokenizationTextModelPart.getWordUntilPosition(position);
2114 }
2115 > textModel.ts
2116 > //#endregion
2117 > normalizePosition(position: Position, affinity: model.PositionAffinity): Position {
2118 return position;
2119 }
2120 > textModel.ts
2121 > /**
2122 > * Gets the column at which indentation stops at a given line.
2123 > * @internal
2124 > */
2125 > public getLineIndentColumn(lineNumber: number): number {
2126 // Columns start with 1.
2127 return indentOfLine(this.getLineContent(lineNumber)) + 1;
2128 }
2129 > textModel.ts
2130 > public override toString(): string {
2131 return `TextModel(${this.uri.toString()})`;
2132 }
2133 > } textModel.ts
2134 >
2135 > export function getLineTokensWithInjections(tokens: LineTokens, injectionOptions: model.InjectedTextOptions[] | null, injectionOffsets: number[] | null): LineTokens {
2136 let lineTokens: LineTokens;
2137 if (injectionOffsets) {
2163 return lineTokens;
2164 }
2165 > textModel.ts
2166 > export function indentOfLine(line: string): number {
2167 let indent = 0;
2168 for (const c of line) {
2175 return indent;
2176 }
2177 > textModel.ts
2178 > //#region Decorations
2179 >
2180 function isNodeInOverviewRuler(node: IntervalNode): boolean {
2181 return (node.options.overviewRuler && node.options.overviewRuler.color ? true : false);
2182 }
2183 > textModel.ts
2184 function isOptionsInjectedText(options: ModelDecorationOptions): boolean {
2185 return !!options.after || !!options.before;
2186 }
2187 > textModel.ts
2188 function isNodeInjectedText(node: IntervalNode): boolean {
2189 return !!node.options.after || !!node.options.before;
2190 }
2191 > textModel.ts
2192 > export interface IDecorationsTreesHost {
2193 > getVersionId(): number;
2194 > getRangeAt(start: number, end: number): Range;
2195 > }
2196 >
2197 > class DecorationsTrees {
2198 >
2199 > /**
2200 > * This tree holds decorations that do not show up in the overview ruler.
2201 > */
2202 > private readonly _decorationsTree0: IntervalTree;
2203 >
2204 > /**
2205 > * This tree holds decorations that show up in the overview ruler.
2206 > */
2207 > private readonly _decorationsTree1: IntervalTree;
2208 >
2209 > /**
2210 > * This tree holds decorations that contain injected text.
2211 > */
2212 > private readonly _injectedTextDecorationsTree: IntervalTree;
2213 >
2214 > constructor() {
2215 this._decorationsTree0 = new IntervalTree();
2216 this._decorationsTree1 = new IntervalTree();
2217 this._injectedTextDecorationsTree = new IntervalTree();
2218 }
2219 > textModel.ts
2220 > public ensureAllNodesHaveRanges(host: IDecorationsTreesHost): void {
2221 this.getAll(host, 0, false, false, false, false);
2222 }
2223 > textModel.ts
2224 > private _ensureNodesHaveRanges(host: IDecorationsTreesHost, nodes: IntervalNode[]): model.IModelDecoration[] {
2225 for (const node of nodes) {
2226 if (node.range === null) {
2230 return <model.IModelDecoration[]>nodes;
2231 }
2232 > textModel.ts
2233 > public getAllInInterval(host: IDecorationsTreesHost, start: number, end: number, filterOwnerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, onlyMarginDecorations: boolean): model.IModelDecoration[] {
2234 const versionId = host.getVersionId();
2235 const result = this._intervalSearch(start, end, filterOwnerId, filterOutValidation, filterFontDecorations, versionId, onlyMarginDecorations);
2236 return this._ensureNodesHaveRanges(host, result);
2237 }
2238 > textModel.ts
2239 > private _intervalSearch(start: number, end: number, filterOwnerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {
2240 const r0 = this._decorationsTree0.intervalSearch(start, end, filterOwnerId, filterOutValidation, filterFontDecorations, cachedVersionId, onlyMarginDecorations);
2241 const r1 = this._decorationsTree1.intervalSearch(start, end, filterOwnerId, filterOutValidation, filterFontDecorations, cachedVersionId, onlyMarginDecorations);
2243 return r0.concat(r1).concat(r2);
2244 }
2245 > textModel.ts
2246 > public getInjectedTextInInterval(host: IDecorationsTreesHost, start: number, end: number, filterOwnerId: number): model.IModelDecoration[] {
2247 const versionId = host.getVersionId();
2248 const result = this._injectedTextDecorationsTree.intervalSearch(start, end, filterOwnerId, false, false, versionId, false);
2249 return this._ensureNodesHaveRanges(host, result).filter((i) => i.options.showIfCollapsed || !i.range.isEmpty());
2250 }
2251 > textModel.ts
2252 > public getFontDecorationsInInterval(host: IDecorationsTreesHost, start: number, end: number, filterOwnerId: number): model.IModelDecoration[] {
2253 const versionId = host.getVersionId();
2254 const decorations = this._decorationsTree0.intervalSearch(start, end, filterOwnerId, false, false, versionId, false);
2255 return this._ensureNodesHaveRanges(host, decorations).filter((i) => i.options.affectsFont);
2256 }
2257 > textModel.ts
2258 > public getAllInjectedText(host: IDecorationsTreesHost, filterOwnerId: number): model.IModelDecoration[] {
2259 const versionId = host.getVersionId();
2260 const result = this._injectedTextDecorationsTree.search(filterOwnerId, false, false, versionId, false);
2261 return this._ensureNodesHaveRanges(host, result).filter((i) => i.options.showIfCollapsed || !i.range.isEmpty());
2262 }
2263 > textModel.ts
2264 > public getAllCustomLineHeights(host: IDecorationsTreesHost, filterOwnerId: number): model.IModelDecoration[] {
2265 const versionId = host.getVersionId();
2266 const result = this._search(filterOwnerId, false, false, false, versionId, false);
2267 return this._ensureNodesHaveRanges(host, result).filter((i) => typeof i.options.lineHeight === 'number');
2268 }
2269 > textModel.ts
2270 > public getCustomLineHeightsInInterval(host: IDecorationsTreesHost, start: number, end: number, filterOwnerId: number): model.IModelDecoration[] {
2271 const versionId = host.getVersionId();
2272 const result = this._intervalSearch(start, end, filterOwnerId, false, false, versionId, false);
2273 return this._ensureNodesHaveRanges(host, result).filter((i) => typeof i.options.lineHeight === 'number');
2274 }
2275 > textModel.ts
2276 > public getAll(host: IDecorationsTreesHost, filterOwnerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, overviewRulerOnly: boolean, onlyMarginDecorations: boolean): model.IModelDecoration[] {
2277 const versionId = host.getVersionId();
2278 const result = this._search(filterOwnerId, filterOutValidation, filterFontDecorations, overviewRulerOnly, versionId, onlyMarginDecorations);
2279 return this._ensureNodesHaveRanges(host, result);
2280 }
2281 > textModel.ts
2282 > private _search(filterOwnerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, overviewRulerOnly: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {
2283 if (overviewRulerOnly) {
2284 return this._decorationsTree1.search(filterOwnerId, filterOutValidation, filterFontDecorations, cachedVersionId, onlyMarginDecorations);
2290 }
2291 }
2292 > textModel.ts
2293 > public collectNodesFromOwner(ownerId: number): IntervalNode[] {
2294 const r0 = this._decorationsTree0.collectNodesFromOwner(ownerId);
2295 const r1 = this._decorationsTree1.collectNodesFromOwner(ownerId);
2297 return r0.concat(r1).concat(r2);
2298 }
2299 > textModel.ts
2300 > public collectNodesPostOrder(): IntervalNode[] {
2301 const r0 = this._decorationsTree0.collectNodesPostOrder();
2302 const r1 = this._decorationsTree1.collectNodesPostOrder();
2304 return r0.concat(r1).concat(r2);
2305 }
2306 > textModel.ts
2307 > public insert(node: IntervalNode): void {
2308 if (isNodeInjectedText(node)) {
2309 this._injectedTextDecorationsTree.insert(node);
2314 }
2315 }
2316 > textModel.ts
2317 > public delete(node: IntervalNode): void {
2318 if (isNodeInjectedText(node)) {
2319 this._injectedTextDecorationsTree.delete(node);
2324 }
2325 }
2326 > textModel.ts
2327 > public getNodeRange(host: IDecorationsTreesHost, node: IntervalNode): Range {
2328 const versionId = host.getVersionId();
2329 if (node.cachedVersionId !== versionId) {
2335 return node.range;
2336 }
2337 > textModel.ts
2338 > private _resolveNode(node: IntervalNode, cachedVersionId: number): void {
2339 if (isNodeInjectedText(node)) {
2340 this._injectedTextDecorationsTree.resolveNode(node, cachedVersionId);
2345 }
2346 }
2347 > textModel.ts
2348 > public acceptReplace(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void {
2349 this._decorationsTree0.acceptReplace(offset, length, textLength, forceMoveMarkers);
2350 this._decorationsTree1.acceptReplace(offset, length, textLength, forceMoveMarkers);
2351 this._injectedTextDecorationsTree.acceptReplace(offset, length, textLength, forceMoveMarkers);
2352 }
2353 > } textModel.ts
2354 >
2355 function cleanClassName(className: string): string {
2356 return className.replace(/[^a-z0-9\-_]/gi, ' ');
2357 }
2358 > textModel.ts
2359 > class DecorationOptions implements model.IDecorationOptions {
2360 > readonly color: string | ThemeColor;
2361 > readonly darkColor: string | ThemeColor;
2362 >
2363 > constructor(options: model.IDecorationOptions) {
2364 this.color = options.color || '';
2365 this.darkColor = options.darkColor || '';
2366
2367 }
2368 > } textModel.ts
2369 >
2370 > export class ModelDecorationOverviewRulerOptions extends DecorationOptions {
2371 > readonly position: model.OverviewRulerLane;
2372 > private _resolvedColor: string | null;
2373 >
2374 > constructor(options: model.IModelDecorationOverviewRulerOptions) {
2375 super(options);
2376 this._resolvedColor = null;
2377 this.position = (typeof options.position === 'number' ? options.position : model.OverviewRulerLane.Center);
2378 }
2379 > textModel.ts
2380 > public getColor(theme: IColorTheme): string {
2381 if (!this._resolvedColor) {
2382 if (isDark(theme.type) && this.darkColor) {
2388 return this._resolvedColor;
2389 }
2390 > textModel.ts
2391 > public invalidateCachedColor(): void {
2392 this._resolvedColor = null;
2393 }
2394 > textModel.ts
2395 > private _resolveColor(color: string | ThemeColor, theme: IColorTheme): string {
2396 if (typeof color === 'string') {
2397 return color;
2403 return c.toString();
2404 }
2405 > } textModel.ts
2406 >
2407 > export class ModelDecorationGlyphMarginOptions {
2408 > readonly position: model.GlyphMarginLane;
2409 > readonly persistLane: boolean | undefined;
2410 >
2411 > constructor(options: model.IModelDecorationGlyphMarginOptions | null | undefined) {
2412 this.position = options?.position ?? model.GlyphMarginLane.Center;
2413 this.persistLane = options?.persistLane;
2414 }
2415 > } textModel.ts
2416 >
2417 > export class ModelDecorationMinimapOptions extends DecorationOptions {
2418 > readonly position: model.MinimapPosition;
2419 > readonly sectionHeaderStyle: model.MinimapSectionHeaderStyle | null;
2420 > readonly sectionHeaderText: string | null;
2421 > private _resolvedColor: Color | undefined;
2422 >
2423 > constructor(options: model.IModelDecorationMinimapOptions) {
2424 super(options);
2425 this.position = options.position;
2427 this.sectionHeaderText = options.sectionHeaderText ?? null;
2428 }
2429 > textModel.ts
2430 > public getColor(theme: IColorTheme): Color | undefined {
2431 if (!this._resolvedColor) {
2432 if (isDark(theme.type) && this.darkColor) {
2439 return this._resolvedColor;
2440 }
2441 > textModel.ts
2442 > public invalidateCachedColor(): void {
2443 this._resolvedColor = undefined;
2444 }
2445 > textModel.ts
2446 > private _resolveColor(color: string | ThemeColor, theme: IColorTheme): Color | undefined {
2447 if (typeof color === 'string') {
2448 return Color.fromHex(color);
2450 return theme.getColor(color.id);
2451 }
2452 > } textModel.ts
2453 >
2454 > export class ModelDecorationInjectedTextOptions implements model.InjectedTextOptions {
2455 > public static from(options: model.InjectedTextOptions): ModelDecorationInjectedTextOptions {
2456 if (options instanceof ModelDecorationInjectedTextOptions) {
2457 return options;
2459 return new ModelDecorationInjectedTextOptions(options);
2460 }
2461 > textModel.ts
2462 > public readonly content: string;
2463 > public readonly tokens: TokenArray | null;
2464 > readonly inlineClassName: string | null;
2465 > readonly inlineClassNameAffectsLetterSpacing: boolean;
2466 > readonly attachedData: unknown | null;
2467 > readonly cursorStops: model.InjectedTextCursorStops | null;
2468 >
2469 > private constructor(options: model.InjectedTextOptions) {
2470 this.content = options.content || '';
2471 this.tokens = options.tokens ?? null;
2475 this.cursorStops = options.cursorStops || null;
2476 }
2477 > } textModel.ts
2478 >
2479 > export class ModelDecorationOptions implements model.IModelDecorationOptions {
2480 >
2481 > public static EMPTY: ModelDecorationOptions;
2482 >
2483 > public static register(options: model.IModelDecorationOptions): ModelDecorationOptions {
2484 > return new ModelDecorationOptions(options);
2485 > }
2486 >
2487 > public static createDynamic(options: model.IModelDecorationOptions): ModelDecorationOptions {
2488 return new ModelDecorationOptions(options);
2489 }
2490 > readonly description: string; textModel.ts
2491 > readonly blockClassName: string | null;
2492 > readonly blockIsAfterEnd: boolean | null;
2493 > readonly blockDoesNotCollapse?: boolean | null;
2494 > readonly blockPadding: [top: number, right: number, bottom: number, left: number] | null;
2495 > readonly stickiness: model.TrackedRangeStickiness;
2496 > readonly zIndex: number;
2497 > readonly className: string | null;
2498 > readonly shouldFillLineOnLineBreak: boolean | null;
2499 > readonly hoverMessage: IMarkdownString | IMarkdownString[] | null;
2500 > readonly glyphMarginHoverMessage: IMarkdownString | IMarkdownString[] | null;
2501 > readonly isWholeLine: boolean;
2502 > readonly lineHeight: number | null;
2503 > readonly fontSize: string | null;
2504 > readonly showIfCollapsed: boolean;
2505 > readonly collapseOnReplaceEdit: boolean;
2506 > readonly overviewRuler: ModelDecorationOverviewRulerOptions | null;
2507 > readonly minimap: ModelDecorationMinimapOptions | null;
2508 > readonly glyphMargin?: model.IModelDecorationGlyphMarginOptions | null | undefined;
2509 > readonly glyphMarginClassName: string | null;
2510 > readonly linesDecorationsClassName: string | null;
2511 > readonly lineNumberClassName: string | null;
2512 > readonly lineNumberHoverMessage: IMarkdownString | IMarkdownString[] | null;
2513 > readonly linesDecorationsTooltip: string | null;
2514 > readonly firstLineDecorationClassName: string | null;
2515 > readonly marginClassName: string | null;
2516 > readonly inlineClassName: string | null;
2517 > readonly inlineClassNameAffectsLetterSpacing: boolean;
2518 > readonly beforeContentClassName: string | null;
2519 > readonly afterContentClassName: string | null;
2520 > readonly after: ModelDecorationInjectedTextOptions | null;
2521 > readonly before: ModelDecorationInjectedTextOptions | null;
2522 > readonly hideInCommentTokens: boolean | null;
2523 > readonly hideInStringTokens: boolean | null;
2524 > readonly affectsFont: boolean | null;
2525 > readonly textDirection?: model.TextDirection | null | undefined;
2526 >
2527 > private constructor(options: model.IModelDecorationOptions) {
2528 > this.description = options.description;
2529 > this.blockClassName = options.blockClassName ? cleanClassName(options.blockClassName) : null;
2530 > this.blockDoesNotCollapse = options.blockDoesNotCollapse ?? null;
2531 > this.blockIsAfterEnd = options.blockIsAfterEnd ?? null;
2532 > this.blockPadding = options.blockPadding ?? null;
2533 > this.stickiness = options.stickiness || model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges;
2534 > this.zIndex = options.zIndex || 0;
2535 > this.className = options.className ? cleanClassName(options.className) : null;
2536 > this.shouldFillLineOnLineBreak = options.shouldFillLineOnLineBreak ?? null;
2537 > this.hoverMessage = options.hoverMessage || null;
2538 > this.glyphMarginHoverMessage = options.glyphMarginHoverMessage || null;
2539 > this.lineNumberHoverMessage = options.lineNumberHoverMessage || null;
2540 > this.isWholeLine = options.isWholeLine || false;
2541 > this.lineHeight = options.lineHeight ? Math.min(options.lineHeight, LINE_HEIGHT_CEILING) : null;
2542 > this.fontSize = options.fontSize || null;
2543 > this.affectsFont = !!options.fontSize || !!options.fontFamily || !!options.fontWeight || !!options.fontStyle;
2544 > this.showIfCollapsed = options.showIfCollapsed || false;
2545 > this.collapseOnReplaceEdit = options.collapseOnReplaceEdit || false;
2546 > this.overviewRuler = options.overviewRuler ? new ModelDecorationOverviewRulerOptions(options.overviewRuler) : null;
2547 > this.minimap = options.minimap ? new ModelDecorationMinimapOptions(options.minimap) : null;
2548 > this.glyphMargin = options.glyphMarginClassName ? new ModelDecorationGlyphMarginOptions(options.glyphMargin) : null;
2549 > this.glyphMarginClassName = options.glyphMarginClassName ? cleanClassName(options.glyphMarginClassName) : null;
2550 > this.linesDecorationsClassName = options.linesDecorationsClassName ? cleanClassName(options.linesDecorationsClassName) : null;
2551 > this.lineNumberClassName = options.lineNumberClassName ? cleanClassName(options.lineNumberClassName) : null;
2552 > this.linesDecorationsTooltip = options.linesDecorationsTooltip ? strings.htmlAttributeEncodeValue(options.linesDecorationsTooltip) : null;
2553 > this.firstLineDecorationClassName = options.firstLineDecorationClassName ? cleanClassName(options.firstLineDecorationClassName) : null;
2554 > this.marginClassName = options.marginClassName ? cleanClassName(options.marginClassName) : null;
2555 > this.inlineClassName = options.inlineClassName ? cleanClassName(options.inlineClassName) : null;
2556 > this.inlineClassNameAffectsLetterSpacing = options.inlineClassNameAffectsLetterSpacing || false;
2557 > this.beforeContentClassName = options.beforeContentClassName ? cleanClassName(options.beforeContentClassName) : null;
2558 > this.afterContentClassName = options.afterContentClassName ? cleanClassName(options.afterContentClassName) : null;
2559 > this.after = options.after ? ModelDecorationInjectedTextOptions.from(options.after) : null;
2560 > this.before = options.before ? ModelDecorationInjectedTextOptions.from(options.before) : null;
2561 > this.hideInCommentTokens = options.hideInCommentTokens ?? false;
2562 > this.hideInStringTokens = options.hideInStringTokens ?? false;
2563 > this.textDirection = options.textDirection ?? null;
2564 > }
2565 > }
2566 > ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({ description: 'empty' });
2567 >
2568 > /**
2569 > * The order carefully matches the values of the enum.
2570 > */
2571 > const TRACKED_RANGE_OPTIONS = [
2572 > ModelDecorationOptions.register({ description: 'tracked-range-always-grows-when-typing-at-edges', stickiness: model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges }),
2573 > ModelDecorationOptions.register({ description: 'tracked-range-never-grows-when-typing-at-edges', stickiness: model.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }),
2574 > ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-before', stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore }),
2575 > ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-after', stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter }),
2576 > ];
2577 >
2578 function _normalizeOptions(options: model.IModelDecorationOptions): ModelDecorationOptions {
2579 if (options instanceof ModelDecorationOptions) {
2582 return ModelDecorationOptions.createDynamic(options);
2583 }
2584 > textModel.ts
2585 >
2586 > class DidChangeDecorationsEmitter extends Disposable {
2587 >
2588 > private readonly _actual: Emitter<IModelDecorationsChangedEvent> = this._register(new Emitter<IModelDecorationsChangedEvent>());
2589 > public readonly event: Event<IModelDecorationsChangedEvent> = this._actual.event;
2590 >
2591 > private _deferredCnt: number;
2592 > private _shouldFireDeferred: boolean;
2593 > private _affectsMinimap: boolean;
2594 > private _affectsOverviewRuler: boolean;
2595 > private _affectedInjectedTextLines: Set<number> | null = null;
2596 > private _affectedLineHeights: SetWithKey<LineHeightChangingDecoration> | null = null;
2597 > private _affectedFontLines: SetWithKey<LineFontChangingDecoration> | null = null;
2598 > private _affectsGlyphMargin: boolean;
2599 > private _affectsLineNumber: boolean;
2600 >
2601 > constructor(private readonly handleBeforeFire: (affectedInjectedTextLines: Set<number> | null, affectedLineHeights: SetWithKey<LineHeightChangingDecoration> | null, affectedFontLines: SetWithKey<LineFontChangingDecoration> | null) => void) {
2602 super();
2603 this._deferredCnt = 0;
2608 this._affectsLineNumber = false;
2609 }
2610 > textModel.ts
2611 > hasListeners(): boolean {
2612 return this._actual.hasListeners();
2613 }
2614 > textModel.ts
2615 > public beginDeferredEmit(): void {
2616 this._deferredCnt++;
2617 }
2618 > textModel.ts
2619 > public endDeferredEmit(): void {
2620 this._deferredCnt--;
2621 if (this._deferredCnt === 0) {
2632 }
2633 }
2634 > textModel.ts
2635 > public recordLineAffectedByInjectedText(lineNumber: number): void {
2636 if (!this._affectedInjectedTextLines) {
2637 this._affectedInjectedTextLines = new Set();
2639 this._affectedInjectedTextLines.add(lineNumber);
2640 }
2641 > textModel.ts
2642 > public recordLineAffectedByLineHeightChange(ownerId: number, decorationId: string, lineNumber: number, lineHeight: number | null): void {
2643 if (!this._affectedLineHeights) {
2644 this._affectedLineHeights = new SetWithKey<LineHeightChangingDecoration>([], LineHeightChangingDecoration.toKey);
2646 this._affectedLineHeights.add(new LineHeightChangingDecoration(ownerId, decorationId, lineNumber, lineHeight));
2647 }
2648 > textModel.ts
2649 > public recordLineAffectedByFontChange(ownerId: number, decorationId: string, lineNumber: number): void {
2650 if (!this._affectedFontLines) {
2651 this._affectedFontLines = new SetWithKey<LineFontChangingDecoration>([], LineFontChangingDecoration.toKey);
2653 this._affectedFontLines.add(new LineFontChangingDecoration(ownerId, decorationId, lineNumber));
2654 }
2655 > textModel.ts
2656 > public checkAffectedAndFire(options: ModelDecorationOptions): void {
2657 this._affectsMinimap ||= !!options.minimap?.position;
2658 this._affectsOverviewRuler ||= !!options.overviewRuler?.color;
2661 this.tryFire();
2662 }
2663 > textModel.ts
2664 > public fire(): void {
2665 this._affectsMinimap = true;
2666 this._affectsOverviewRuler = true;
2668 this.tryFire();
2669 }
2670 > textModel.ts
2671 > private tryFire() {
2672 if (this._deferredCnt === 0) {
2673 this.doFire();
2676 }
2677 }
2678 > textModel.ts
2679 > private doFire() {
2680 this.handleBeforeFire(this._affectedInjectedTextLines, this._affectedLineHeights, this._affectedFontLines);
2681
2692 this._actual.fire(event);
2693 }
2694 > } textModel.ts
2695 >
2696 > //#endregion
2697 >
2698 > class DidChangeContentEmitter extends Disposable {
2699 >
2700 > private readonly _emitter: Emitter<InternalModelContentChangeEvent> = this._register(new Emitter<InternalModelContentChangeEvent>());
2701 > public readonly event: Event<InternalModelContentChangeEvent> = this._emitter.event;
2702 >
2703 > private _deferredCnt: number;
2704 > private _deferredEvent: InternalModelContentChangeEvent | null;
2705 >
2706 > constructor() {
2707 super();
2708 this._deferredCnt = 0;
2709 this._deferredEvent = null;
2710 }
2711 > textModel.ts
2712 > public hasListeners(): boolean {
2713 return this._emitter.hasListeners();
2714 }
2715 > textModel.ts
2716 > public beginDeferredEmit(): void {
2717 this._deferredCnt++;
2718 }
2719 > textModel.ts
2720 > public endDeferredEmit(resultingSelection: Selection[] | null = null): void {
2721 this._deferredCnt--;
2722 if (this._deferredCnt === 0) {
2729 }
2730 }
2731 > textModel.ts
2732 > public fire(e: InternalModelContentChangeEvent): void {
2733 if (this._deferredCnt > 0) {
2734 if (this._deferredEvent) {
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/platform/configuration/common/configurationRegistry.ts 616 covered LOC · 66 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- configurationRegistry.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 { distinct } from '../../../base/common/arrays.js';
7 > import { IStringDictionary } from '../../../base/common/collections.js';
8 > import { Emitter, Event } from '../../../base/common/event.js';
9 > import { IJSONSchema } from '../../../base/common/jsonSchema.js';
10 > import * as types from '../../../base/common/types.js';
11 > import * as nls from '../../../nls.js';
12 > import { getLanguageTagSettingPlainKey } from './configuration.js';
13 > import { Extensions as JSONExtensions, IJSONContributionRegistry } from '../../jsonschemas/common/jsonContributionRegistry.js';
14 > import { Registry } from '../../registry/common/platform.js';
15 > import { IPolicy, IPolicyReference, PolicyName } from '../../../base/common/policy.js';
16 > import { Disposable } from '../../../base/common/lifecycle.js';
17 > import product from '../../product/common/product.js';
18 >
19 > export enum EditPresentationTypes {
20 > Multiline = 'multilineText',
21 > Singleline = 'singlelineText'
22 > }
23 >
24 > export const Extensions = {
25 > Configuration: 'base.contributions.configuration'
26 > };
27 >
28 > export interface IConfigurationDelta {
29 > removedDefaults?: IConfigurationDefaults[];
30 > removedConfigurations?: IConfigurationNode[];
31 > addedDefaults?: IConfigurationDefaults[];
32 > addedConfigurations?: IConfigurationNode[];
33 > }
34 >
35 > export interface IConfigurationRegistry {
36 >
37 > /**
38 > * Register a configuration to the registry.
39 > */
40 > registerConfiguration(configuration: IConfigurationNode): IConfigurationNode;
41 >
42 > /**
43 > * Register multiple configurations to the registry.
44 > */
45 > registerConfigurations(configurations: IConfigurationNode[], validate?: boolean): void;
46 >
47 > /**
48 > * Deregister multiple configurations from the registry.
49 > */
50 > deregisterConfigurations(configurations: IConfigurationNode[]): void;
51 >
52 > /**
53 > * update the configuration registry by
54 > * - registering the configurations to add
55 > * - dereigstering the configurations to remove
56 > */
57 > updateConfigurations(configurations: { add: IConfigurationNode[]; remove: IConfigurationNode[] }): void;
58 >
59 > /**
60 > * Register multiple default configurations to the registry.
61 > */
62 > registerDefaultConfigurations(defaultConfigurations: IConfigurationDefaults[]): void;
63 >
64 > /**
65 > * Deregister multiple default configurations from the registry.
66 > */
67 > deregisterDefaultConfigurations(defaultConfigurations: IConfigurationDefaults[]): void;
68 >
69 > /**
70 > * Bulk update of the configuration registry (default and configurations, remove and add)
71 > * @param delta
72 > */
73 > deltaConfiguration(delta: IConfigurationDelta): void;
74 >
75 > /**
76 > * Return the registered default configurations
77 > */
78 > getRegisteredDefaultConfigurations(): IConfigurationDefaults[];
79 >
80 > /**
81 > * Return the registered configuration defaults overrides
82 > */
83 > getConfigurationDefaultsOverrides(): Map<string, IConfigurationDefaultOverrideValue>;
84 >
85 > /**
86 > * Signal that the schema of a configuration setting has changes. It is currently only supported to change enumeration values.
87 > * Property or default value changes are not allowed.
88 > */
89 > notifyConfigurationSchemaUpdated(...configurations: IConfigurationNode[]): void;
90 >
91 > /**
92 > * Event that fires whenever a configuration has been
93 > * registered.
94 > */
95 > readonly onDidSchemaChange: Event<void>;
96 >
97 > /**
98 > * Event that fires whenever a configuration has been
99 > * registered.
100 > */
101 > readonly onDidUpdateConfiguration: Event<{ properties: ReadonlySet<string>; defaultsOverrides?: boolean }>;
102 >
103 > /**
104 > * Returns all configuration nodes contributed to this registry.
105 > */
106 > getConfigurations(): IConfigurationNode[];
107 >
108 > /**
109 > * Returns all configurations settings of all configuration nodes contributed to this registry.
110 > */
111 > getConfigurationProperties(): IStringDictionary<IRegisteredConfigurationPropertySchema>;
112 >
113 > /**
114 > * Returns the owning setting key per policy name (at most one owner per name).
115 > */
116 > getPolicyConfigurations(): Map<PolicyName, string>;
117 >
118 > /**
119 > * Returns the referencing setting keys per policy name.
120 > */
121 > getPolicyReferenceConfigurations(): Map<PolicyName, Set<string>>;
122 >
123 > /**
124 > * Returns all excluded configurations settings of all configuration nodes contributed to this registry.
125 > */
126 > getExcludedConfigurationProperties(): IStringDictionary<IRegisteredConfigurationPropertySchema>;
127 >
128 > /**
129 > * Register the identifiers for editor configurations
130 > */
131 > registerOverrideIdentifiers(identifiers: string[]): void;
132 > }
133 >
134 > export const enum ConfigurationScope {
135 > /**
136 > * Application specific configuration, which can be configured only in default profile user settings.
137 > */
138 > APPLICATION = 1,
139 > /**
140 > * Machine specific configuration, which can be configured only in local and remote user settings.
141 > */
142 > MACHINE,
143 > /**
144 > * An application machine specific configuration, which can be configured only in default profile user settings and remote user settings.
145 > */
146 > APPLICATION_MACHINE,
147 > /**
148 > * Window specific configuration, which can be configured in the user or workspace settings.
149 > */
150 > WINDOW,
151 > /**
152 > * Resource specific configuration, which can be configured in the user, workspace or folder settings.
153 > */
154 > RESOURCE,
155 > /**
156 > * Resource specific configuration that can be configured in language specific settings
157 > */
158 > LANGUAGE_OVERRIDABLE,
159 > /**
160 > * Machine specific configuration that can also be configured in workspace or folder settings.
161 > */
162 > MACHINE_OVERRIDABLE,
163 > }
164 >
165 >
166 > export interface IConfigurationPropertySchema extends IJSONSchema {
167 >
168 > scope?: ConfigurationScope;
169 >
170 > /**
171 > * When restricted, value of this configuration will be read only from trusted sources.
172 > * For eg., If the workspace is not trusted, then the value of this configuration is not read from workspace settings file.
173 > */
174 > restricted?: boolean;
175 >
176 > /**
177 > * When `false` this property is excluded from the registry. Default is to include.
178 > */
179 > included?: boolean;
180 >
181 > /**
182 > * List of tags associated to the property.
183 > * - A tag can be used for filtering
184 > * - Use `experimental` tag for marking the setting as experimental.
185 > */
186 > tags?: string[];
187 >
188 > /**
189 > * When enabled this setting is ignored during sync and user can override this.
190 > */
191 > ignoreSync?: boolean;
192 >
193 > /**
194 > * When enabled this setting is ignored during sync and user cannot override this.
195 > */
196 > disallowSyncIgnore?: boolean;
197 >
198 > /**
199 > * Disallow extensions to contribute configuration default value for this setting.
200 > */
201 > disallowConfigurationDefault?: boolean;
202 >
203 > /**
204 > * Labels for enumeration items
205 > */
206 > enumItemLabels?: string[];
207 >
208 > /**
209 > * Optional keywords used for search purposes.
210 > */
211 > keywords?: string[];
212 >
213 > /**
214 > * When specified, controls the presentation format of string settings.
215 > * Otherwise, the presentation format defaults to `singleline`.
216 > */
217 > editPresentation?: EditPresentationTypes;
218 >
219 > /**
220 > * When specified, gives an order number for the setting
221 > * within the settings editor. Otherwise, the setting is placed at the end.
222 > */
223 > order?: number;
224 >
225 > /**
226 > * When specified, this setting's value can always be overwritten by
227 > * a system-wide policy. Exactly one setting may *own* a given policy name.
228 > */
229 > policy?: IPolicy;
230 >
231 > /**
232 > * When specified, this setting is governed by a policy owned by another setting.
233 > * A setting must not declare both `policy` and `policyReference`.
234 > * The type must match the owning setting (enforced when exporting the policy catalog).
235 > */
236 > policyReference?: IPolicyReference;
237 >
238 > /**
239 > * When specified, this setting's default value can always be overwritten by
240 > * an experiment.
241 > */
242 > experiment?: {
243 > /**
244 > * The mode of the experiment.
245 > * - `startup`: The setting value is updated to the experiment value only on startup.
246 > * - `auto`: The setting value is updated to the experiment value automatically (whenever the experiment value changes).
247 > */
248 > mode: 'startup' | 'auto';
249 >
250 > /**
251 > * The name of the experiment. By default, this is `config.${settingId}`
252 > */
253 > name?: string;
254 > };
255 >
256 > /**
257 > * When specified, provides configuration overrides for the Agents window.
258 > */
259 > agentsWindow?: {
260 > /**
261 > * Override default value for this setting in the Agents window.
262 > */
263 > default?: unknown;
264 >
265 > /**
266 > * When `true`, this setting is read-only in the Agents window
267 > * and cannot be changed by the user.
268 > */
269 > readOnly?: boolean;
270 > };
271 > }
272 >
273 > export interface IExtensionInfo {
274 > id: string;
275 > displayName?: string;
276 > }
277 >
278 > export interface IConfigurationNode {
279 > id?: string;
280 > order?: number;
281 > type?: string | string[];
282 > title?: string;
283 > description?: string;
284 > properties?: IStringDictionary<IConfigurationPropertySchema>;
285 > allOf?: IConfigurationNode[];
286 > scope?: ConfigurationScope;
287 > extensionInfo?: IExtensionInfo;
288 > restrictedProperties?: string[];
289 > }
290 >
291 > export type ConfigurationDefaultSource = IExtensionInfo | string;
292 >
293 > export function isConfigurationDefaultSourceEquals(a: ConfigurationDefaultSource | undefined, b: ConfigurationDefaultSource | undefined): boolean {
294 if (a === b) {
295 return true;
303 return a.id === b.id;
304 }
306 > export type ConfigurationDefaultValueSource = ConfigurationDefaultSource | Map<string, ConfigurationDefaultSource>;
307 >
308 > export interface IConfigurationDefaults {
309 > overrides: IStringDictionary<unknown>;
310 > source?: ConfigurationDefaultSource;
311 > donotCache?: boolean;
312 > preventExperimentOverride?: boolean;
313 > }
314 >
315 > export type IRegisteredConfigurationPropertySchema = IConfigurationPropertySchema & {
316 > section?: {
317 > id?: string;
318 > title?: string;
319 > order?: number;
320 > extensionInfo?: IExtensionInfo;
321 > };
322 > defaultDefaultValue?: unknown;
323 > source?: ConfigurationDefaultSource; // Source of the Property
324 > defaultValueSource?: ConfigurationDefaultValueSource; // Source of the Default Value
325 > };
326 >
327 > export interface IConfigurationDefaultOverride {
328 > readonly value: unknown;
329 > readonly source?: ConfigurationDefaultSource; // Source of the default override
330 > }
331 >
332 > export interface IConfigurationDefaultOverrideValue {
333 > readonly value: unknown;
334 > readonly source?: ConfigurationDefaultValueSource;
335 > }
336 >
337 > export const allSettings: { properties: IStringDictionary<IConfigurationPropertySchema>; patternProperties: IStringDictionary<IConfigurationPropertySchema> } = { properties: {}, patternProperties: {} };
338 > export const applicationSettings: { properties: IStringDictionary<IConfigurationPropertySchema>; patternProperties: IStringDictionary<IConfigurationPropertySchema> } = { properties: {}, patternProperties: {} };
339 > export const applicationMachineSettings: { properties: IStringDictionary<IConfigurationPropertySchema>; patternProperties: IStringDictionary<IConfigurationPropertySchema> } = { properties: {}, patternProperties: {} };
340 > export const machineSettings: { properties: IStringDictionary<IConfigurationPropertySchema>; patternProperties: IStringDictionary<IConfigurationPropertySchema> } = { properties: {}, patternProperties: {} };
341 > export const machineOverridableSettings: { properties: IStringDictionary<IConfigurationPropertySchema>; patternProperties: IStringDictionary<IConfigurationPropertySchema> } = { properties: {}, patternProperties: {} };
342 > export const windowSettings: { properties: IStringDictionary<IConfigurationPropertySchema>; patternProperties: IStringDictionary<IConfigurationPropertySchema> } = { properties: {}, patternProperties: {} };
343 > export const resourceSettings: { properties: IStringDictionary<IConfigurationPropertySchema>; patternProperties: IStringDictionary<IConfigurationPropertySchema> } = { properties: {}, patternProperties: {} };
344 >
345 > export const resourceLanguageSettingsSchemaId = 'vscode://schemas/settings/resourceLanguage';
346 > export const configurationDefaultsSchemaId = 'vscode://schemas/settings/configurationDefaults';
347 >
348 > const contributionRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
349 >
350 > class ConfigurationRegistry extends Disposable implements IConfigurationRegistry {
351 >
352 > private readonly registeredConfigurationDefaults: IConfigurationDefaults[] = [];
353 > private readonly configurationDefaultsOverrides: Map<string, { configurationDefaultOverrides: IConfigurationDefaultOverride[]; configurationDefaultOverrideValue?: IConfigurationDefaultOverrideValue }>;
354 > private readonly defaultLanguageConfigurationOverridesNode: IConfigurationNode;
355 > private readonly configurationContributors: IConfigurationNode[];
356 > private readonly configurationProperties: IStringDictionary<IRegisteredConfigurationPropertySchema>;
357 > private readonly policyConfigurations: Map<PolicyName, string>;
358 > private readonly policyReferenceConfigurations: Map<PolicyName, Set<string>>;
359 > private readonly excludedConfigurationProperties: IStringDictionary<IRegisteredConfigurationPropertySchema>;
360 > private readonly resourceLanguageSettingsSchema: IJSONSchema;
361 > private readonly overrideIdentifiers = new Set<string>();
362 >
363 > private readonly _onDidSchemaChange = this._register(new Emitter<void>());
364 > readonly onDidSchemaChange: Event<void> = this._onDidSchemaChange.event;
365 >
366 > private readonly _onDidUpdateConfiguration = this._register(new Emitter<{ properties: ReadonlySet<string>; defaultsOverrides?: boolean }>());
367 > readonly onDidUpdateConfiguration = this._onDidUpdateConfiguration.event;
368 >
369 > constructor() {
370 > super();
371 > this.configurationDefaultsOverrides = new Map();
372 > this.defaultLanguageConfigurationOverridesNode = {
373 > id: 'defaultOverrides',
374 > title: nls.localize('defaultLanguageConfigurationOverrides.title', "Default Language Configuration Overrides"),
375 > properties: {}
376 > };
377 > this.configurationContributors = [this.defaultLanguageConfigurationOverridesNode];
378 > this.resourceLanguageSettingsSchema = {
379 > properties: {},
380 > patternProperties: {},
381 > additionalProperties: true,
382 > allowTrailingCommas: true,
383 > allowComments: true
384 > };
385 > this.configurationProperties = {};
386 > this.policyConfigurations = new Map<PolicyName, string>();
387 > this.policyReferenceConfigurations = new Map<PolicyName, Set<string>>();
388 > this.excludedConfigurationProperties = {};
389 >
390 > contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
391 > this.registerOverridePropertyPatternKey();
392 > }
393 >
394 > public registerConfiguration(configuration: IConfigurationNode, validate: boolean = true): IConfigurationNode {
395 this.registerConfigurations([configuration], validate);
396 return configuration;
397 }
399 > public registerConfigurations(configurations: IConfigurationNode[], validate: boolean = true): void {
400 const properties = new Set<string>();
401 this.doRegisterConfigurations(configurations, validate, properties);
405 this._onDidUpdateConfiguration.fire({ properties });
406 }
408 > public deregisterConfigurations(configurations: IConfigurationNode[]): void {
409 const properties = new Set<string>();
410 this.doDeregisterConfigurations(configurations, properties);
414 this._onDidUpdateConfiguration.fire({ properties });
415 }
417 > public updateConfigurations({ add, remove }: { add: IConfigurationNode[]; remove: IConfigurationNode[] }): void {
418 const properties = new Set<string>();
419 this.doDeregisterConfigurations(remove, properties);
424 this._onDidUpdateConfiguration.fire({ properties });
425 }
427 > public registerDefaultConfigurations(configurationDefaults: IConfigurationDefaults[]): void {
428 > const properties = new Set<string>(); configurationRegistry.ts
429 > this.doRegisterDefaultConfigurations(configurationDefaults, properties);
430 > this._onDidSchemaChange.fire();
431 > this._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });
432 > }
434 > private doRegisterDefaultConfigurations(configurationDefaults: IConfigurationDefaults[], bucket: Set<string>) {
436 > this.registeredConfigurationDefaults.push(...configurationDefaults);
437 >
438 > const overrideIdentifiers: string[] = [];
439 >
440 > for (const { overrides, source } of configurationDefaults) {
441 > for (const key in overrides) {
442 > bucket.add(key);
443 >
444 > const configurationDefaultOverridesForKey = this.configurationDefaultsOverrides.get(key)
445 > ?? this.configurationDefaultsOverrides.set(key, { configurationDefaultOverrides: [] }).get(key)!;
446 >
447 > const value = overrides[key];
448 > configurationDefaultOverridesForKey.configurationDefaultOverrides.push({ value, source });
449 >
450 > // Configuration defaults for Override Identifiers
451 > if (OVERRIDE_PROPERTY_REGEX.test(key)) {
452 > const newDefaultOverride = this.mergeDefaultConfigurationsForOverrideIdentifier(key, value as IStringDictionary<unknown>, source, configurationDefaultOverridesForKey.configurationDefaultOverrideValue); configurationRegistry.ts
453 > if (!newDefaultOverride) {
454 continue;
455 }
457 > configurationDefaultOverridesForKey.configurationDefaultOverrideValue = newDefaultOverride;
458 > this.updateDefaultOverrideProperty(key, newDefaultOverride, source);
459 > overrideIdentifiers.push(...overrideIdentifiersFromKey(key));
460 > }
461
462 // Configuration defaults for Configuration Properties
474 }
475 }
477 > }
478 > }
479 >
480 > this.doRegisterOverrideIdentifiers(overrideIdentifiers);
481 > }
483 > public deregisterDefaultConfigurations(defaultConfigurations: IConfigurationDefaults[]): void {
484 const properties = new Set<string>();
485 this.doDeregisterDefaultConfigurations(defaultConfigurations, properties);
487 this._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });
488 }
490 > private doDeregisterDefaultConfigurations(defaultConfigurations: IConfigurationDefaults[], bucket: Set<string>): void {
491 for (const defaultConfiguration of defaultConfigurations) {
492 const index = this.registeredConfigurationDefaults.indexOf(defaultConfiguration);
544 this.updateOverridePropertyPatternKey();
545 }
547 > private updateDefaultOverrideProperty(key: string, newDefaultOverride: IConfigurationDefaultOverrideValue, source: ConfigurationDefaultSource | undefined): void {
548 > const property: IRegisteredConfigurationPropertySchema = { configurationRegistry.ts
549 > section: {
550 > id: this.defaultLanguageConfigurationOverridesNode.id,
551 > title: this.defaultLanguageConfigurationOverridesNode.title,
552 > order: this.defaultLanguageConfigurationOverridesNode.order,
553 > extensionInfo: this.defaultLanguageConfigurationOverridesNode.extensionInfo
554 > },
555 > type: 'object',
556 > default: newDefaultOverride.value,
557 > description: nls.localize('defaultLanguageConfiguration.description', "Configure settings to be overridden for {0}.", getLanguageTagSettingPlainKey(key)),
558 > $ref: resourceLanguageSettingsSchemaId,
559 > defaultDefaultValue: newDefaultOverride.value,
560 > source,
561 > defaultValueSource: source
562 > };
563 > this.configurationProperties[key] = property;
564 > this.defaultLanguageConfigurationOverridesNode.properties![key] = property;
565 > }
567 > private mergeDefaultConfigurationsForOverrideIdentifier(overrideIdentifier: string, configurationValueObject: IStringDictionary<unknown>, valueSource: ConfigurationDefaultSource | undefined, existingDefaultOverride: IConfigurationDefaultOverrideValue | undefined): IConfigurationDefaultOverrideValue | undefined {
568 > const defaultValue = existingDefaultOverride?.value || {}; configurationRegistry.ts
569 > const source = existingDefaultOverride?.source ?? new Map<string, ConfigurationDefaultSource>();
570 >
571 > // This should not happen
572 > if (!(source instanceof Map)) {
573 console.error('objectConfigurationSources is not a Map');
574 return undefined;
575 }
577 > for (const propertyKey of Object.keys(configurationValueObject)) {
578 > const propertyDefaultValue = configurationValueObject[propertyKey];
579 >
580 > const isObjectSetting = types.isObject(propertyDefaultValue) &&
581 (types.isUndefined((defaultValue as IStringDictionary<unknown>)[propertyKey]) || types.isObject((defaultValue as IStringDictionary<unknown>)[propertyKey]));
583 > // If the default value is an object, merge the objects and store the source of each keys
584 > if (isObjectSetting) {
585 (defaultValue as IStringDictionary<unknown>)[propertyKey] = { ...((defaultValue as IStringDictionary<unknown>)[propertyKey] ?? {}), ...propertyDefaultValue };
586 // Track the source of each value in the object
591 }
592 }
594 > // Primitive values are overridden
595 > else {
596 > (defaultValue as IStringDictionary<unknown>)[propertyKey] = propertyDefaultValue;
597 > if (valueSource) {
598 source.set(propertyKey, valueSource);
599 > } else { configurationRegistry.ts
600 > source.delete(propertyKey);
601 > }
602 > }
604 >
605 > return { value: defaultValue, source };
606 > }
608 > private mergeDefaultConfigurationsForConfigurationProperty(propertyKey: string, value: unknown, valuesSource: ConfigurationDefaultSource | undefined, existingDefaultOverride: IConfigurationDefaultOverrideValue | undefined): IConfigurationDefaultOverrideValue | undefined {
609 const property = this.configurationProperties[propertyKey];
610 const existingDefaultValue = existingDefaultOverride?.value ?? property?.defaultDefaultValue;
637 return { value, source };
638 }
640 > public deltaConfiguration(delta: IConfigurationDelta): void {
641 // defaults: remove
642 let defaultsOverrides = false;
662 this._onDidUpdateConfiguration.fire({ properties, defaultsOverrides });
663 }
665 > public notifyConfigurationSchemaUpdated(...configurations: IConfigurationNode[]) {
666 this._onDidSchemaChange.fire();
667 }
669 > public registerOverrideIdentifiers(overrideIdentifiers: string[]): void {
670 this.doRegisterOverrideIdentifiers(overrideIdentifiers);
671 this._onDidSchemaChange.fire();
672 }
674 > private doRegisterOverrideIdentifiers(overrideIdentifiers: string[]) {
675 > for (const overrideIdentifier of overrideIdentifiers) { configurationRegistry.ts
676 > this.overrideIdentifiers.add(overrideIdentifier); configurationRegistry.ts
677 > }
678 > this.updateOverridePropertyPatternKey(); configurationRegistry.ts
679 > }
681 > private doRegisterConfigurations(configurations: IConfigurationNode[], validate: boolean, bucket: Set<string>): void {
682
683 configurations.forEach(configuration => {
689 });
690 }
692 > private doDeregisterConfigurations(configurations: IConfigurationNode[], bucket: Set<string>): void {
693
694 const deregisterConfiguration = (configuration: IConfigurationNode) => {
723 }
724 }
726 > private validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, extensionInfo: IExtensionInfo | undefined, restrictedProperties: string[] | undefined, scope: ConfigurationScope = ConfigurationScope.WINDOW, bucket: Set<string>): void {
727 scope = types.isUndefinedOrNull(configuration.scope) ? scope : configuration.scope;
728 const properties = configuration.properties;
805 }
806 }
808 > private addPolicyReferenceConfiguration(policyName: PolicyName, key: string): void {
809 let keys = this.policyReferenceConfigurations.get(policyName);
810 if (!keys) {
814 keys.add(key);
815 }
817 > // Only for tests
818 > getConfigurations(): IConfigurationNode[] {
819 return this.configurationContributors;
820 }
822 > getConfigurationProperties(): IStringDictionary<IRegisteredConfigurationPropertySchema> {
823 return this.configurationProperties;
824 }
826 > getPolicyConfigurations(): Map<PolicyName, string> {
827 return this.policyConfigurations;
828 }
830 > getPolicyReferenceConfigurations(): Map<PolicyName, Set<string>> {
831 return this.policyReferenceConfigurations;
832 }
834 > getExcludedConfigurationProperties(): IStringDictionary<IRegisteredConfigurationPropertySchema> {
835 return this.excludedConfigurationProperties;
836 }
838 > getRegisteredDefaultConfigurations(): IConfigurationDefaults[] {
839 return [...this.registeredConfigurationDefaults];
840 }
842 > getConfigurationDefaultsOverrides(): Map<string, IConfigurationDefaultOverrideValue> {
843 const configurationDefaultsOverrides = new Map<string, IConfigurationDefaultOverrideValue>();
844 for (const [key, value] of this.configurationDefaultsOverrides) {
849 return configurationDefaultsOverrides;
850 }
852 > private registerJSONConfiguration(configuration: IConfigurationNode) {
853 const register = (configuration: IConfigurationNode) => {
854 const properties = configuration.properties;
863 register(configuration);
864 }
866 > private updateSchema(key: string, property: IConfigurationPropertySchema): void {
867 allSettings.properties[key] = property;
868 switch (property.scope) {
891 }
892 }
894 > private removeFromSchema(key: string, property: IConfigurationPropertySchema): void {
895 delete allSettings.properties[key];
896 switch (property.scope) {
917 }
918 }
920 > private updateOverridePropertyPatternKey(): void {
921 > for (const overrideIdentifier of this.overrideIdentifiers.values()) { configurationRegistry.ts
922 > const overrideIdentifierProperty = `[${overrideIdentifier}]`; configurationRegistry.ts
923 > const resourceLanguagePropertiesSchema: IJSONSchema = {
924 > type: 'object',
925 > description: nls.localize('overrideSettings.defaultDescription', "Configure editor settings to be overridden for a language."),
926 > errorMessage: nls.localize('overrideSettings.errorMessage', "This setting does not support per-language configuration."),
927 > $ref: resourceLanguageSettingsSchemaId,
928 > };
929 > this.updatePropertyDefaultValue(overrideIdentifierProperty, resourceLanguagePropertiesSchema);
930 > allSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
931 > applicationSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
932 > applicationMachineSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
933 > machineSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
934 > machineOverridableSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
935 > windowSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
936 > resourceSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
937 > }
940 > private registerOverridePropertyPatternKey(): void {
941 > const resourceLanguagePropertiesSchema: IJSONSchema = {
942 > type: 'object',
943 > description: nls.localize('overrideSettings.defaultDescription', "Configure editor settings to be overridden for a language."),
944 > errorMessage: nls.localize('overrideSettings.errorMessage', "This setting does not support per-language configuration."),
945 > $ref: resourceLanguageSettingsSchemaId,
946 > };
947 > allSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
948 > applicationSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
949 > applicationMachineSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
950 > machineSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
951 > machineOverridableSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
952 > windowSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
953 > resourceSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
954 > this._onDidSchemaChange.fire();
955 > }
956 >
957 > private updatePropertyDefaultValue(key: string, property: IRegisteredConfigurationPropertySchema): void {
958 > const configurationdefaultOverride = this.configurationDefaultsOverrides.get(key)?.configurationDefaultOverrideValue; configurationRegistry.ts
959 > let defaultValue = undefined;
960 > let defaultSource = undefined;
961 > if (configurationdefaultOverride
962 > && (!property.disallowConfigurationDefault || !configurationdefaultOverride.source) // Prevent overriding the default value if the property is disallowed to be overridden by configuration defaults from extensions configurationRegistry.ts
964 > defaultValue = configurationdefaultOverride.value; configurationRegistry.ts
965 > defaultSource = configurationdefaultOverride.source;
966 > }
967 > if (types.isUndefined(defaultValue)) { configurationRegistry.ts
968 defaultValue = property.defaultDefaultValue;
969 defaultSource = undefined;
970 }
971 > if (types.isUndefined(defaultValue)) { configurationRegistry.ts
972 defaultValue = getDefaultValue(property.type);
973 }
974 > property.default = defaultValue; configurationRegistry.ts
975 > property.defaultValueSource = defaultSource;
976 > }
978 >
979 > const OVERRIDE_IDENTIFIER_PATTERN = `\\[([^\\]]+)\\]`;
980 > const OVERRIDE_IDENTIFIER_REGEX = new RegExp(OVERRIDE_IDENTIFIER_PATTERN, 'g');
981 > export const OVERRIDE_PROPERTY_PATTERN = `^(${OVERRIDE_IDENTIFIER_PATTERN})+$`;
982 > export const OVERRIDE_PROPERTY_REGEX = new RegExp(OVERRIDE_PROPERTY_PATTERN);
983 >
984 > export function overrideIdentifiersFromKey(key: string): string[] {
985 > const identifiers: string[] = []; configurationRegistry.ts
986 > if (OVERRIDE_PROPERTY_REGEX.test(key)) {
987 > let matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
988 > while (matches?.length) {
989 > const identifier = matches[1].trim();
990 > if (identifier) {
991 > identifiers.push(identifier);
992 > }
993 > matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
994 > }
995 > }
996 > return distinct(identifiers);
997 > }
999 > export function keyFromOverrideIdentifiers(overrideIdentifiers: string[]): string {
1000 return overrideIdentifiers.reduce((result, overrideIdentifier) => `${result}[${overrideIdentifier}]`, '');
1001 }
1003 > export function getDefaultValue(type: string | string[] | undefined) {
1004 const t = Array.isArray(type) ? type[0] : <string>type;
1005 switch (t) {
1019 }
1020 }
1022 > const configurationRegistry = new ConfigurationRegistry();
1023 > Registry.add(Extensions.Configuration, configurationRegistry);
1024 >
1025 > export function validateProperty(property: string, schema: IRegisteredConfigurationPropertySchema, extensionId?: string): string | null {
1026 if (!property.trim()) {
1027 return nls.localize('config.property.empty', "Cannot register an empty property");
1041 return null;
1042 }
1044 > export function getScopes(): [string, ConfigurationScope | undefined][] {
1045 const scopes: [string, ConfigurationScope | undefined][] = [];
1046 const configurationProperties = configurationRegistry.getConfigurationProperties();
1052 return scopes;
1053 }
1055 > export function getAllConfigurationProperties(configurationNode: IConfigurationNode[]): IStringDictionary<IRegisteredConfigurationPropertySchema> {
1056 const result: IStringDictionary<IRegisteredConfigurationPropertySchema> = {};
1057 for (const configuration of configurationNode) {
1068 return result;
1069 }
1071 > export function parseScope(scope: string): ConfigurationScope {
1072 switch (scope) {
1073 case 'application':
1085 }
1086 }
1088 > // Used for extension unification. Should be removed when complete.
1089 > export const EXTENSION_UNIFICATION_EXTENSION_IDS: Set<string> = new Set(product.defaultChatAgent ? [product.defaultChatAgent.extensionId, product.defaultChatAgent.chatExtensionId].map(id => id.toLowerCase()) : []);
src/vs/base/common/lifecycle.ts 546 covered LOC · 123 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); lifecycle.ts
92 > if (!val) {
93 > val = { parent: null, source: null, isSingleton: false, value: d, idx: DisposableTracker.idx++ };
94 > this.livingDisposables.set(d, val);
95 > }
96 > return val;
97 > }
99 > trackDisposable(d: IDisposable): void {
100 > const data = this.getDisposableData(d); lifecycle.ts
101 > if (!data.source) {
102 > data.source =
103 > new Error().stack!;
104 > }
105 > }
106 > lifecycle.ts
107 > setParent(child: IDisposable, parent: IDisposable | null): void {
108 > const data = this.getDisposableData(child); lifecycle.ts
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 { lifecycle.ts
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)) { lifecycle.ts
334 > const errors: any[] = []; lifecycle.ts
335 >
336 > for (const d of arg) {
337 > if (d) { lifecycle.ts
338 > try {
339 > d.dispose();
340 > } catch (e) {
341 errors.push(e);
342 }
343 > } lifecycle.ts
344 > }
345 > lifecycle.ts
346 > if (errors.length === 1) {
347 throw errors[0];
348 > } else if (errors.length > 1) { lifecycle.ts
349 throw new AggregateError(errors, 'Encountered errors while disposing of store');
350 }
351 > lifecycle.ts
352 > return Array.isArray(arg) ? [] : arg; lifecycle.ts
353 > } else if (arg) { lifecycle.ts
354 arg.dispose();
355 return arg;
356 }
357 > } lifecycle.ts
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; lifecycle.ts
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); lifecycle.ts
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;
455 }
456 > lifecycle.ts
457 > try {
458 > dispose(this._toDispose);
459 > } finally {
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) { lifecycle.ts
469 return o;
470 }
471 > if ((o as unknown as DisposableStore) === this) { lifecycle.ts
472 throw new Error('Cannot register a disposable on itself!');
473 }
474 > lifecycle.ts
475 > setParentOfDisposable(o, this);
476 > if (this._isDisposed) {
477 if (!DisposableStore.DISABLE_DISPOSED_WARNING) {
478 console.warn(new Error('Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!').stack);
479 }
480 > } else { lifecycle.ts
481 > this._toDispose.add(o);
482 > }
483 >
484 > return o;
485 > } lifecycle.ts
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); lifecycle.ts
539 > setParentOfDisposable(this._store, this);
540 > }
541 > lifecycle.ts
542 > public dispose(): void {
543 > markAsDisposed(this); lifecycle.ts
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) { lifecycle.ts
553 throw new Error('Cannot register a disposable on itself!');
554 }
555 > return this._store.add(o); lifecycle.ts
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/platform/dialogs/common/dialogs.ts 511 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- dialogs.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CancellationToken } from '../../../base/common/cancellation.js';
7 > import { Event } from '../../../base/common/event.js';
8 > import { ThemeIcon } from '../../../base/common/themables.js';
9 > import { IMarkdownString } from '../../../base/common/htmlContent.js';
10 > import { basename } from '../../../base/common/resources.js';
11 > import Severity from '../../../base/common/severity.js';
12 > import { URI } from '../../../base/common/uri.js';
13 > import { localize } from '../../../nls.js';
14 > import { createDecorator } from '../../instantiation/common/instantiation.js';
15 > import { ITelemetryData } from '../../telemetry/common/telemetry.js';
16 >
17 > export interface IDialogArgs {
18 > readonly confirmArgs?: IConfirmDialogArgs;
19 > readonly inputArgs?: IInputDialogArgs;
20 > readonly promptArgs?: IPromptDialogArgs;
21 > }
22 >
23 > export interface IBaseDialogOptions {
24 > readonly type?: Severity | DialogType;
25 >
26 > readonly title?: string;
27 > readonly message: string;
28 > readonly detail?: string;
29 >
30 > readonly checkbox?: ICheckbox;
31 >
32 > /**
33 > * Allows to enforce use of custom dialog even in native environments.
34 > */
35 > readonly custom?: boolean | ICustomDialogOptions;
36 >
37 > /**
38 > * An optional cancellation token that can be used to dismiss the dialog
39 > * programmatically for custom dialog implementations.
40 > *
41 > * When cancelled, the custom dialog resolves as if the cancel button was
42 > * pressed. Native dialog handlers cannot currently be dismissed
43 > * programmatically and ignore this option unless a custom dialog is
44 > * explicitly enforced via the {@link custom} option.
45 > */
46 > readonly token?: CancellationToken;
47 > }
48 >
49 > export interface IConfirmDialogArgs {
50 > readonly confirmation: IConfirmation;
51 > }
52 >
53 > export interface IConfirmation extends IBaseDialogOptions {
54 >
55 > /**
56 > * If not provided, defaults to `Yes`.
57 > */
58 > readonly primaryButton?: string;
59 >
60 > /**
61 > * If not provided, defaults to `Cancel`.
62 > */
63 > readonly cancelButton?: string;
64 > }
65 >
66 > export interface IConfirmationResult extends ICheckboxResult {
67 >
68 > /**
69 > * Will be true if the dialog was confirmed with the primary button pressed.
70 > */
71 > readonly confirmed: boolean;
72 > }
73 >
74 > export interface IInputDialogArgs {
75 > readonly input: IInput;
76 > }
77 >
78 > export interface IInput extends IConfirmation {
79 > readonly inputs: IInputElement[];
80 >
81 > /**
82 > * If not provided, defaults to `Ok`.
83 > */
84 > readonly primaryButton?: string;
85 > }
86 >
87 > export interface IInputElement {
88 > readonly type?: 'text' | 'password';
89 > readonly value?: string;
90 > readonly placeholder?: string;
91 > }
92 >
93 > export interface IInputResult extends IConfirmationResult {
94 >
95 > /**
96 > * Values for the input fields as provided by the user or `undefined` if none.
97 > */
98 > readonly values?: string[];
99 > }
100 >
101 > export interface IPromptDialogArgs {
102 > readonly prompt: IPrompt<unknown>;
103 > }
104 >
105 > export interface IPromptBaseButton<T> {
106 >
107 > /**
108 > * @returns the result of the prompt button will be returned
109 > * as result from the `prompt()` call.
110 > */
111 > run(checkbox: ICheckboxResult): T | Promise<T>;
112 > }
113 >
114 > export interface IPromptButton<T> extends IPromptBaseButton<T> {
115 > readonly label: string;
116 > }
117 >
118 > export interface IPromptCancelButton<T> extends IPromptBaseButton<T> {
119 >
120 > /**
121 > * The cancel button to show in the prompt. Defaults to
122 > * `Cancel` if not provided.
123 > */
124 > readonly label?: string;
125 > }
126 >
127 > export interface IPrompt<T> extends IBaseDialogOptions {
128 >
129 > /**
130 > * The buttons to show in the prompt. Defaults to `OK`
131 > * if no buttons or cancel button is provided.
132 > */
133 > readonly buttons?: IPromptButton<T>[];
134 >
135 > /**
136 > * The cancel button to show in the prompt. Defaults to
137 > * `Cancel` if set to `true`.
138 > */
139 > readonly cancelButton?: IPromptCancelButton<T> | true | string;
140 > }
141 >
142 > export interface IPromptWithCustomCancel<T> extends IPrompt<T> {
143 > readonly cancelButton: IPromptCancelButton<T>;
144 > }
145 >
146 > export interface IPromptWithDefaultCancel<T> extends IPrompt<T> {
147 > readonly cancelButton: true | string;
148 > }
149 >
150 > export interface IPromptResult<T> extends ICheckboxResult {
151 >
152 > /**
153 > * The result of the `IPromptButton` that was pressed or `undefined` if none.
154 > */
155 > readonly result?: T;
156 > }
157 >
158 > export interface IPromptResultWithCancel<T> extends IPromptResult<T> {
159 > readonly result: T;
160 > }
161 >
162 > export interface IAsyncPromptResult<T> extends ICheckboxResult {
163 >
164 > /**
165 > * The result of the `IPromptButton` that was pressed or `undefined` if none.
166 > */
167 > readonly result?: Promise<T>;
168 > }
169 >
170 > export interface IAsyncPromptResultWithCancel<T> extends IAsyncPromptResult<T> {
171 > readonly result: Promise<T>;
172 > }
173 >
174 > export type IDialogResult = IConfirmationResult | IInputResult | IAsyncPromptResult<unknown>;
175 >
176 > export type DialogType = 'none' | 'info' | 'error' | 'question' | 'warning';
177 >
178 > export interface ICheckbox {
179 > readonly label: string;
180 > readonly checked?: boolean;
181 > }
182 >
183 > export interface ICheckboxResult {
184 >
185 > /**
186 > * This will only be defined if the confirmation was created
187 > * with the checkbox option defined.
188 > */
189 > readonly checkboxChecked?: boolean;
190 > }
191 >
192 > export interface IPickAndOpenOptions {
193 > readonly forceNewWindow?: boolean;
194 > defaultUri?: URI;
195 > readonly telemetryExtraData?: ITelemetryData;
196 > availableFileSystems?: string[];
197 > remoteAuthority?: string | null;
198 > }
199 >
200 > export interface FileFilter {
201 > readonly extensions: string[];
202 > readonly name: string;
203 > }
204 >
205 > export interface ISaveDialogOptions {
206 >
207 > /**
208 > * A human-readable string for the dialog title
209 > */
210 > title?: string;
211 >
212 > /**
213 > * The resource the dialog shows when opened.
214 > */
215 > defaultUri?: URI;
216 >
217 > /**
218 > * A set of file filters that are used by the dialog. Each entry is a human readable label,
219 > * like "TypeScript", and an array of extensions.
220 > */
221 > filters?: FileFilter[];
222 >
223 > /**
224 > * A human-readable string for the ok button
225 > */
226 > readonly saveLabel?: { readonly withMnemonic: string; readonly withoutMnemonic: string } | string;
227 >
228 > /**
229 > * Specifies a list of schemas for the file systems the user can save to. If not specified, uses the schema of the defaultURI or, if also not specified,
230 > * the schema of the current window.
231 > */
232 > availableFileSystems?: readonly string[];
233 > }
234 >
235 > export interface IOpenDialogOptions {
236 >
237 > /**
238 > * A human-readable string for the dialog title
239 > */
240 > readonly title?: string;
241 >
242 > /**
243 > * The resource the dialog shows when opened.
244 > */
245 > defaultUri?: URI;
246 >
247 > /**
248 > * A human-readable string for the open button.
249 > */
250 > readonly openLabel?: { readonly withMnemonic: string; readonly withoutMnemonic: string } | string;
251 >
252 > /**
253 > * Allow to select files, defaults to `true`.
254 > */
255 > canSelectFiles?: boolean;
256 >
257 > /**
258 > * Allow to select folders, defaults to `false`.
259 > */
260 > canSelectFolders?: boolean;
261 >
262 > /**
263 > * Allow to select many files or folders.
264 > */
265 > readonly canSelectMany?: boolean;
266 >
267 > /**
268 > * A set of file filters that are used by the dialog. Each entry is a human readable label,
269 > * like "TypeScript", and an array of extensions.
270 > */
271 > filters?: FileFilter[];
272 >
273 > /**
274 > * Specifies a list of schemas for the file systems the user can load from. If not specified, uses the schema of the defaultURI or, if also not available,
275 > * the schema of the current window.
276 > */
277 > availableFileSystems?: readonly string[];
278 > }
279 >
280 > export const IDialogService = createDecorator<IDialogService>('dialogService');
281 >
282 > export interface ICustomDialogOptions {
283 > readonly buttonDetails?: string[];
284 > readonly markdownDetails?: ICustomDialogMarkdown[];
285 > readonly classes?: string[];
286 > readonly icon?: ThemeIcon;
287 > readonly disableCloseAction?: boolean;
288 > }
289 >
290 > export interface ICustomDialogMarkdown {
291 > readonly markdown: IMarkdownString;
292 > readonly classes?: string[];
293 > /** Custom link handler for markdown content, see {@link IContentActionHandler}. Defaults to {@link openLinkFromMarkdown}. */
294 > actionHandler?(link: string): Promise<boolean>;
295 > }
296 >
297 > /**
298 > * A handler to bring up modal dialogs.
299 > */
300 > export interface IDialogHandler {
301 >
302 > /**
303 > * Ask the user for confirmation with a modal dialog.
304 > */
305 > confirm(confirmation: IConfirmation): Promise<IConfirmationResult>;
306 >
307 > /**
308 > * Prompt the user with a modal dialog.
309 > */
310 > prompt<T>(prompt: IPrompt<T>): Promise<IAsyncPromptResult<T>>;
311 >
312 > /**
313 > * Present a modal dialog to the user asking for input.
314 > */
315 > input(input: IInput): Promise<IInputResult>;
316 >
317 > /**
318 > * Present the about dialog to the user.
319 > */
320 > about(title: string, details: string, detailsToCopy: string): Promise<void>;
321 > }
322 >
323 > enum DialogKind {
324 > Confirmation = 1,
325 > Prompt,
326 > Input
327 > }
328 >
329 > export abstract class AbstractDialogHandler implements IDialogHandler {
330 >
331 > protected getConfirmationButtons(dialog: IConfirmation): string[] {
332 return this.getButtons(dialog, DialogKind.Confirmation);
333 }
334 > dialogs.ts
335 > protected getPromptButtons(dialog: IPrompt<unknown>): string[] {
336 return this.getButtons(dialog, DialogKind.Prompt);
337 }
338 > dialogs.ts
339 > protected getInputButtons(dialog: IInput): string[] {
340 return this.getButtons(dialog, DialogKind.Input);
341 }
342 > dialogs.ts
343 > private getButtons(dialog: IConfirmation, kind: DialogKind.Confirmation): string[];
344 > private getButtons(dialog: IPrompt<unknown>, kind: DialogKind.Prompt): string[];
345 > private getButtons(dialog: IInput, kind: DialogKind.Input): string[];
346 > private getButtons(dialog: IConfirmation | IInput | IPrompt<unknown>, kind: DialogKind): string[] {
347
348 // We put buttons in the order of "default" button first and "cancel"
418 return buttons;
419 }
420 > dialogs.ts
421 > protected getDialogType(type: Severity | DialogType | undefined): DialogType | undefined {
422 if (typeof type === 'string') {
423 return type;
430 return undefined;
431 }
432 > dialogs.ts
433 > protected getPromptResult<T>(prompt: IPrompt<T>, buttonIndex: number, checkboxChecked: boolean | undefined): IAsyncPromptResult<T> {
434 const promptButtons: IPromptBaseButton<T>[] = [...(prompt.buttons ?? [])];
435 if (prompt.cancelButton && typeof prompt.cancelButton !== 'string' && typeof prompt.cancelButton !== 'boolean') {
444 return { result, checkboxChecked };
445 }
446 > dialogs.ts
447 > abstract confirm(confirmation: IConfirmation): Promise<IConfirmationResult>;
448 > abstract input(input: IInput): Promise<IInputResult>;
449 > abstract prompt<T>(prompt: IPrompt<T>): Promise<IAsyncPromptResult<T>>;
450 > abstract about(title: string, details: string, detailsToCopy: string): Promise<void>;
451 > }
452 >
453 > /**
454 > * A service to bring up modal dialogs.
455 > *
456 > * Note: use the `INotificationService.prompt()` method for a non-modal way to ask
457 > * the user for input.
458 > */
459 > export interface IDialogService {
460 >
461 > readonly _serviceBrand: undefined;
462 >
463 > /**
464 > * An event that fires when a dialog is about to show.
465 > */
466 > readonly onWillShowDialog: Event<void>;
467 >
468 > /**
469 > * An event that fires when a dialog did show (closed).
470 > */
471 > readonly onDidShowDialog: Event<void>;
472 >
473 > /**
474 > * Ask the user for confirmation with a modal dialog.
475 > */
476 > confirm(confirmation: IConfirmation): Promise<IConfirmationResult>;
477 >
478 > /**
479 > * Prompt the user with a modal dialog. Provides a bit
480 > * more control over the dialog compared to the simpler
481 > * `confirm` method. Specifically, allows to show more
482 > * than 2 buttons and makes it easier to just show a
483 > * message to the user.
484 > *
485 > * @returns a promise that resolves to the `T` result
486 > * from the provided `IPromptButton<T>` or `undefined`.
487 > */
488 > prompt<T>(prompt: IPromptWithCustomCancel<T>): Promise<IPromptResultWithCancel<T>>;
489 > prompt<T>(prompt: IPromptWithDefaultCancel<T>): Promise<IPromptResult<T>>;
490 > prompt<T>(prompt: IPrompt<T>): Promise<IPromptResult<T>>;
491 >
492 > /**
493 > * Present a modal dialog to the user asking for input.
494 > */
495 > input(input: IInput): Promise<IInputResult>;
496 >
497 > /**
498 > * Show a modal info dialog.
499 > */
500 > info(message: string, detail?: string): Promise<void>;
501 >
502 > /**
503 > * Show a modal warning dialog.
504 > */
505 > warn(message: string, detail?: string): Promise<void>;
506 >
507 > /**
508 > * Show a modal error dialog.
509 > */
510 > error(message: string, detail?: string): Promise<void>;
511 >
512 > /**
513 > * Present the about dialog to the user.
514 > */
515 > about(): Promise<void>;
516 > }
517 >
518 > export const IFileDialogService = createDecorator<IFileDialogService>('fileDialogService');
519 >
520 > /**
521 > * A service to bring up file dialogs.
522 > */
523 > export interface IFileDialogService {
524 >
525 > readonly _serviceBrand: undefined;
526 >
527 > /**
528 > * The default path for a new file based on previously used files.
529 > * @param schemeFilter The scheme of the file path. If no filter given, the scheme of the current window is used.
530 > * Falls back to user home in the absence of enough information to find a better URI.
531 > */
532 > defaultFilePath(schemeFilter?: string): Promise<URI>;
533 >
534 > /**
535 > * The default path for a new folder based on previously used folders.
536 > * @param schemeFilter The scheme of the folder path. If no filter given, the scheme of the current window is used.
537 > * Falls back to user home in the absence of enough information to find a better URI.
538 > */
539 > defaultFolderPath(schemeFilter?: string): Promise<URI>;
540 >
541 > /**
542 > * The default path for a new workspace based on previously used workspaces.
543 > * @param schemeFilter The scheme of the workspace path. If no filter given, the scheme of the current window is used.
544 > * Falls back to user home in the absence of enough information to find a better URI.
545 > */
546 > defaultWorkspacePath(schemeFilter?: string): Promise<URI>;
547 >
548 > /**
549 > * Shows a file-folder selection dialog and opens the selected entry.
550 > */
551 > pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise<void>;
552 >
553 > /**
554 > * Shows a file selection dialog and opens the selected entry.
555 > */
556 > pickFileAndOpen(options: IPickAndOpenOptions): Promise<void>;
557 >
558 > /**
559 > * Shows a folder selection dialog and opens the selected entry.
560 > */
561 > pickFolderAndOpen(options: IPickAndOpenOptions): Promise<void>;
562 >
563 > /**
564 > * Shows a workspace selection dialog and opens the selected entry.
565 > */
566 > pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise<void>;
567 >
568 > /**
569 > * Shows a save file dialog and save the file at the chosen file URI.
570 > */
571 > pickFileToSave(defaultUri: URI, availableFileSystems?: string[]): Promise<URI | undefined>;
572 >
573 > /**
574 > * The preferred folder path to open the dialog at.
575 > * @param schemeFilter The scheme of the file path. If no filter given, the scheme of the current window is used.
576 > * Falls back to user home in the absence of a setting.
577 > */
578 > preferredHome(schemeFilter?: string): Promise<URI>;
579 >
580 > /**
581 > * Shows a save file dialog and returns the chosen file URI.
582 > */
583 > showSaveDialog(options: ISaveDialogOptions): Promise<URI | undefined>;
584 >
585 > /**
586 > * Shows a confirm dialog for saving 1-N files.
587 > */
588 > showSaveConfirm(fileNamesOrResources: (string | URI)[]): Promise<ConfirmResult>;
589 >
590 > /**
591 > * Shows a open file dialog and returns the chosen file URI.
592 > */
593 > showOpenDialog(options: IOpenDialogOptions): Promise<URI[] | undefined>;
594 > }
595 >
596 > export const enum ConfirmResult {
597 > SAVE,
598 > DONT_SAVE,
599 > CANCEL
600 > }
601 >
602 > const MAX_CONFIRM_FILES = 10;
603 > export function getFileNamesMessage(fileNamesOrResources: readonly (string | URI)[]): string {
604 const message: string[] = [];
605 message.push(...fileNamesOrResources.slice(0, MAX_CONFIRM_FILES).map(fileNameOrResource => typeof fileNameOrResource === 'string' ? fileNameOrResource : basename(fileNameOrResource)));
616 return message.join('\n');
617 }
618 > dialogs.ts
619 > export interface INativeOpenDialogOptions {
620 > readonly forceNewWindow?: boolean;
621 >
622 > readonly defaultPath?: string;
623 >
624 > readonly telemetryEventName?: string;
625 > readonly telemetryExtraData?: ITelemetryData;
626 > }
src/vs/platform/notification/common/notification.ts 469 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- notification.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 { IAction } from '../../../base/common/actions.js';
8 > import { Event } from '../../../base/common/event.js';
9 > import BaseSeverity from '../../../base/common/severity.js';
10 > import { createDecorator } from '../../instantiation/common/instantiation.js';
11 >
12 > export import Severity = BaseSeverity;
13 >
14 > export const INotificationService = createDecorator<INotificationService>('notificationService');
15 >
16 > export type NotificationMessage = string | Error;
17 >
18 > export enum NotificationPriority {
19 >
20 > /**
21 > * Default priority: notification will be visible unless do not disturb mode is enabled.
22 > */
23 > DEFAULT,
24 >
25 > /**
26 > * Optional priority: notification might only be visible from the notifications center.
27 > */
28 > OPTIONAL,
29 >
30 > /**
31 > * Silent priority: notification will only be visible from the notifications center.
32 > */
33 > SILENT,
34 >
35 > /**
36 > * Urgent priority: notification will be visible even when do not disturb mode is enabled.
37 > */
38 > URGENT
39 > }
40 >
41 > export interface INotificationProperties {
42 >
43 > /**
44 > * Sticky notifications are not automatically removed after a certain timeout.
45 > *
46 > * Currently, only 2 kinds of notifications are sticky:
47 > * - Error notifications with primary actions
48 > * - Notifications that show progress
49 > */
50 > readonly sticky?: boolean;
51 >
52 > /**
53 > * Allows to override the priority of the notification based on needs.
54 > */
55 > readonly priority?: NotificationPriority;
56 >
57 > /**
58 > * Adds an action to never show the notification again. The choice will be persisted
59 > * such as future requests will not cause the notification to show again.
60 > */
61 > readonly neverShowAgain?: INeverShowAgainOptions;
62 > }
63 >
64 > export enum NeverShowAgainScope {
65 >
66 > /**
67 > * Will never show this notification on the current workspace again.
68 > */
69 > WORKSPACE,
70 >
71 > /**
72 > * Will never show this notification on any workspace of the same
73 > * profile again.
74 > */
75 > PROFILE,
76 >
77 > /**
78 > * Will never show this notification on any workspace across all
79 > * profiles again.
80 > */
81 > APPLICATION
82 > }
83 >
84 > export interface INeverShowAgainOptions {
85 >
86 > /**
87 > * The id is used to persist the selection of not showing the notification again.
88 > */
89 > readonly id: string;
90 >
91 > /**
92 > * By default the action will show up as primary action. Setting this to true will
93 > * make it a secondary action instead.
94 > */
95 > readonly isSecondary?: boolean;
96 >
97 > /**
98 > * Whether to persist the choice in the current workspace or for all workspaces. By
99 > * default it will be persisted for all workspaces across all profiles
100 > * (= `NeverShowAgainScope.APPLICATION`).
101 > */
102 > readonly scope?: NeverShowAgainScope;
103 > }
104 >
105 > export interface INotificationSource {
106 >
107 > /**
108 > * The id of the source.
109 > */
110 > readonly id: string;
111 >
112 > /**
113 > * The label of the source.
114 > */
115 > readonly label: string;
116 > }
117 >
118 > export function isNotificationSource(thing: unknown): thing is INotificationSource {
119 if (thing) {
120 const candidate = thing as INotificationSource;
125 return false;
126 }
128 > export interface INotification extends INotificationProperties {
129 >
130 > /**
131 > * The id of the notification. If provided, will be used to compare
132 > * notifications with others to decide whether a notification is
133 > * duplicate or not.
134 > */
135 > readonly id?: string;
136 >
137 > /**
138 > * The severity of the notification. Either `Info`, `Warning` or `Error`.
139 > */
140 > readonly severity: Severity;
141 >
142 > /**
143 > * The message of the notification. This can either be a `string` or `Error`. Messages
144 > * can optionally include links in the format: `[text](link)`
145 > */
146 > readonly message: NotificationMessage;
147 >
148 > /**
149 > * The source of the notification appears as additional information.
150 > */
151 > readonly source?: string | INotificationSource;
152 >
153 > /**
154 > * Actions to show as part of the notification. Primary actions show up as
155 > * buttons as part of the message and will close the notification once clicked.
156 > *
157 > * Secondary actions are meant to provide additional configuration or context
158 > * for the notification and will show up less prominent. A notification does not
159 > * close automatically when invoking a secondary action.
160 > *
161 > * **Note:** If your intent is to show a message with actions to the user, consider
162 > * the `INotificationService.prompt()` method instead which are optimized for
163 > * this usecase and much easier to use!
164 > */
165 > actions?: INotificationActions;
166 >
167 > /**
168 > * The initial set of progress properties for the notification. To update progress
169 > * later on, access the `INotificationHandle.progress` property.
170 > */
171 > readonly progress?: INotificationProgressProperties;
172 > }
173 >
174 > export interface INotificationActions {
175 >
176 > /**
177 > * Primary actions show up as buttons as part of the message and will close
178 > * the notification once clicked.
179 > *
180 > * Pass `ActionWithMenuAction` for an action that has additional menu actions.
181 > */
182 > readonly primary?: readonly IAction[];
183 >
184 > /**
185 > * Secondary actions are meant to provide additional configuration or context
186 > * for the notification and will show up less prominent. A notification does not
187 > * close automatically when invoking a secondary action.
188 > */
189 > readonly secondary?: readonly IAction[];
190 > }
191 >
192 > export interface INotificationProgressProperties {
193 >
194 > /**
195 > * Causes the progress bar to spin infinitley.
196 > */
197 > readonly infinite?: boolean;
198 >
199 > /**
200 > * Indicate the total amount of work.
201 > */
202 > readonly total?: number;
203 >
204 > /**
205 > * Indicate that a specific chunk of work is done.
206 > */
207 > readonly worked?: number;
208 > }
209 >
210 > export interface INotificationProgress {
211 >
212 > /**
213 > * Causes the progress bar to spin infinitley.
214 > */
215 > infinite(): void;
216 >
217 > /**
218 > * Indicate the total amount of work.
219 > */
220 > total(value: number): void;
221 >
222 > /**
223 > * Indicate that a specific chunk of work is done.
224 > */
225 > worked(value: number): void;
226 >
227 > /**
228 > * Indicate that the long running operation is done.
229 > */
230 > done(): void;
231 > }
232 >
233 > export interface INotificationHandle {
234 >
235 > /**
236 > * Will be fired once the notification is closed.
237 > */
238 > readonly onDidClose: Event<void>;
239 >
240 > /**
241 > * Will be fired whenever the visibility of the notification changes.
242 > * A notification can either be visible as toast or inside the notification
243 > * center if it is visible.
244 > */
245 > readonly onDidChangeVisibility: Event<boolean>;
246 >
247 > /**
248 > * Allows to indicate progress on the notification even after the
249 > * notification is already visible.
250 > */
251 > readonly progress: INotificationProgress;
252 >
253 > /**
254 > * Allows to update the severity of the notification.
255 > */
256 > updateSeverity(severity: Severity): void;
257 >
258 > /**
259 > * Allows to update the message of the notification even after the
260 > * notification is already visible.
261 > */
262 > updateMessage(message: NotificationMessage): void;
263 >
264 > /**
265 > * Allows to update the actions of the notification even after the
266 > * notification is already visible.
267 > */
268 > updateActions(actions?: INotificationActions): void;
269 >
270 > /**
271 > * Hide the notification and remove it from the notification center.
272 > */
273 > close(): void;
274 > }
275 >
276 > export interface IStatusHandle {
277 >
278 > /**
279 > * Hide the status message.
280 > */
281 > close(): void;
282 > }
283 >
284 > interface IBasePromptChoice {
285 >
286 > /**
287 > * Label to show for the choice to the user.
288 > */
289 > readonly label: string;
290 >
291 > /**
292 > * Whether to keep the notification open after the choice was selected
293 > * by the user. By default, will close the notification upon click.
294 > */
295 > readonly keepOpen?: boolean;
296 >
297 > /**
298 > * Triggered when the user selects the choice.
299 > */
300 > run: () => void;
301 > }
302 >
303 > export interface IPromptChoice extends IBasePromptChoice {
304 >
305 > /**
306 > * Primary choices show up as buttons in the notification below the message.
307 > * Secondary choices show up under the gear icon in the header of the notification.
308 > */
309 > readonly isSecondary?: boolean;
310 > }
311 >
312 > export interface IPromptChoiceWithMenu extends IPromptChoice {
313 >
314 > /**
315 > * Additional choices those will be shown in the dropdown menu for this choice.
316 > */
317 > readonly menu: IBasePromptChoice[];
318 >
319 > /**
320 > * Menu is not supported on secondary choices
321 > */
322 > readonly isSecondary: false | undefined;
323 > }
324 >
325 > export interface IPromptOptions extends INotificationProperties {
326 >
327 > /**
328 > * Will be called if the user closed the notification without picking
329 > * any of the provided choices.
330 > */
331 > onCancel?: () => void;
332 > }
333 >
334 > export interface IStatusMessageOptions {
335 >
336 > /**
337 > * An optional timeout after which the status message should show. By default
338 > * the status message will show immediately.
339 > */
340 > readonly showAfter?: number;
341 >
342 > /**
343 > * An optional timeout after which the status message is to be hidden. By default
344 > * the status message will not hide until another status message is displayed.
345 > */
346 > readonly hideAfter?: number;
347 > }
348 >
349 > export enum NotificationsFilter {
350 >
351 > /**
352 > * No filter is enabled.
353 > */
354 > OFF,
355 >
356 > /**
357 > * All notifications are silent except error notifications.
358 > */
359 > ERROR
360 > }
361 >
362 > export interface INotificationSourceFilter extends INotificationSource {
363 > readonly filter: NotificationsFilter;
364 > }
365 >
366 > /**
367 > * A service to bring up notifications and non-modal prompts.
368 > *
369 > * Note: use the `IDialogService` for a modal way to ask the user for input.
370 > */
371 > export interface INotificationService {
372 >
373 > readonly _serviceBrand: undefined;
374 >
375 > /**
376 > * Emitted when the notifications filter changed.
377 > */
378 > readonly onDidChangeFilter: Event<void>;
379 >
380 > /**
381 > * Sets a notification filter either for all notifications
382 > * or for a specific source.
383 > */
384 > setFilter(filter: NotificationsFilter | INotificationSourceFilter): void;
385 >
386 > /**
387 > * Gets the notification filter either for all notifications
388 > * or for a specific source.
389 > */
390 > getFilter(source?: INotificationSource): NotificationsFilter;
391 >
392 > /**
393 > * Returns all filters with their sources.
394 > */
395 > getFilters(): INotificationSourceFilter[];
396 >
397 > /**
398 > * Removes a filter for a specific source.
399 > */
400 > removeFilter(sourceId: string): void;
401 >
402 > /**
403 > * Show the provided notification to the user. The returned `INotificationHandle`
404 > * can be used to control the notification afterwards.
405 > *
406 > * **Note:** If your intent is to show a message with actions to the user, consider
407 > * the `INotificationService.prompt()` method instead which are optimized for
408 > * this usecase and much easier to use!
409 > *
410 > * @returns a handle on the notification to e.g. hide it or update message, buttons, etc.
411 > */
412 > notify(notification: INotification): INotificationHandle;
413 >
414 > /**
415 > * A convenient way of reporting infos. Use the `INotificationService.notify`
416 > * method if you need more control over the notification.
417 > */
418 > info(message: NotificationMessage | NotificationMessage[]): void;
419 >
420 > /**
421 > * A convenient way of reporting warnings. Use the `INotificationService.notify`
422 > * method if you need more control over the notification.
423 > */
424 > warn(message: NotificationMessage | NotificationMessage[]): void;
425 >
426 > /**
427 > * A convenient way of reporting errors. Use the `INotificationService.notify`
428 > * method if you need more control over the notification.
429 > */
430 > error(message: NotificationMessage | NotificationMessage[]): void;
431 >
432 > /**
433 > * Shows a prompt in the notification area with the provided choices. The prompt
434 > * is non-modal. If you want to show a modal dialog instead, use `IDialogService`.
435 > *
436 > * @param severity the severity of the notification. Either `Info`, `Warning` or `Error`.
437 > * @param message the message to show as status.
438 > * @param choices options to be chosen from.
439 > * @param options provides some optional configuration options.
440 > *
441 > * @returns a handle on the notification to e.g. hide it or update message, buttons, etc.
442 > */
443 > prompt(severity: Severity, message: string, choices: (IPromptChoice | IPromptChoiceWithMenu)[], options?: IPromptOptions): INotificationHandle;
444 >
445 > /**
446 > * Shows a status message in the status area with the provided text.
447 > *
448 > * @param message the message to show as status
449 > * @param options provides some optional configuration options
450 > *
451 > * @returns a handle to hide the status message
452 > */
453 > status(message: NotificationMessage, options?: IStatusMessageOptions): IStatusHandle;
454 > }
455 >
456 > export class NoOpNotification implements INotificationHandle {
458 > readonly progress = new NoOpProgress();
459 >
460 > readonly onDidClose = Event.None;
461 > readonly onDidChangeVisibility = Event.None;
463 > updateSeverity(severity: Severity): void { }
464 > updateMessage(message: NotificationMessage): void { }
465 > updateActions(actions?: INotificationActions): void { }
466 >
467 > close(): void { }
468 > }
469 >
470 > export class NoOpProgress implements INotificationProgress {
471 > infinite(): void { }
472 > done(): void { }
473 > total(value: number): void { }
474 > worked(value: number): void { }
475 > }
476 >
477 > export function withSeverityPrefix(label: string, severity: Severity): string {
478
479 // Add severity prefix to match WCAG 4.1.3 Status
src/vs/platform/theme/common/colors/editorColors.ts 457 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editorColors.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 > // Import the effects we need
9 > import { Color, RGBA } from '../../../../base/common/color.js';
10 > import { registerColor, transparent, lessProminent, darken, lighten } from '../colorUtils.js';
11 >
12 > // Import the colors we need
13 > import { foreground, contrastBorder, activeContrastBorder } from './baseColors.js';
14 > import { scrollbarShadow, badgeBackground } from './miscColors.js';
15 >
16 >
17 > // ----- editor
18 >
19 > export const editorBackground = registerColor('editor.background',
20 > { light: '#ffffff', dark: '#1E1E1E', hcDark: Color.black, hcLight: Color.white },
21 > nls.localize('editorBackground', "Editor background color."));
22 >
23 > export const editorForeground = registerColor('editor.foreground',
24 > { light: '#333333', dark: '#BBBBBB', hcDark: Color.white, hcLight: foreground },
25 > nls.localize('editorForeground', "Editor default foreground color."));
26 >
27 >
28 > export const editorStickyScrollBackground = registerColor('editorStickyScroll.background',
29 > editorBackground,
30 > nls.localize('editorStickyScrollBackground', "Background color of sticky scroll in the editor"));
31 >
32 > export const editorStickyScrollGutterBackground = registerColor('editorStickyScrollGutter.background',
33 > editorBackground,
34 > nls.localize('editorStickyScrollGutterBackground', "Background color of the gutter part of sticky scroll in the editor"));
35 >
36 > export const editorStickyScrollHoverBackground = registerColor('editorStickyScrollHover.background',
37 > { dark: '#2A2D2E', light: '#F0F0F0', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) },
38 > nls.localize('editorStickyScrollHoverBackground', "Background color of sticky scroll on hover in the editor"));
39 >
40 > export const editorStickyScrollBorder = registerColor('editorStickyScroll.border',
41 > { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },
42 > nls.localize('editorStickyScrollBorder', "Border color of sticky scroll in the editor"));
43 >
44 > export const editorStickyScrollShadow = registerColor('editorStickyScroll.shadow',
45 > scrollbarShadow,
46 > nls.localize('editorStickyScrollShadow', " Shadow color of sticky scroll in the editor"));
47 >
48 >
49 > export const editorWidgetBackground = registerColor('editorWidget.background',
50 > { dark: '#252526', light: '#F3F3F3', hcDark: '#0C141F', hcLight: Color.white },
51 > nls.localize('editorWidgetBackground', 'Background color of editor widgets, such as find/replace.'));
52 >
53 > export const editorWidgetForeground = registerColor('editorWidget.foreground',
54 > foreground,
55 > nls.localize('editorWidgetForeground', 'Foreground color of editor widgets, such as find/replace.'));
56 >
57 > export const editorWidgetBorder = registerColor('editorWidget.border',
58 > { dark: transparent(editorWidgetForeground, 0.2), light: transparent(editorWidgetForeground, 0.2), hcDark: contrastBorder, hcLight: contrastBorder },
59 > nls.localize('editorWidgetBorder', 'Border color of editor widgets. The color is only used if the widget chooses to have a border and if the color is not overridden by a widget.'));
60 >
61 > export const editorWidgetResizeBorder = registerColor('editorWidget.resizeBorder',
62 > null,
63 > nls.localize('editorWidgetResizeBorder', "Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget."));
64 >
65 >
66 > export const editorErrorBackground = registerColor('editorError.background',
67 > null,
68 > nls.localize('editorError.background', 'Background color of error text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true);
69 >
70 > export const editorErrorForeground = registerColor('editorError.foreground',
71 > { dark: '#F14C4C', light: '#E51400', hcDark: '#F48771', hcLight: '#B5200D' },
72 > nls.localize('editorError.foreground', 'Foreground color of error squigglies in the editor.'));
73 >
74 > export const editorErrorBorder = registerColor('editorError.border',
75 > { dark: null, light: null, hcDark: Color.fromHex('#E47777').transparent(0.8), hcLight: '#B5200D' },
76 > nls.localize('errorBorder', 'If set, color of double underlines for errors in the editor.'));
77 >
78 >
79 > export const editorWarningBackground = registerColor('editorWarning.background',
80 > null,
81 > nls.localize('editorWarning.background', 'Background color of warning text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true);
82 >
83 > export const editorWarningForeground = registerColor('editorWarning.foreground',
84 > { dark: '#CCA700', light: '#BF8803', hcDark: '#FFD370', hcLight: '#895503' },
85 > nls.localize('editorWarning.foreground', 'Foreground color of warning squigglies in the editor.'));
86 >
87 > export const editorWarningBorder = registerColor('editorWarning.border',
88 > { dark: null, light: null, hcDark: Color.fromHex('#FFCC00').transparent(0.8), hcLight: Color.fromHex('#FFCC00').transparent(0.8) },
89 > nls.localize('warningBorder', 'If set, color of double underlines for warnings in the editor.'));
90 >
91 >
92 > export const editorInfoBackground = registerColor('editorInfo.background',
93 > null,
94 > nls.localize('editorInfo.background', 'Background color of info text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true);
95 >
96 > export const editorInfoForeground = registerColor('editorInfo.foreground',
97 > { dark: '#59a4f9', light: '#0063d3', hcDark: '#59a4f9', hcLight: '#0063d3' },
98 > nls.localize('editorInfo.foreground', 'Foreground color of info squigglies in the editor.'));
99 >
100 > export const editorInfoBorder = registerColor('editorInfo.border',
101 > { dark: null, light: null, hcDark: Color.fromHex('#59a4f9').transparent(0.8), hcLight: '#292929' },
102 > nls.localize('infoBorder', 'If set, color of double underlines for infos in the editor.'));
103 >
104 >
105 > export const editorHintForeground = registerColor('editorHint.foreground',
106 > { dark: Color.fromHex('#eeeeee').transparent(0.7), light: '#6c6c6c', hcDark: null, hcLight: null },
107 > nls.localize('editorHint.foreground', 'Foreground color of hint squigglies in the editor.'));
108 >
109 > export const editorHintBorder = registerColor('editorHint.border',
110 > { dark: null, light: null, hcDark: Color.fromHex('#eeeeee').transparent(0.8), hcLight: '#292929' },
111 > nls.localize('hintBorder', 'If set, color of double underlines for hints in the editor.'));
112 >
113 >
114 > export const editorActiveLinkForeground = registerColor('editorLink.activeForeground',
115 > { dark: '#4E94CE', light: Color.blue, hcDark: Color.cyan, hcLight: '#292929' },
116 > nls.localize('activeLinkForeground', 'Color of active links.'));
117 >
118 >
119 > // ----- editor selection
120 >
121 > export const editorSelectionBackground = registerColor('editor.selectionBackground',
122 > { light: '#ADD6FF', dark: '#264F78', hcDark: '#f3f518', hcLight: '#0F4A85' },
123 > nls.localize('editorSelectionBackground', "Color of the editor selection."));
124 >
125 > export const editorSelectionForeground = registerColor('editor.selectionForeground',
126 > { light: null, dark: null, hcDark: '#000000', hcLight: Color.white },
127 > nls.localize('editorSelectionForeground', "Color of the selected text for high contrast."));
128 >
129 > export const editorInactiveSelection = registerColor('editor.inactiveSelectionBackground',
130 > { light: transparent(editorSelectionBackground, 0.5), dark: transparent(editorSelectionBackground, 0.5), hcDark: transparent(editorSelectionBackground, 0.7), hcLight: transparent(editorSelectionBackground, 0.5) },
131 > nls.localize('editorInactiveSelection', "Color of the selection in an inactive editor. The color must not be opaque so as not to hide underlying decorations."), true);
132 >
133 > export const editorSelectionHighlight = registerColor('editor.selectionHighlightBackground',
134 > { light: lessProminent(editorSelectionBackground, editorBackground, 0.3, 0.6), dark: lessProminent(editorSelectionBackground, editorBackground, 0.3, 0.6), hcDark: null, hcLight: null },
135 > nls.localize('editorSelectionHighlight', 'Color for regions with the same content as the selection. The color must not be opaque so as not to hide underlying decorations.'), true);
136 >
137 > export const editorSelectionHighlightBorder = registerColor('editor.selectionHighlightBorder',
138 > { light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },
139 > nls.localize('editorSelectionHighlightBorder', "Border color for regions with the same content as the selection."));
140 >
141 > export const editorCompositionBorder = registerColor('editor.compositionBorder',
142 > { light: '#000000', dark: '#ffffff', hcLight: '#000000', hcDark: '#ffffff' },
143 > nls.localize('editorCompositionBorder', "The border color for an IME composition."));
144 >
145 >
146 > // ----- editor find
147 >
148 > export const editorFindMatch = registerColor('editor.findMatchBackground',
149 > { light: '#A8AC94', dark: '#515C6A', hcDark: null, hcLight: null },
150 > nls.localize('editorFindMatch', "Color of the current search match."));
151 >
152 > export const editorFindMatchForeground = registerColor('editor.findMatchForeground',
153 > null,
154 > nls.localize('editorFindMatchForeground', "Text color of the current search match."));
155 >
156 > export const editorFindMatchHighlight = registerColor('editor.findMatchHighlightBackground',
157 > { light: '#EA5C0055', dark: '#EA5C0055', hcDark: null, hcLight: null },
158 > nls.localize('findMatchHighlight', "Color of the other search matches. The color must not be opaque so as not to hide underlying decorations."), true);
159 >
160 > export const editorFindMatchHighlightForeground = registerColor('editor.findMatchHighlightForeground',
161 > null,
162 > nls.localize('findMatchHighlightForeground', "Foreground color of the other search matches."), true);
163 >
164 > export const editorFindRangeHighlight = registerColor('editor.findRangeHighlightBackground',
165 > { dark: '#3a3d4166', light: '#b4b4b44d', hcDark: null, hcLight: null },
166 > nls.localize('findRangeHighlight', "Color of the range limiting the search. The color must not be opaque so as not to hide underlying decorations."), true);
167 >
168 > export const editorFindMatchBorder = registerColor('editor.findMatchBorder',
169 > { light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },
170 > nls.localize('editorFindMatchBorder', "Border color of the current search match."));
171 >
172 > export const editorFindMatchHighlightBorder = registerColor('editor.findMatchHighlightBorder',
173 > { light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },
174 > nls.localize('findMatchHighlightBorder', "Border color of the other search matches."));
175 >
176 > export const editorFindRangeHighlightBorder = registerColor('editor.findRangeHighlightBorder',
177 > { dark: null, light: null, hcDark: transparent(activeContrastBorder, 0.4), hcLight: transparent(activeContrastBorder, 0.4) },
178 > nls.localize('findRangeHighlightBorder', "Border color of the range limiting the search. The color must not be opaque so as not to hide underlying decorations."), true);
179 >
180 >
181 > // ----- editor hover
182 >
183 > export const editorHoverHighlight = registerColor('editor.hoverHighlightBackground',
184 > { light: '#ADD6FF26', dark: '#264f7840', hcDark: '#ADD6FF26', hcLight: null },
185 > nls.localize('hoverHighlight', 'Highlight below the word for which a hover is shown. The color must not be opaque so as not to hide underlying decorations.'), true);
186 >
187 > export const editorHoverBackground = registerColor('editorHoverWidget.background',
188 > editorWidgetBackground,
189 > nls.localize('hoverBackground', 'Background color of the editor hover.'));
190 >
191 > export const editorHoverForeground = registerColor('editorHoverWidget.foreground',
192 > editorWidgetForeground,
193 > nls.localize('hoverForeground', 'Foreground color of the editor hover.'));
194 >
195 > export const editorHoverBorder = registerColor('editorHoverWidget.border',
196 > editorWidgetBorder,
197 > nls.localize('hoverBorder', 'Border color of the editor hover.'));
198 >
199 > export const editorHoverStatusBarBackground = registerColor('editorHoverWidget.statusBarBackground',
200 > { dark: lighten(editorHoverBackground, 0.2), light: darken(editorHoverBackground, 0.05), hcDark: editorWidgetBackground, hcLight: editorWidgetBackground },
201 > nls.localize('statusBarBackground', "Background color of the editor hover status bar."));
202 >
203 >
204 > // ----- editor inlay hint
205 >
206 > export const editorInlayHintForeground = registerColor('editorInlayHint.foreground',
207 > { dark: '#969696', light: '#969696', hcDark: Color.white, hcLight: Color.black },
208 > nls.localize('editorInlayHintForeground', 'Foreground color of inline hints'));
209 >
210 > export const editorInlayHintBackground = registerColor('editorInlayHint.background',
211 > { dark: transparent(badgeBackground, .10), light: transparent(badgeBackground, .10), hcDark: transparent(Color.white, .10), hcLight: transparent(badgeBackground, .10) },
212 > nls.localize('editorInlayHintBackground', 'Background color of inline hints'));
213 >
214 > export const editorInlayHintTypeForeground = registerColor('editorInlayHint.typeForeground',
215 > editorInlayHintForeground,
216 > nls.localize('editorInlayHintForegroundTypes', 'Foreground color of inline hints for types'));
217 >
218 > export const editorInlayHintTypeBackground = registerColor('editorInlayHint.typeBackground',
219 > editorInlayHintBackground,
220 > nls.localize('editorInlayHintBackgroundTypes', 'Background color of inline hints for types'));
221 >
222 > export const editorInlayHintParameterForeground = registerColor('editorInlayHint.parameterForeground',
223 > editorInlayHintForeground,
224 > nls.localize('editorInlayHintForegroundParameter', 'Foreground color of inline hints for parameters'));
225 >
226 > export const editorInlayHintParameterBackground = registerColor('editorInlayHint.parameterBackground',
227 > editorInlayHintBackground,
228 > nls.localize('editorInlayHintBackgroundParameter', 'Background color of inline hints for parameters'));
229 >
230 >
231 > // ----- editor lightbulb
232 >
233 > export const editorLightBulbForeground = registerColor('editorLightBulb.foreground',
234 > { dark: '#FFCC00', light: '#DDB100', hcDark: '#FFCC00', hcLight: '#007ACC' },
235 > nls.localize('editorLightBulbForeground', "The color used for the lightbulb actions icon."));
236 >
237 > export const editorLightBulbAutoFixForeground = registerColor('editorLightBulbAutoFix.foreground',
238 > { dark: '#75BEFF', light: '#007ACC', hcDark: '#75BEFF', hcLight: '#007ACC' },
239 > nls.localize('editorLightBulbAutoFixForeground', "The color used for the lightbulb auto fix actions icon."));
240 >
241 > export const editorLightBulbAiForeground = registerColor('editorLightBulbAi.foreground',
242 > editorLightBulbForeground,
243 > nls.localize('editorLightBulbAiForeground', "The color used for the lightbulb AI icon."));
244 >
245 >
246 > // ----- editor snippet
247 >
248 > export const snippetTabstopHighlightBackground = registerColor('editor.snippetTabstopHighlightBackground',
249 > { dark: new Color(new RGBA(124, 124, 124, 0.3)), light: new Color(new RGBA(10, 50, 100, 0.2)), hcDark: new Color(new RGBA(124, 124, 124, 0.3)), hcLight: new Color(new RGBA(10, 50, 100, 0.2)) },
250 > nls.localize('snippetTabstopHighlightBackground', "Highlight background color of a snippet tabstop."));
251 >
252 > export const snippetTabstopHighlightBorder = registerColor('editor.snippetTabstopHighlightBorder',
253 > null,
254 > nls.localize('snippetTabstopHighlightBorder', "Highlight border color of a snippet tabstop."));
255 >
256 > export const snippetFinalTabstopHighlightBackground = registerColor('editor.snippetFinalTabstopHighlightBackground',
257 > null,
258 > nls.localize('snippetFinalTabstopHighlightBackground', "Highlight background color of the final tabstop of a snippet."));
259 >
260 > export const snippetFinalTabstopHighlightBorder = registerColor('editor.snippetFinalTabstopHighlightBorder',
261 > { dark: '#525252', light: new Color(new RGBA(10, 50, 100, 0.5)), hcDark: '#525252', hcLight: '#292929' },
262 > nls.localize('snippetFinalTabstopHighlightBorder', "Highlight border color of the final tabstop of a snippet."));
263 >
264 >
265 > // ----- diff editor
266 >
267 > export const defaultInsertColor = new Color(new RGBA(155, 185, 85, .2));
268 > export const defaultRemoveColor = new Color(new RGBA(255, 0, 0, .2));
269 >
270 > export const diffInserted = registerColor('diffEditor.insertedTextBackground',
271 > { dark: '#9ccc2c33', light: '#9ccc2c40', hcDark: null, hcLight: null },
272 > nls.localize('diffEditorInserted', 'Background color for text that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true);
273 >
274 > export const diffRemoved = registerColor('diffEditor.removedTextBackground',
275 > { dark: '#ff000033', light: '#ff000033', hcDark: null, hcLight: null },
276 > nls.localize('diffEditorRemoved', 'Background color for text that got removed. The color must not be opaque so as not to hide underlying decorations.'), true);
277 >
278 >
279 > export const diffInsertedLine = registerColor('diffEditor.insertedLineBackground',
280 > { dark: defaultInsertColor, light: defaultInsertColor, hcDark: null, hcLight: null },
281 > nls.localize('diffEditorInsertedLines', 'Background color for lines that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true);
282 >
283 > export const diffRemovedLine = registerColor('diffEditor.removedLineBackground',
284 > { dark: defaultRemoveColor, light: defaultRemoveColor, hcDark: null, hcLight: null },
285 > nls.localize('diffEditorRemovedLines', 'Background color for lines that got removed. The color must not be opaque so as not to hide underlying decorations.'), true);
286 >
287 >
288 > export const diffInsertedLineGutter = registerColor('diffEditorGutter.insertedLineBackground',
289 > null,
290 > nls.localize('diffEditorInsertedLineGutter', 'Background color for the margin where lines got inserted.'));
291 >
292 > export const diffRemovedLineGutter = registerColor('diffEditorGutter.removedLineBackground',
293 > null,
294 > nls.localize('diffEditorRemovedLineGutter', 'Background color for the margin where lines got removed.'));
295 >
296 >
297 > export const diffOverviewRulerInserted = registerColor('diffEditorOverview.insertedForeground',
298 > null,
299 > nls.localize('diffEditorOverviewInserted', 'Diff overview ruler foreground for inserted content.'));
300 >
301 > export const diffOverviewRulerRemoved = registerColor('diffEditorOverview.removedForeground',
302 > null,
303 > nls.localize('diffEditorOverviewRemoved', 'Diff overview ruler foreground for removed content.'));
304 >
305 >
306 > export const diffInsertedOutline = registerColor('diffEditor.insertedTextBorder',
307 > { dark: null, light: null, hcDark: '#33ff2eff', hcLight: '#374E06' },
308 > nls.localize('diffEditorInsertedOutline', 'Outline color for the text that got inserted.'));
309 >
310 > export const diffRemovedOutline = registerColor('diffEditor.removedTextBorder',
311 > { dark: null, light: null, hcDark: '#FF008F', hcLight: '#AD0707' },
312 > nls.localize('diffEditorRemovedOutline', 'Outline color for text that got removed.'));
313 >
314 >
315 > export const diffBorder = registerColor('diffEditor.border',
316 > { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },
317 > nls.localize('diffEditorBorder', 'Border color between the two text editors.'));
318 >
319 > export const diffDiagonalFill = registerColor('diffEditor.diagonalFill',
320 > { dark: '#cccccc33', light: '#22222233', hcDark: null, hcLight: null },
321 > nls.localize('diffDiagonalFill', "Color of the diff editor's diagonal fill. The diagonal fill is used in side-by-side diff views."));
322 >
323 >
324 > export const diffUnchangedRegionBackground = registerColor('diffEditor.unchangedRegionBackground',
325 > 'sideBar.background',
326 > nls.localize('diffEditor.unchangedRegionBackground', "The background color of unchanged blocks in the diff editor."));
327 >
328 > export const diffUnchangedRegionForeground = registerColor('diffEditor.unchangedRegionForeground',
329 > 'foreground',
330 > nls.localize('diffEditor.unchangedRegionForeground', "The foreground color of unchanged blocks in the diff editor."));
331 >
332 > export const diffUnchangedTextBackground = registerColor('diffEditor.unchangedCodeBackground',
333 > { dark: '#74747429', light: '#b8b8b829', hcDark: null, hcLight: null },
334 > nls.localize('diffEditor.unchangedCodeBackground', "The background color of unchanged code in the diff editor."));
335 >
336 >
337 > // ----- widget
338 >
339 > export const widgetShadow = registerColor('widget.shadow',
340 > { dark: transparent(Color.black, .36), light: transparent(Color.black, .16), hcDark: null, hcLight: null },
341 > nls.localize('widgetShadow', 'Shadow color of widgets such as find/replace inside the editor.'));
342 >
343 > export const widgetBorder = registerColor('widget.border',
344 > { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },
345 > nls.localize('widgetBorder', 'Border color of widgets such as find/replace inside the editor.'));
346 >
347 >
348 > // ----- toolbar
349 >
350 > export const toolbarHoverBackground = registerColor('toolbar.hoverBackground',
351 > { dark: '#5a5d5e50', light: '#b8b8b850', hcDark: null, hcLight: null },
352 > nls.localize('toolbarHoverBackground', "Toolbar background when hovering over actions using the mouse"));
353 >
354 > export const toolbarHoverOutline = registerColor('toolbar.hoverOutline',
355 > { dark: null, light: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },
356 > nls.localize('toolbarHoverOutline', "Toolbar outline when hovering over actions using the mouse"));
357 >
358 > export const toolbarActiveBackground = registerColor('toolbar.activeBackground',
359 > { dark: lighten(toolbarHoverBackground, 0.1), light: darken(toolbarHoverBackground, 0.1), hcDark: null, hcLight: null },
360 > nls.localize('toolbarActiveBackground', "Toolbar background when holding the mouse over actions"));
361 >
362 >
363 > // ----- breadcumbs
364 >
365 > export const breadcrumbsForeground = registerColor('breadcrumb.foreground',
366 > transparent(foreground, 0.8),
367 > nls.localize('breadcrumbsFocusForeground', "Color of focused breadcrumb items."));
368 >
369 > export const breadcrumbsBackground = registerColor('breadcrumb.background',
370 > editorBackground,
371 > nls.localize('breadcrumbsBackground', "Background color of breadcrumb items."));
372 >
373 > export const breadcrumbsFocusForeground = registerColor('breadcrumb.focusForeground',
374 > { light: darken(foreground, 0.2), dark: lighten(foreground, 0.1), hcDark: lighten(foreground, 0.1), hcLight: lighten(foreground, 0.1) },
375 > nls.localize('breadcrumbsFocusForeground', "Color of focused breadcrumb items."));
376 >
377 > export const breadcrumbsActiveSelectionForeground = registerColor('breadcrumb.activeSelectionForeground',
378 > { light: darken(foreground, 0.2), dark: lighten(foreground, 0.1), hcDark: lighten(foreground, 0.1), hcLight: lighten(foreground, 0.1) },
379 > nls.localize('breadcrumbsSelectedForeground', "Color of selected breadcrumb items."));
380 >
381 > export const breadcrumbsPickerBackground = registerColor('breadcrumbPicker.background',
382 > editorWidgetBackground,
383 > nls.localize('breadcrumbsSelectedBackground', "Background color of breadcrumb item picker."));
384 >
385 >
386 > // ----- merge
387 >
388 > const headerTransparency = 0.5;
389 > const currentBaseColor = Color.fromHex('#40C8AE').transparent(headerTransparency);
390 > const incomingBaseColor = Color.fromHex('#40A6FF').transparent(headerTransparency);
391 > const commonBaseColor = Color.fromHex('#606060').transparent(0.4);
392 > const contentTransparency = 0.4;
393 > const rulerTransparency = 1;
394 >
395 > export const mergeCurrentHeaderBackground = registerColor('merge.currentHeaderBackground',
396 > { dark: currentBaseColor, light: currentBaseColor, hcDark: null, hcLight: null },
397 > nls.localize('mergeCurrentHeaderBackground', 'Current header background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);
398 >
399 > export const mergeCurrentContentBackground = registerColor('merge.currentContentBackground',
400 > transparent(mergeCurrentHeaderBackground, contentTransparency),
401 > nls.localize('mergeCurrentContentBackground', 'Current content background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);
402 >
403 > export const mergeIncomingHeaderBackground = registerColor('merge.incomingHeaderBackground',
404 > { dark: incomingBaseColor, light: incomingBaseColor, hcDark: null, hcLight: null },
405 > nls.localize('mergeIncomingHeaderBackground', 'Incoming header background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);
406 >
407 > export const mergeIncomingContentBackground = registerColor('merge.incomingContentBackground',
408 > transparent(mergeIncomingHeaderBackground, contentTransparency),
409 > nls.localize('mergeIncomingContentBackground', 'Incoming content background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);
410 >
411 > export const mergeCommonHeaderBackground = registerColor('merge.commonHeaderBackground',
412 > { dark: commonBaseColor, light: commonBaseColor, hcDark: null, hcLight: null },
413 > nls.localize('mergeCommonHeaderBackground', 'Common ancestor header background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);
414 >
415 > export const mergeCommonContentBackground = registerColor('merge.commonContentBackground',
416 > transparent(mergeCommonHeaderBackground, contentTransparency),
417 > nls.localize('mergeCommonContentBackground', 'Common ancestor content background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);
418 >
419 > export const mergeBorder = registerColor('merge.border',
420 > { dark: null, light: null, hcDark: '#C3DF6F', hcLight: '#007ACC' },
421 > nls.localize('mergeBorder', 'Border color on headers and the splitter in inline merge-conflicts.'));
422 >
423 >
424 > export const overviewRulerCurrentContentForeground = registerColor('editorOverviewRuler.currentContentForeground',
425 > { dark: transparent(mergeCurrentHeaderBackground, rulerTransparency), light: transparent(mergeCurrentHeaderBackground, rulerTransparency), hcDark: mergeBorder, hcLight: mergeBorder },
426 > nls.localize('overviewRulerCurrentContentForeground', 'Current overview ruler foreground for inline merge-conflicts.'));
427 >
428 > export const overviewRulerIncomingContentForeground = registerColor('editorOverviewRuler.incomingContentForeground',
429 > { dark: transparent(mergeIncomingHeaderBackground, rulerTransparency), light: transparent(mergeIncomingHeaderBackground, rulerTransparency), hcDark: mergeBorder, hcLight: mergeBorder },
430 > nls.localize('overviewRulerIncomingContentForeground', 'Incoming overview ruler foreground for inline merge-conflicts.'));
431 >
432 > export const overviewRulerCommonContentForeground = registerColor('editorOverviewRuler.commonContentForeground',
433 > { dark: transparent(mergeCommonHeaderBackground, rulerTransparency), light: transparent(mergeCommonHeaderBackground, rulerTransparency), hcDark: mergeBorder, hcLight: mergeBorder },
434 > nls.localize('overviewRulerCommonContentForeground', 'Common ancestor overview ruler foreground for inline merge-conflicts.'));
435 >
436 > export const overviewRulerFindMatchForeground = registerColor('editorOverviewRuler.findMatchForeground',
437 > { dark: '#d186167e', light: '#d186167e', hcDark: '#AB5A00', hcLight: '#AB5A00' },
438 > nls.localize('overviewRulerFindMatchForeground', 'Overview ruler marker color for find matches. The color must not be opaque so as not to hide underlying decorations.'), true);
439 >
440 > export const overviewRulerSelectionHighlightForeground = registerColor('editorOverviewRuler.selectionHighlightForeground',
441 > '#A0A0A0CC',
442 > nls.localize('overviewRulerSelectionHighlightForeground', 'Overview ruler marker color for selection highlights. The color must not be opaque so as not to hide underlying decorations.'), true);
443 >
444 >
445 > // ----- problems
446 >
447 > export const problemsErrorIconForeground = registerColor('problemsErrorIcon.foreground',
448 > editorErrorForeground,
449 > nls.localize('problemsErrorIconForeground', "The color used for the problems error icon."));
450 >
451 > export const problemsWarningIconForeground = registerColor('problemsWarningIcon.foreground',
452 > editorWarningForeground,
453 > nls.localize('problemsWarningIconForeground', "The color used for the problems warning icon."));
454 >
455 > export const problemsInfoIconForeground = registerColor('problemsInfoIcon.foreground',
456 > editorInfoForeground,
457 > nls.localize('problemsInfoIconForeground', "The color used for the problems info icon."));
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/textModelEvents.ts 447 covered LOC · 26 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelEvents.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 } from './core/position.js';
7 > import { IRange, Range } from './core/range.js';
8 > import { Selection } from './core/selection.js';
9 > import { IModelDecoration, InjectedTextOptions } from './model.js';
10 > import { IModelContentChange } from './model/mirrorTextModel.js';
11 > import { AnnotationsUpdate } from './model/tokens/annotations.js';
12 > import { TextModelEditSource } from './textModelEditSource.js';
13 >
14 > /**
15 > * An event describing that the current language associated with a model has changed.
16 > */
17 > export interface IModelLanguageChangedEvent {
18 > /**
19 > * Previous language
20 > */
21 > readonly oldLanguage: string;
22 > /**
23 > * New language
24 > */
25 > readonly newLanguage: string;
26 >
27 > /**
28 > * Source of the call that caused the event.
29 > */
30 > readonly source: string;
31 > }
32 >
33 > /**
34 > * An event describing that the language configuration associated with a model has changed.
35 > */
36 > export interface IModelLanguageConfigurationChangedEvent {
37 > }
38 >
39 > /**
40 > * An event describing a change in the text of a model.
41 > */
42 > export interface IModelContentChangedEvent {
43 > /**
44 > * The changes are ordered from the end of the document to the beginning, so they should be safe to apply in sequence.
45 > */
46 > readonly changes: IModelContentChange[];
47 > /**
48 > * The (new) end-of-line character.
49 > */
50 > readonly eol: string;
51 > /**
52 > * The new version id the model has transitioned to.
53 > */
54 > readonly versionId: number;
55 > /**
56 > * Flag that indicates that this event was generated while undoing.
57 > */
58 > readonly isUndoing: boolean;
59 > /**
60 > * Flag that indicates that this event was generated while redoing.
61 > */
62 > readonly isRedoing: boolean;
63 > /**
64 > * Flag that indicates that all decorations were lost with this edit.
65 > * The model has been reset to a new value.
66 > */
67 > readonly isFlush: boolean;
68 >
69 > /**
70 > * Flag that indicates that this event describes an eol change.
71 > */
72 > readonly isEolChange: boolean;
73 >
74 > /**
75 > * Detailed reason information for the change
76 > * @internal
77 > */
78 > readonly detailedReasons: TextModelEditSource[];
79 >
80 > /**
81 > * The sum of these lengths equals changes.length.
82 > * The length of this array must equal the length of detailedReasons.
83 > */
84 > readonly detailedReasonsChangeLengths: number[];
85 > }
86 >
87 > export interface ISerializedModelContentChangedEvent {
88 > /**
89 > * The changes are ordered from the end of the document to the beginning, so they should be safe to apply in sequence.
90 > */
91 > readonly changes: IModelContentChange[];
92 > /**
93 > * The (new) end-of-line character.
94 > */
95 > readonly eol: string;
96 > /**
97 > * The new version id the model has transitioned to.
98 > */
99 > readonly versionId: number;
100 > /**
101 > * Flag that indicates that this event was generated while undoing.
102 > */
103 > readonly isUndoing: boolean;
104 > /**
105 > * Flag that indicates that this event was generated while redoing.
106 > */
107 > readonly isRedoing: boolean;
108 > /**
109 > * Flag that indicates that all decorations were lost with this edit.
110 > * The model has been reset to a new value.
111 > */
112 > readonly isFlush: boolean;
113 >
114 > /**
115 > * Flag that indicates that this event describes an eol change.
116 > */
117 > readonly isEolChange: boolean;
118 >
119 > /**
120 > * Detailed reason information for the change
121 > * @internal
122 > */
123 > readonly detailedReason: Record<string, unknown> | undefined;
124 > }
125 >
126 > /**
127 > * An event describing that model decorations have changed.
128 > */
129 > export interface IModelDecorationsChangedEvent {
130 > readonly affectsMinimap: boolean;
131 > readonly affectsOverviewRuler: boolean;
132 > readonly affectsGlyphMargin: boolean;
133 > readonly affectsLineNumber: boolean;
134 > }
135 >
136 > /**
137 > * An event describing that some ranges of lines have been tokenized (their tokens have changed).
138 > * @internal
139 > */
140 > export interface IModelTokensChangedEvent {
141 > readonly semanticTokensApplied: boolean;
142 > readonly ranges: {
143 > /**
144 > * The start of the range (inclusive)
145 > */
146 > readonly fromLineNumber: number;
147 > /**
148 > * The end of the range (inclusive)
149 > */
150 > readonly toLineNumber: number;
151 > }[];
152 > }
153 >
154 > /**
155 > * @internal
156 > */
157 > export interface IFontTokenOption {
158 > /**
159 > * Font family of the token.
160 > */
161 > readonly fontFamily?: string;
162 > /**
163 > * Font size of the token.
164 > */
165 > readonly fontSizeMultiplier?: number;
166 > /**
167 > * Line height of the token.
168 > */
169 > readonly lineHeightMultiplier?: number;
170 > }
171 >
172 > /**
173 > * An event describing a token font change event
174 > * @internal
175 > */
176 > export interface IModelFontTokensChangedEvent {
177 > changes: FontTokensUpdate;
178 > }
179 >
180 > /**
181 > * @internal
182 > */
183 > export type FontTokensUpdate = AnnotationsUpdate<IFontTokenOption | undefined>;
184 >
185 > /**
186 > * @internal
187 > */
188 > export function serializeFontTokenOptions(): (options: IFontTokenOption) => IFontTokenOption {
189 return (annotation: IFontTokenOption) => {
190 return {
195 };
196 }
198 > /**
199 > * @internal
200 > */
201 > export function deserializeFontTokenOptions(): (options: IFontTokenOption) => IFontTokenOption {
202 return (annotation: IFontTokenOption) => {
203 return {
208 };
209 }
211 > export interface IModelOptionsChangedEvent {
212 > readonly tabSize: boolean;
213 > readonly indentSize: boolean;
214 > readonly insertSpaces: boolean;
215 > readonly trimAutoWhitespace: boolean;
216 > }
217 >
218 > /**
219 > * @internal
220 > */
221 > export const enum RawContentChangedType {
222 > Flush = 1,
223 > LineChanged = 2,
224 > LinesDeleted = 3,
225 > LinesInserted = 4,
226 > EOLChanged = 5
227 > }
228 >
229 > /**
230 > * An event describing that a model has been reset to a new value.
231 > * @internal
232 > */
233 > export class ModelRawFlush {
234 public readonly changeType = RawContentChangedType.Flush;
236 >
237 > /**
238 > * Represents text injected on a line
239 > * @internal
240 > */
241 > export class LineInjectedText {
242 > public static applyInjectedText(lineText: string, injectedTexts: LineInjectedText[] | null): string {
243 > if (!injectedTexts || injectedTexts.length === 0) {
244 > return lineText;
245 > }
246 > let result = ''; textModelEvents.ts
247 > let lastOriginalOffset = 0;
248 > for (const injectedText of injectedTexts) {
249 > result += lineText.substring(lastOriginalOffset, injectedText.column - 1);
250 > lastOriginalOffset = injectedText.column - 1;
251 > result += injectedText.options.content;
252 > }
253 > result += lineText.substring(lastOriginalOffset);
254 > return result;
256 >
257 > public static fromDecorations(decorations: IModelDecoration[]): LineInjectedText[] {
258 const result: LineInjectedText[] = [];
259 for (const decoration of decorations) {
288 return result;
289 }
291 > constructor(
292 public readonly ownerId: number,
293 public readonly lineNumber: number,
296 public readonly order: number
297 ) { }
299 > public withText(text: string): LineInjectedText {
300 return new LineInjectedText(this.ownerId, this.lineNumber, this.column, { ...this.options, content: text }, this.order);
301 }
303 >
304 > /**
305 > * An event describing that a line has changed in a model.
306 > * @internal
307 > */
308 > export class ModelRawLineChanged {
309 > public readonly changeType = RawContentChangedType.LineChanged;
310 > /**
311 > * The line number that has changed (before the change was applied).
312 > */
313 > public readonly lineNumber: number;
314 > /**
315 > * The new line number the old one is mapped to (after the change was applied).
316 > */
317 > public readonly lineNumberPostEdit: number;
318 >
319 > constructor(lineNumber: number, lineNumberPostEdit: number) {
320 this.lineNumber = lineNumber;
321 this.lineNumberPostEdit = lineNumberPostEdit;
322 }
324 >
325 >
326 > /**
327 > * An event describing that a line height has changed in the model.
328 > * @internal
329 > */
330 > export class ModelLineHeightChanged {
331 > /**
332 > * Editor owner ID
333 > */
334 > public readonly ownerId: number;
335 > /**
336 > * The decoration ID that has changed.
337 > */
338 > public readonly decorationId: string;
339 > /**
340 > * The line that has changed.
341 > */
342 > public readonly lineNumber: number;
343 > /**
344 > * The line height on the line.
345 > */
346 > public readonly lineHeightMultiplier: number | null;
347 >
348 > constructor(ownerId: number, decorationId: string, lineNumber: number, lineHeightMultiplier: number | null) {
349 this.ownerId = ownerId;
350 this.decorationId = decorationId;
352 this.lineHeightMultiplier = lineHeightMultiplier;
353 }
355 >
356 > /**
357 > * An event describing that a line height has changed in the model.
358 > * @internal
359 > */
360 > export class ModelFontChanged {
361 > /**
362 > * Editor owner ID
363 > */
364 > public readonly ownerId: number;
365 > /**
366 > * The line that has changed.
367 > */
368 > public readonly lineNumber: number;
369 >
370 > constructor(ownerId: number, lineNumber: number) {
371 this.ownerId = ownerId;
372 this.lineNumber = lineNumber;
373 }
375 >
376 > /**
377 > * An event describing that line(s) have been deleted in a model.
378 > * @internal
379 > */
380 > export class ModelRawLinesDeleted {
381 > public readonly changeType = RawContentChangedType.LinesDeleted;
382 > /**
383 > * At what line the deletion began (inclusive).
384 > */
385 > public readonly fromLineNumber: number;
386 > /**
387 > * At what line the deletion stopped (inclusive).
388 > */
389 > public readonly toLineNumber: number;
390 > /**
391 > * The last unmodified line in the updated buffer after the deletion is made.
392 > */
393 > public readonly lastUntouchedLinePostEdit: number;
394 >
395 > constructor(fromLineNumber: number, toLineNumber: number, lastUntouchedLinePostEdit: number) {
396 this.fromLineNumber = fromLineNumber;
397 this.toLineNumber = toLineNumber;
398 this.lastUntouchedLinePostEdit = lastUntouchedLinePostEdit;
399 }
401 >
402 > /**
403 > * An event describing that line(s) have been inserted in a model.
404 > * @internal
405 > */
406 > export class ModelRawLinesInserted {
407 > public readonly changeType = RawContentChangedType.LinesInserted;
408 > /**
409 > * Before what line did the insertion begin
410 > */
411 > public readonly fromLineNumber: number;
412 > /**
413 > * The actual start line number in the updated buffer where the newly inserted content can be found.
414 > */
415 > public readonly fromLineNumberPostEdit: number;
416 > /**
417 > * The count of inserted lines.
418 > */
419 > public readonly count: number;
420 > /**
421 > * `toLineNumber` - `fromLineNumber` + 1 denotes the number of lines that were inserted
422 > */
423 > public get toLineNumber(): number {
424 > return this.fromLineNumber + this.count - 1;
425 > }
426 > /**
427 > * The actual end line number of the insertion in the updated buffer.
428 > */
429 > public get toLineNumberPostEdit(): number {
430 return this.fromLineNumberPostEdit + this.count - 1;
431 }
433 > constructor(fromLineNumber: number, fromLineNumberPostEdit: number, count: number) {
434 this.fromLineNumber = fromLineNumber;
435 this.fromLineNumberPostEdit = fromLineNumberPostEdit;
436 this.count = count;
437 }
439 >
440 > /**
441 > * An event describing that a model has had its EOL changed.
442 > * @internal
443 > */
444 > export class ModelRawEOLChanged {
445 public readonly changeType = RawContentChangedType.EOLChanged;
447 >
448 > /**
449 > * @internal
450 > */
451 > export type ModelRawChange = ModelRawFlush | ModelRawLineChanged | ModelRawLinesDeleted | ModelRawLinesInserted | ModelRawEOLChanged;
452 >
453 > /**
454 > * An event describing a change in the text of a model.
455 > * @internal
456 > */
457 > export class ModelRawContentChangedEvent {
458 >
459 > public readonly changes: ModelRawChange[];
460 > /**
461 > * The new version id the model has transitioned to.
462 > */
463 > public readonly versionId: number;
464 > /**
465 > * Flag that indicates that this event was generated while undoing.
466 > */
467 > public readonly isUndoing: boolean;
468 > /**
469 > * Flag that indicates that this event was generated while redoing.
470 > */
471 > public readonly isRedoing: boolean;
472 >
473 > public resultingSelection: Selection[] | null;
474 >
475 > constructor(changes: ModelRawChange[], versionId: number, isUndoing: boolean, isRedoing: boolean) {
476 this.changes = changes;
477 this.versionId = versionId;
480 this.resultingSelection = null;
481 }
483 > public containsEvent(type: RawContentChangedType): boolean {
484 for (let i = 0, len = this.changes.length; i < len; i++) {
485 const change = this.changes[i];
490 return false;
491 }
493 > public static merge(a: ModelRawContentChangedEvent, b: ModelRawContentChangedEvent): ModelRawContentChangedEvent {
494 const changes = ([] as ModelRawChange[]).concat(a.changes).concat(b.changes);
495 const versionId = b.versionId;
498 return new ModelRawContentChangedEvent(changes, versionId, isUndoing, isRedoing);
499 }
501 >
502 > /**
503 > * An event describing a change in injected text.
504 > * @internal
505 > */
506 > export class ModelInjectedTextChangedEvent {
507 >
508 > public readonly changes: ModelRawLineChanged[];
509 >
510 > constructor(changes: ModelRawLineChanged[]) {
511 this.changes = changes;
512 }
514 >
515 > /**
516 > * An event describing a change of a line height.
517 > * @internal
518 > */
519 > export class ModelLineHeightChangedEvent {
520 >
521 > public readonly changes: ModelLineHeightChanged[];
522 >
523 > constructor(changes: ModelLineHeightChanged[]) {
524 this.changes = changes;
525 }
527 > public affects(rangeOrPosition: IRange | IPosition) {
528 if (Range.isIRange(rangeOrPosition)) {
529 for (const change of this.changes) {
542 }
543 }
545 >
546 > /**
547 > * An event describing a change in fonts.
548 > * @internal
549 > */
550 > export class ModelFontChangedEvent {
551 >
552 > public readonly changes: ModelFontChanged[];
553 >
554 > constructor(changes: ModelFontChanged[]) {
555 this.changes = changes;
556 }
558 >
559 > /**
560 > * @internal
561 > */
562 > export class InternalModelContentChangeEvent {
563 > constructor(
564 public readonly rawContentChangedEvent: ModelRawContentChangedEvent,
565 public readonly contentChangedEvent: IModelContentChangedEvent,
566 ) { }
568 > public merge(other: InternalModelContentChangeEvent): InternalModelContentChangeEvent {
569 const rawContentChangedEvent = ModelRawContentChangedEvent.merge(this.rawContentChangedEvent, other.rawContentChangedEvent);
570 const contentChangedEvent = InternalModelContentChangeEvent._mergeChangeEvents(this.contentChangedEvent, other.contentChangedEvent);
571 return new InternalModelContentChangeEvent(rawContentChangedEvent, contentChangedEvent);
572 }
574 > private static _mergeChangeEvents(a: IModelContentChangedEvent, b: IModelContentChangedEvent): IModelContentChangedEvent {
575 const changes = ([] as IModelContentChange[]).concat(a.changes).concat(b.changes);
576 const eol = b.eol;
src/vs/platform/log/common/log.ts 446 covered LOC · 72 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- log.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 > import { toErrorMessage } from '../../../base/common/errorMessage.js';
8 > import { Emitter, Event } from '../../../base/common/event.js';
9 > import { hash } from '../../../base/common/hash.js';
10 > import { Disposable, IDisposable, toDisposable } from '../../../base/common/lifecycle.js';
11 > import { ResourceMap } from '../../../base/common/map.js';
12 > import { isWindows } from '../../../base/common/platform.js';
13 > import { joinPath } from '../../../base/common/resources.js';
14 > import { Mutable, isNumber, isString } from '../../../base/common/types.js';
15 > import { URI } from '../../../base/common/uri.js';
16 > import { ILocalizedString } from '../../action/common/action.js';
17 > import { RawContextKey } from '../../contextkey/common/contextkey.js';
18 > import { IEnvironmentService } from '../../environment/common/environment.js';
19 > import { createDecorator } from '../../instantiation/common/instantiation.js';
20 >
21 > export const ILogService = createDecorator<ILogService>('logService');
22 > export const ILoggerService = createDecorator<ILoggerService>('loggerService');
23 >
24 function now(): string {
25 return new Date().toISOString();
26 }
27 > log.ts
28 > export function isLogLevel(thing: unknown): thing is LogLevel {
29 return isNumber(thing);
30 }
31 > log.ts
32 > export enum LogLevel {
33 > Off,
34 > Trace,
35 > Debug,
36 > Info,
37 > Warning,
38 > Error
39 > }
40 >
41 > export const DEFAULT_LOG_LEVEL: LogLevel = LogLevel.Info;
42 >
43 > export interface ILogger extends IDisposable {
44 > readonly onDidChangeLogLevel: Event<LogLevel>;
45 > getLevel(): LogLevel;
46 > setLevel(level: LogLevel): void;
47 >
48 > trace(message: string, ...args: unknown[]): void;
49 > debug(message: string, ...args: unknown[]): void;
50 > info(message: string, ...args: unknown[]): void;
51 > warn(message: string, ...args: unknown[]): void;
52 > error(message: string | Error, ...args: unknown[]): void;
53 >
54 > /**
55 > * An operation to flush the contents. Can be synchronous.
56 > */
57 > flush(): void;
58 > }
59 >
60 > export function canLog(loggerLevel: LogLevel, messageLevel: LogLevel): boolean {
61 return loggerLevel !== LogLevel.Off && loggerLevel <= messageLevel;
62 }
63 > log.ts
64 > export function log(logger: ILogger, level: LogLevel, message: string): void {
65 switch (level) {
66 case LogLevel.Trace: logger.trace(message); break;
73 }
74 }
75 > log.ts
76 > type ConsoleMethod = 'debug' | 'error' | 'info' | 'log' | 'warn';
77 > type ConsoleMethodFn = (...args: unknown[]) => void;
78 >
79 > /**
80 > * Flag to enable forwarding of console.* calls to the log service in development.
81 > * This is intended for the use of agents to quickly instrument the code with console.logs
82 > * which will end up in the log service's file outputs.
83 > */
84 > export const isDevConsoleLogForwardingEnabled = false
85 > // || Boolean("true") // done "weirdly" so that a lint warning prevents you from pushing this
86 > ;
87 >
88 > let isConsoleForwarding = false;
89 > let isLogServiceConsoleEcho = false;
90 >
91 function getConsoleMethod(method: ConsoleMethod): ConsoleMethodFn {
92 switch (method) {
98 }
99 }
100 > log.ts
101 function setConsoleMethod(method: ConsoleMethod, fn: ConsoleMethodFn): void {
102 switch (method) {
108 }
109 }
110 > log.ts
111 function logToConsole(method: ConsoleMethod, ...args: unknown[]): void {
112 if (isConsoleForwarding) {
120 }
121 }
122 > log.ts
123 > export function registerDevConsoleLogForwarder(logService: ILogService): IDisposable {
124 const originalConsoleMethods: Record<ConsoleMethod, ConsoleMethodFn> = {
125 debug: console.debug,
177 });
178 }
179 > log.ts
180 > export function format(args: any, verbose: boolean = false): string {
181 let result = '';
182
199 return result;
200 }
201 > log.ts
202 > export type LoggerGroup = {
203 > readonly id: string;
204 > readonly name: string;
205 > };
206 >
207 > export interface ILogService extends ILogger {
208 > readonly _serviceBrand: undefined;
209 > }
210 >
211 > export interface ILoggerOptions {
212 >
213 > /**
214 > * Id of the logger.
215 > */
216 > id?: string;
217 >
218 > /**
219 > * Name of the logger.
220 > */
221 > name?: string;
222 >
223 > /**
224 > * Do not create rotating files if max size exceeds.
225 > */
226 > donotRotate?: boolean;
227 >
228 > /**
229 > * Do not use formatters.
230 > */
231 > donotUseFormatters?: boolean;
232 >
233 > /**
234 > * When to log. Set to `always` to log always.
235 > */
236 > logLevel?: 'always' | LogLevel;
237 >
238 > /**
239 > * Whether the log should be hidden from the user.
240 > */
241 > hidden?: boolean;
242 >
243 > /**
244 > * Condition which must be true to show this logger
245 > */
246 > when?: string;
247 >
248 > /**
249 > * Id of the extension that created this logger.
250 > */
251 > extensionId?: string;
252 >
253 > /**
254 > * Group of the logger.
255 > */
256 > group?: LoggerGroup;
257 > }
258 >
259 > export interface ILoggerResource {
260 > readonly resource: URI;
261 > readonly id: string;
262 > readonly name?: string;
263 > readonly logLevel?: LogLevel;
264 > readonly hidden?: boolean;
265 > readonly when?: string;
266 > readonly extensionId?: string;
267 > readonly group?: LoggerGroup;
268 > }
269 >
270 > export type DidChangeLoggersEvent = {
271 > readonly added: Iterable<ILoggerResource>;
272 > readonly removed: Iterable<ILoggerResource>;
273 > };
274 >
275 > export interface ILoggerService {
276 >
277 > readonly _serviceBrand: undefined;
278 >
279 > /**
280 > * Creates a logger for the given resource, or gets one if it already exists.
281 > *
282 > * This will also register the logger with the logger service.
283 > */
284 > createLogger(resource: URI, options?: ILoggerOptions): ILogger;
285 >
286 > /**
287 > * Creates a logger with the given id in the logs folder, or gets one if it already exists.
288 > *
289 > * This will also register the logger with the logger service.
290 > */
291 > createLogger(id: string, options?: Omit<ILoggerOptions, 'id'>): ILogger;
292 >
293 > /**
294 > * Gets an existing logger, if any.
295 > */
296 > getLogger(resourceOrId: URI | string): ILogger | undefined;
297 >
298 > /**
299 > * An event which fires when the log level of a logger has changed
300 > */
301 > readonly onDidChangeLogLevel: Event<LogLevel | [URI, LogLevel]>;
302 >
303 > /**
304 > * Set default log level.
305 > */
306 > setLogLevel(level: LogLevel): void;
307 >
308 > /**
309 > * Set log level for a logger.
310 > */
311 > setLogLevel(resource: URI, level: LogLevel): void;
312 >
313 > /**
314 > * Get log level for a logger or the default log level.
315 > */
316 > getLogLevel(resource?: URI): LogLevel;
317 >
318 > /**
319 > * An event which fires when the visibility of a logger has changed
320 > */
321 > readonly onDidChangeVisibility: Event<[URI, boolean]>;
322 >
323 > /**
324 > * Set the visibility of a logger.
325 > */
326 > setVisibility(resourceOrId: URI | string, visible: boolean): void;
327 >
328 > /**
329 > * An event which fires when the logger resources are changed
330 > */
331 > readonly onDidChangeLoggers: Event<DidChangeLoggersEvent>;
332 >
333 > /**
334 > * Register a logger with the logger service.
335 > *
336 > * Note that this will not create a logger, but only register it.
337 > *
338 > * Use `createLogger` to create a logger and register it.
339 > *
340 > * Use it when you want to register a logger that is not created by the logger service.
341 > */
342 > registerLogger(resource: ILoggerResource): void;
343 >
344 > /**
345 > * Deregister the logger for the given resource.
346 > */
347 > deregisterLogger(idOrResource: URI | string): void;
348 >
349 > /**
350 > * Get all registered loggers
351 > */
352 > getRegisteredLoggers(): Iterable<ILoggerResource>;
353 >
354 > /**
355 > * Get the registered logger for the given resource.
356 > */
357 > getRegisteredLogger(resource: URI): ILoggerResource | undefined;
358 > }
359 >
360 > export abstract class AbstractLogger extends Disposable implements ILogger {
361
362 private level: LogLevel = DEFAULT_LOG_LEVEL;
363 private readonly _onDidChangeLogLevel: Emitter<LogLevel> = this._register(new Emitter<LogLevel>());
364 > get onDidChangeLogLevel(): Event<LogLevel> { return this._onDidChangeLogLevel.event; } log.ts
365 >
366 > setLevel(level: LogLevel): void {
367 if (this.level !== level) {
368 this.level = level;
370 }
371 }
372 > log.ts
373 > getLevel(): LogLevel {
374 return this.level;
375 }
376 > log.ts
377 > protected checkLogLevel(level: LogLevel): boolean {
378 return canLog(this.level, level);
379 }
380 > log.ts
381 > protected canLog(level: LogLevel): boolean {
382 if (this._store.isDisposed) {
383 return false;
385 return this.checkLogLevel(level);
386 }
387 > log.ts
388 > abstract trace(message: string, ...args: unknown[]): void;
389 > abstract debug(message: string, ...args: unknown[]): void;
390 > abstract info(message: string, ...args: unknown[]): void;
391 > abstract warn(message: string, ...args: unknown[]): void;
392 > abstract error(message: string | Error, ...args: unknown[]): void;
393 > abstract flush(): void;
394 > }
395 >
396 > export abstract class AbstractMessageLogger extends AbstractLogger implements ILogger {
397 >
398 > constructor(private readonly logAlways?: boolean) {
399 super();
400 }
401 > log.ts
402 > protected override checkLogLevel(level: LogLevel): boolean {
403 return this.logAlways || super.checkLogLevel(level);
404 }
405 > log.ts
406 > trace(message: string, ...args: unknown[]): void {
407 if (this.canLog(LogLevel.Trace)) {
408 this.log(LogLevel.Trace, format([message, ...args], true));
409 }
410 }
411 > log.ts
412 > debug(message: string, ...args: unknown[]): void {
413 if (this.canLog(LogLevel.Debug)) {
414 this.log(LogLevel.Debug, format([message, ...args]));
415 }
416 }
417 > log.ts
418 > info(message: string, ...args: unknown[]): void {
419 if (this.canLog(LogLevel.Info)) {
420 this.log(LogLevel.Info, format([message, ...args]));
421 }
422 }
423 > log.ts
424 > warn(message: string, ...args: unknown[]): void {
425 if (this.canLog(LogLevel.Warning)) {
426 this.log(LogLevel.Warning, format([message, ...args]));
427 }
428 }
429 > log.ts
430 > error(message: string | Error, ...args: unknown[]): void {
431 if (this.canLog(LogLevel.Error)) {
432 if (message instanceof Error) {
439 }
440 }
441 > log.ts
442 > flush(): void { }
443 >
444 > protected abstract log(level: LogLevel, message: string): void;
445 > }
446 >
447 >
448 > export class ConsoleMainLogger extends AbstractLogger implements ILogger {
449 >
450 > private useColors: boolean;
451 >
452 > constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
453 super();
454 this.setLevel(logLevel);
455 this.useColors = !isWindows;
456 }
457 > log.ts
458 > trace(message: string, ...args: unknown[]): void {
459 if (this.canLog(LogLevel.Trace)) {
460 if (this.useColors) {
465 }
466 }
467 > log.ts
468 > debug(message: string, ...args: unknown[]): void {
469 if (this.canLog(LogLevel.Debug)) {
470 if (this.useColors) {
475 }
476 }
477 > log.ts
478 > info(message: string, ...args: unknown[]): void {
479 if (this.canLog(LogLevel.Info)) {
480 if (this.useColors) {
485 }
486 }
487 > log.ts
488 > warn(message: string | Error, ...args: unknown[]): void {
489 if (this.canLog(LogLevel.Warning)) {
490 if (this.useColors) {
495 }
496 }
497 > log.ts
498 > error(message: string, ...args: unknown[]): void {
499 if (this.canLog(LogLevel.Error)) {
500 if (this.useColors) {
505 }
506 }
507 > log.ts
508 > flush(): void {
509 // noop
510 }
511 > log.ts
512 > }
513 >
514 > export class ConsoleLogger extends AbstractLogger implements ILogger {
515 >
516 > constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL, private readonly useColors: boolean = true) {
517 super();
518 this.setLevel(logLevel);
519 }
520 > log.ts
521 > trace(message: string, ...args: unknown[]): void {
522 if (this.canLog(LogLevel.Trace)) {
523 if (this.useColors) {
528 }
529 }
530 > log.ts
531 > debug(message: string, ...args: unknown[]): void {
532 if (this.canLog(LogLevel.Debug)) {
533 if (this.useColors) {
538 }
539 }
540 > log.ts
541 > info(message: string, ...args: unknown[]): void {
542 if (this.canLog(LogLevel.Info)) {
543 if (this.useColors) {
548 }
549 }
550 > log.ts
551 > warn(message: string | Error, ...args: unknown[]): void {
552 if (this.canLog(LogLevel.Warning)) {
553 if (this.useColors) {
558 }
559 }
560 > log.ts
561 > error(message: string, ...args: unknown[]): void {
562 if (this.canLog(LogLevel.Error)) {
563 if (this.useColors) {
568 }
569 }
570 > log.ts
571 >
572 > flush(): void {
573 // noop
574 }
575 > } log.ts
576 >
577 > export class AdapterLogger extends AbstractLogger implements ILogger {
578 >
579 > constructor(private readonly adapter: { log: (logLevel: LogLevel, args: any[]) => void }, logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
580 super();
581 this.setLevel(logLevel);
582 }
583 > log.ts
584 > trace(message: string, ...args: unknown[]): void {
585 if (this.canLog(LogLevel.Trace)) {
586 this.adapter.log(LogLevel.Trace, [this.extractMessage(message), ...args]);
587 }
588 }
589 > log.ts
590 > debug(message: string, ...args: unknown[]): void {
591 if (this.canLog(LogLevel.Debug)) {
592 this.adapter.log(LogLevel.Debug, [this.extractMessage(message), ...args]);
593 }
594 }
595 > log.ts
596 > info(message: string, ...args: unknown[]): void {
597 if (this.canLog(LogLevel.Info)) {
598 this.adapter.log(LogLevel.Info, [this.extractMessage(message), ...args]);
599 }
600 }
601 > log.ts
602 > warn(message: string | Error, ...args: unknown[]): void {
603 if (this.canLog(LogLevel.Warning)) {
604 this.adapter.log(LogLevel.Warning, [this.extractMessage(message), ...args]);
605 }
606 }
607 > log.ts
608 > error(message: string | Error, ...args: unknown[]): void {
609 if (this.canLog(LogLevel.Error)) {
610 this.adapter.log(LogLevel.Error, [this.extractMessage(message), ...args]);
611 }
612 }
613 > log.ts
614 > private extractMessage(msg: string | Error): string {
615 if (typeof msg === 'string') {
616 return msg;
619 return toErrorMessage(msg, this.canLog(LogLevel.Trace));
620 }
621 > log.ts
622 > flush(): void {
623 // noop
624 }
625 > } log.ts
626 >
627 > export class MultiplexLogger extends AbstractLogger implements ILogger {
628 >
629 > constructor(private readonly loggers: ReadonlyArray<ILogger>) {
630 super();
631 if (loggers.length) {
633 }
634 }
635 > log.ts
636 > override setLevel(level: LogLevel): void {
637 for (const logger of this.loggers) {
638 logger.setLevel(level);
640 super.setLevel(level);
641 }
642 > log.ts
643 > trace(message: string, ...args: unknown[]): void {
644 for (const logger of this.loggers) {
645 logger.trace(message, ...args);
646 }
647 }
648 > log.ts
649 > debug(message: string, ...args: unknown[]): void {
650 for (const logger of this.loggers) {
651 logger.debug(message, ...args);
652 }
653 }
654 > log.ts
655 > info(message: string, ...args: unknown[]): void {
656 for (const logger of this.loggers) {
657 logger.info(message, ...args);
658 }
659 }
660 > log.ts
661 > warn(message: string, ...args: unknown[]): void {
662 for (const logger of this.loggers) {
663 logger.warn(message, ...args);
664 }
665 }
666 > log.ts
667 > error(message: string | Error, ...args: unknown[]): void {
668 for (const logger of this.loggers) {
669 logger.error(message, ...args);
670 }
671 }
672 > log.ts
673 > flush(): void {
674 for (const logger of this.loggers) {
675 logger.flush();
676 }
677 }
678 > log.ts
679 > override dispose(): void {
680 for (const logger of this.loggers) {
681 logger.dispose();
683 super.dispose();
684 }
685 > } log.ts
686 >
687 > type LoggerEntry = { logger: ILogger | undefined; info: Mutable<ILoggerResource> };
688 >
689 > export abstract class AbstractLoggerService extends Disposable implements ILoggerService {
690 >
691 > declare readonly _serviceBrand: undefined;
692 >
693 > private readonly _loggers = new ResourceMap<LoggerEntry>();
694 >
695 > private _onDidChangeLoggers = this._register(new Emitter<{ added: ILoggerResource[]; removed: ILoggerResource[] }>);
696 > readonly onDidChangeLoggers = this._onDidChangeLoggers.event;
697 >
698 > private _onDidChangeLogLevel = this._register(new Emitter<LogLevel | [URI, LogLevel]>);
699 > readonly onDidChangeLogLevel = this._onDidChangeLogLevel.event;
700 >
701 > private _onDidChangeVisibility = this._register(new Emitter<[URI, boolean]>);
702 > readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
703 >
704 > constructor(
705 protected logLevel: LogLevel,
706 private readonly logsHome: URI,
714 }
715 }
716 > log.ts
717 > private getLoggerEntry(resourceOrId: URI | string): LoggerEntry | undefined {
718 if (isString(resourceOrId)) {
719 return [...this._loggers.values()].find(logger => logger.info.id === resourceOrId);
721 return this._loggers.get(resourceOrId);
722 }
723 > log.ts
724 > getLogger(resourceOrId: URI | string): ILogger | undefined {
725 return this.getLoggerEntry(resourceOrId)?.logger;
726 }
727 > log.ts
728 > createLogger(idOrResource: URI | string, options?: ILoggerOptions): ILogger {
729 const resource = this.toResource(idOrResource);
730 const id = isString(idOrResource) ? idOrResource : (options?.id ?? hash(resource.toString()).toString(16));
752 return logger;
753 }
754 > log.ts
755 > protected toResource(idOrResource: string | URI): URI {
756 return isString(idOrResource) ? joinPath(this.logsHome, `${idOrResource.replace(/[\\/:\*\?"<>\|]/g, '')}.log`) : idOrResource;
757 }
758 > log.ts
759 > setLogLevel(logLevel: LogLevel): void;
760 > setLogLevel(resource: URI, logLevel: LogLevel): void;
761 > setLogLevel(arg1: any, arg2?: any): void {
762 if (URI.isUri(arg1)) {
763 const resource = arg1;
780 }
781 }
782 > log.ts
783 > setVisibility(resourceOrId: URI | string, visibility: boolean): void {
784 const logger = this.getLoggerEntry(resourceOrId);
785 if (logger && visibility !== !logger.info.hidden) {
789 }
790 }
791 > log.ts
792 > getLogLevel(resource?: URI): LogLevel {
793 let logLevel;
794 if (resource) {
797 return logLevel ?? this.logLevel;
798 }
799 > log.ts
800 > registerLogger(resource: ILoggerResource): void {
801 const existing = this._loggers.get(resource.resource);
802 if (existing) {
809 }
810 }
811 > log.ts
812 > deregisterLogger(idOrResource: URI | string): void {
813 const resource = this.toResource(idOrResource);
814 const existing = this._loggers.get(resource);
821 }
822 }
823 > log.ts
824 > *getRegisteredLoggers(): Iterable<ILoggerResource> {
825 for (const entry of this._loggers.values()) {
826 yield entry.info;
827 }
828 }
829 > log.ts
830 > getRegisteredLogger(resource: URI): ILoggerResource | undefined {
831 return this._loggers.get(resource)?.info;
832 }
833 > log.ts
834 > override dispose(): void {
835 this._loggers.forEach(logger => logger.logger?.dispose());
836 this._loggers.clear();
837 super.dispose();
838 }
839 > log.ts
840 > protected abstract doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger;
841 > }
842 >
843 > export class NullLogger implements ILogger {
844 readonly onDidChangeLogLevel: Event<LogLevel> = new Emitter<LogLevel>().event;
845 > setLevel(level: LogLevel): void { } log.ts
846 > getLevel(): LogLevel { return LogLevel.Info; }
847 > trace(message: string, ...args: unknown[]): void { }
848 > debug(message: string, ...args: unknown[]): void { }
849 > info(message: string, ...args: unknown[]): void { }
850 > warn(message: string, ...args: unknown[]): void { }
851 > error(message: string | Error, ...args: unknown[]): void { }
852 > critical(message: string | Error, ...args: unknown[]): void { }
853 > dispose(): void { }
854 > flush(): void { }
855 > }
856 >
857 > export class NullLogService extends NullLogger implements ILogService {
858 > declare readonly _serviceBrand: undefined;
859 > }
860 >
861 > export class NullLoggerService extends AbstractLoggerService {
862 > constructor() {
863 super(LogLevel.Off, URI.parse('log:///log'));
864 }
865 > protected override doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger { log.ts
866 return new NullLogger();
867 }
868 > } log.ts
869 >
870 > export function getLogLevel(environmentService: IEnvironmentService): LogLevel {
871 if (environmentService.verbose) {
872 return LogLevel.Trace;
880 return DEFAULT_LOG_LEVEL;
881 }
882 > log.ts
883 > export function LogLevelToString(logLevel: LogLevel): string {
884 > switch (logLevel) {
885 > case LogLevel.Trace: return 'trace';
886 > case LogLevel.Debug: return 'debug';
887 > case LogLevel.Info: return 'info';
888 > case LogLevel.Warning: return 'warn';
889 > case LogLevel.Error: return 'error';
890 > case LogLevel.Off: return 'off';
891 > }
892 > }
893 >
894 > export function LogLevelToLocalizedString(logLevel: LogLevel): ILocalizedString {
895 switch (logLevel) {
896 case LogLevel.Trace: return { original: 'Trace', value: nls.localize('trace', "Trace") };
902 }
903 }
904 > log.ts
905 > export function parseLogLevel(logLevel: string): LogLevel | undefined {
906 switch (logLevel) {
907 case 'trace':
922 return undefined;
923 }
924 > log.ts
925 > // Contexts
926 > export const CONTEXT_LOG_LEVEL = new RawContextKey<string>('logLevel', LogLevelToString(LogLevel.Info));
src/vs/base/common/color.ts 418 covered LOC · 84 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; color.ts
74 > this.s = roundFloat(Math.max(Math.min(1, s), 0), 3);
75 > this.l = roundFloat(Math.max(Math.min(1, l), 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; color.ts
91 > const g = rgba.g / 255;
92 > const b = rgba.b / 255;
93 > const a = rgba.a;
94 >
95 > const max = Math.max(r, g, b);
96 > const min = Math.min(r, g, b);
97 > let h = 0;
98 > let s = 0;
99 > const l = (min + max) / 2;
100 > const chroma = max - min;
101 >
102 > if (chroma > 0) {
103 s = Math.min((l <= 0.5 ? chroma / (2 * l) : chroma / (2 - (2 * l))), 1);
104
112 h = Math.round(h);
113 }
114 > return new HSLA(h, s, l, a); color.ts
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; color.ts
144 > const { s, l, a } = hsla;
145 > let r: number, g: number, b: number;
146 >
147 > if (s === 0) {
148 > r = g = b = l; // achromatic color.ts
149 > } else { color.ts
150 const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
151 const p = 2 * l - q;
154 b = HSLA._hue2rgb(p, q, h - 1 / 3);
155 }
156 > color.ts
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; color.ts
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) { color.ts
276 return this._hsla;
277 > } else { color.ts
278 > return HSLA.fromRGBA(this.rgba); color.ts
279 > }
280 > } color.ts
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; color.ts
297 > this.rgba = HSLA.toRGBA(arg);
298 > } else if (arg instanceof HSVA) { color.ts
299 this._hsva = arg;
300 this.rgba = HSVA.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)); color.ts
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; color.ts
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; color.ts
864 >
865 > if (length === 0) {
866 // Invalid color
867 return null;
868 }
869 > color.ts
870 > if (hex.charCodeAt(0) !== CharCode.Hash) {
871 // Does not begin with a #
872 return null;
873 }
874 > color.ts
875 > if (length === 7) {
876 > // #RRGGBB format color.ts
877 > const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));
878 > const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));
879 > const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));
880 > return new Color(new RGBA(r, g, b, 1));
881 > }
882 > color.ts
883 > if (length === 9) {
884 > // #RRGGBBAA format color.ts
885 > const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));
886 > const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));
887 > const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));
888 > const a = 16 * _parseHexDigit(hex.charCodeAt(7)) + _parseHexDigit(hex.charCodeAt(8));
889 > return new Color(new RGBA(r, g, b, a / 255));
890 > }
891 > color.ts
892 > if (length === 4) {
893 > // #RGB format color.ts
894 > const r = _parseHexDigit(hex.charCodeAt(1));
895 > const g = _parseHexDigit(hex.charCodeAt(2));
896 > const b = _parseHexDigit(hex.charCodeAt(3));
897 > return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b));
898 > }
899 > color.ts
900 > if (length === 5) {
901 > // #RGBA format color.ts
902 > const r = _parseHexDigit(hex.charCodeAt(1));
903 > const g = _parseHexDigit(hex.charCodeAt(2));
904 > const b = _parseHexDigit(hex.charCodeAt(3));
905 > const a = _parseHexDigit(hex.charCodeAt(4));
906 > return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b, (16 * a + a) / 255));
907 > }
908
909 // Invalid color
910 return null;
911 > } color.ts
912 > color.ts
913 > function _parseHexDigit(charCode: CharCode): number {
914 > switch (charCode) { color.ts
915 > case CharCode.Digit0: return 0;
916 > case CharCode.Digit1: return 1;
917 > case CharCode.Digit2: return 2;
918 > case CharCode.Digit3: return 3;
919 > case CharCode.Digit4: return 4;
920 > case CharCode.Digit5: return 5;
921 > case CharCode.Digit6: return 6;
922 > case CharCode.Digit7: return 7;
923 > case CharCode.Digit8: return 8;
924 > case CharCode.Digit9: return 9;
925 > case CharCode.a: return 10;
926 > case CharCode.A: return 10;
927 > case CharCode.b: return 11;
928 > case CharCode.B: return 11;
929 > case CharCode.c: return 12;
930 > case CharCode.C: return 12;
931 > case CharCode.d: return 13;
932 > case CharCode.D: return 13;
933 > case CharCode.e: return 14;
934 > case CharCode.E: return 14;
935 > case CharCode.f: return 15;
936 > case CharCode.F: return 15;
937 > }
938 return 0;
939 > } color.ts
940 > } color.ts
941 > }
942 > }
src/vs/base/common/arrays.ts 415 covered LOC · 77 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- arrays.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { findFirstIdxMonotonousOrArrLen } from './arraysFind.js';
7 > import { CancellationToken } from './cancellation.js';
8 > import { CancellationError } from './errors.js';
9 > import { ISplice } from './sequence.js';
10 >
11 > /**
12 > * Returns the last entry and the initial N-1 entries of the array, as a tuple of [rest, last].
13 > *
14 > * The array must have at least one element.
15 > *
16 > * @param arr The input array
17 > * @returns A tuple of [rest, last] where rest is all but the last element and last is the last element
18 > * @throws Error if the array is empty
19 > */
20 > export function tail<T>(arr: T[]): [T[], T] {
21 if (arr.length === 0) {
22 throw new Error('Invalid tail call');
25 return [arr.slice(0, arr.length - 1), arr[arr.length - 1]];
26 }
27 > arrays.ts
28 > export function equals<T>(one: ReadonlyArray<T> | undefined, other: ReadonlyArray<T> | undefined, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {
29 if (one === other) {
30 return true;
47 return true;
48 }
49 > arrays.ts
50 > /**
51 > * Remove the element at `index` by replacing it with the last element. This is faster than `splice`
52 > * but changes the order of the array
53 > */
54 > export function removeFastWithoutKeepingOrder<T>(array: T[], index: number) {
55 const last = array.length - 1;
56 if (index < last) {
59 array.pop();
60 }
61 > arrays.ts
62 > /**
63 > * Performs a binary search algorithm over a sorted array.
64 > *
65 > * @param array The array being searched.
66 > * @param key The value we search for.
67 > * @param comparator A function that takes two array elements and returns zero
68 > * if they are equal, a negative number if the first element precedes the
69 > * second one in the sorting order, or a positive number if the second element
70 > * precedes the first one.
71 > * @return See {@link binarySearch2}
72 > */
73 > export function binarySearch<T>(array: ReadonlyArray<T>, key: T, comparator: (op1: T, op2: T) => number): number {
74 return binarySearch2(array.length, i => comparator(array[i], key));
75 }
76 > arrays.ts
77 > /**
78 > * Performs a binary search algorithm over a sorted collection. Useful for cases
79 > * when we need to perform a binary search over something that isn't actually an
80 > * array, and converting data to an array would defeat the use of binary search
81 > * in the first place.
82 > *
83 > * @param length The collection length.
84 > * @param compareToKey A function that takes an index of an element in the
85 > * collection and returns zero if the value at this index is equal to the
86 > * search key, a negative number if the value precedes the search key in the
87 > * sorting order, or a positive number if the search key precedes the value.
88 > * @return A non-negative index of an element, if found. If not found, the
89 > * result is -(n+1) (or ~n, using bitwise notation), where n is the index
90 > * where the key should be inserted to maintain the sorting order.
91 > */
92 > export function binarySearch2(length: number, compareToKey: (index: number) => number): number {
93 let low = 0,
94 high = length - 1;
107 return -(low + 1);
108 }
109 > arrays.ts
110 > type Compare<T> = (a: T, b: T) => number;
111 >
112 > /**
113 > * Finds the nth smallest element in the array using quickselect algorithm.
114 > * The data does not need to be sorted.
115 > *
116 > * @param nth The zero-based index of the element to find (0 = smallest, 1 = second smallest, etc.)
117 > * @param data The unsorted array
118 > * @param compare A comparator function that defines the sort order
119 > * @returns The nth smallest element
120 > * @throws TypeError if nth is >= data.length
121 > */
122 > export function quickSelect<T>(nth: number, data: T[], compare: Compare<T>): T {
123
124 nth = nth | 0;
152 }
153 }
154 > arrays.ts
155 > export function groupBy<T>(data: ReadonlyArray<T>, compare: (a: T, b: T) => number): T[][] {
156 const result: T[][] = [];
157 let currentGroup: T[] | undefined = undefined;
166 return result;
167 }
168 > arrays.ts
169 > /**
170 > * Splits the given items into a list of (non-empty) groups.
171 > * `shouldBeGrouped` is used to decide if two consecutive items should be in the same group.
172 > * The order of the items is preserved.
173 > */
174 > export function* groupAdjacentBy<T>(items: Iterable<T>, shouldBeGrouped: (item1: T, item2: T) => boolean): Iterable<T[]> {
175 let currentGroup: T[] | undefined;
176 let last: T | undefined;
190 }
191 }
192 > arrays.ts
193 > export function forEachAdjacent<T>(arr: T[], f: (item1: T | undefined, item2: T | undefined) => void): void {
194 for (let i = 0; i <= arr.length; i++) {
195 f(i === 0 ? undefined : arr[i - 1], i === arr.length ? undefined : arr[i]);
196 }
197 }
198 > arrays.ts
199 > export function forEachWithNeighbors<T>(arr: T[], f: (before: T | undefined, element: T, after: T | undefined) => void): void {
200 for (let i = 0; i < arr.length; i++) {
201 f(i === 0 ? undefined : arr[i - 1], arr[i], i + 1 === arr.length ? undefined : arr[i + 1]);
202 }
203 }
204 > arrays.ts
205 > export function concatArrays<T extends any[]>(...arrays: T): T[number][number][] {
206 return [].concat(...arrays);
207 }
208 > arrays.ts
209 > interface IMutableSplice<T> extends ISplice<T> {
210 > readonly toInsert: T[];
211 > deleteCount: number;
212 > }
213 >
214 > /**
215 > * Diffs two *sorted* arrays and computes the splices which apply the diff.
216 > */
217 > export function sortedDiff<T>(before: ReadonlyArray<T>, after: ReadonlyArray<T>, compare: (a: T, b: T) => number): ISplice<T>[] {
218 const result: IMutableSplice<T>[] = [];
219
266 return result;
267 }
268 > arrays.ts
269 > /**
270 > * Takes two *sorted* arrays and computes their delta (removed, added elements).
271 > * Finishes in `Math.min(before.length, after.length)` steps.
272 > */
273 > export function delta<T>(before: ReadonlyArray<T>, after: ReadonlyArray<T>, compare: (a: T, b: T) => number): { removed: T[]; added: T[] } {
274 const splices = sortedDiff(before, after, compare);
275 const removed: T[] = [];
283 return { removed, added };
284 }
285 > arrays.ts
286 > /**
287 > * Returns the top N elements from the array.
288 > *
289 > * Faster than sorting the entire array when the array is a lot larger than N.
290 > *
291 > * @param array The unsorted array.
292 > * @param compare A sort function for the elements.
293 > * @param n The number of elements to return.
294 > * @return The first n elements from array when sorted with compare.
295 > */
296 > export function top<T>(array: ReadonlyArray<T>, compare: (a: T, b: T) => number, n: number): T[] {
297 if (n === 0) {
298 return [];
302 return result;
303 }
304 > arrays.ts
305 > /**
306 > * Asynchronous variant of `top()` allowing for splitting up work in batches between which the event loop can run.
307 > *
308 > * Returns the top N elements from the array.
309 > *
310 > * Faster than sorting the entire array when the array is a lot larger than N.
311 > *
312 > * @param array The unsorted array.
313 > * @param compare A sort function for the elements.
314 > * @param n The number of elements to return.
315 > * @param batch The number of elements to examine before yielding to the event loop.
316 > * @return The first n elements from array when sorted with compare.
317 > */
318 > export function topAsync<T>(array: T[], compare: (a: T, b: T) => number, n: number, batch: number, token?: CancellationToken): Promise<T[]> {
319 if (n === 0) {
320 return Promise.resolve([]);
339 });
340 }
341 > arrays.ts
342 function topStep<T>(array: ReadonlyArray<T>, compare: (a: T, b: T) => number, result: T[], i: number, m: number): void {
343 for (const n = result.length; i < m; i++) {
350 }
351 }
352 > arrays.ts
353 > /**
354 > * @returns New array with all falsy values removed. The original array IS NOT modified.
355 > */
356 > export function coalesce<T>(array: ReadonlyArray<T | undefined | null>): T[] {
357 return array.filter((e): e is T => !!e);
358 }
359 > arrays.ts
360 > /**
361 > * Remove all falsy values from `array`. The original array IS modified.
362 > */
363 > export function coalesceInPlace<T>(array: Array<T | undefined | null>): asserts array is Array<T> {
364 let to = 0;
365 for (let i = 0; i < array.length; i++) {
371 array.length = to;
372 }
373 > arrays.ts
374 > /**
375 > * @deprecated Use `Array.copyWithin` instead
376 > */
377 > export function move(array: unknown[], from: number, to: number): void {
378 array.splice(to, 0, array.splice(from, 1)[0]);
379 }
380 > arrays.ts
381 > /**
382 > * @returns false if the provided object is an array and not empty.
383 > */
384 > export function isFalsyOrEmpty(obj: unknown): boolean {
385 return !Array.isArray(obj) || obj.length === 0;
386 }
387 > arrays.ts
388 > /**
389 > * @returns True if the provided object is an array and has at least one element.
390 > */
391 > export function isNonEmptyArray<T>(obj: T[] | undefined | null): obj is T[];
392 > export function isNonEmptyArray<T>(obj: readonly T[] | undefined | null): obj is readonly T[];
393 > export function isNonEmptyArray<T>(obj: T[] | readonly T[] | undefined | null): obj is T[] | readonly T[] {
394 return Array.isArray(obj) && obj.length > 0;
395 }
396 > arrays.ts
397 > /**
398 > * Removes duplicates from the given array. The optional keyFn allows to specify
399 > * how elements are checked for equality by returning an alternate value for each.
400 > */
401 > export function distinct<T>(array: ReadonlyArray<T>, keyFn: (value: T) => unknown = value => value): T[] {
402 > const seen = new Set<any>(); arrays.ts
403 >
404 > return array.filter(element => {
405 > const key = keyFn(element); arrays.ts
406 > if (seen.has(key)) {
407 return false;
408 }
409 > seen.add(key); arrays.ts
410 > return true;
411 > }); arrays.ts
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/editor/common/languages/languageConfiguration.ts 330 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageConfiguration.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 { StandardTokenType } from '../encodedTokenAttributes.js';
8 > import { ScopedLineTokens } from './supports.js';
9 >
10 > /**
11 > * Configuration for line comments.
12 > */
13 > export interface LineCommentConfig {
14 > /**
15 > * The line comment token, like `//`
16 > */
17 > comment: string;
18 > /**
19 > * Whether the comment token should not be indented and placed at the first column.
20 > * Defaults to false.
21 > */
22 > noIndent?: boolean;
23 > }
24 >
25 > /**
26 > * Describes how comments for a language work.
27 > */
28 > export interface CommentRule {
29 > /**
30 > * The line comment token, like `// this is a comment`.
31 > * Can be a string or an object with comment and optional noIndent properties.
32 > */
33 > lineComment?: string | LineCommentConfig | null;
34 > /**
35 > * The block comment character pair, like `/* block comment *&#47;`
36 > */
37 > blockComment?: CharacterPair | null;
38 > }
39 >
40 > /**
41 > * The language configuration interface defines the contract between extensions and
42 > * various editor features, like automatic bracket insertion, automatic indentation etc.
43 > */
44 > export interface LanguageConfiguration {
45 > /**
46 > * The language's comment settings.
47 > */
48 > comments?: CommentRule;
49 > /**
50 > * The language's brackets.
51 > * This configuration implicitly affects pressing Enter around these brackets.
52 > */
53 > brackets?: CharacterPair[];
54 > /**
55 > * The language's word definition.
56 > * If the language supports Unicode identifiers (e.g. JavaScript), it is preferable
57 > * to provide a word definition that uses exclusion of known separators.
58 > * e.g.: A regex that matches anything except known separators (and dot is allowed to occur in a floating point number):
59 > * /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g
60 > */
61 > wordPattern?: RegExp;
62 > /**
63 > * The language's indentation settings.
64 > */
65 > indentationRules?: IndentationRule;
66 > /**
67 > * The language's rules to be evaluated when pressing Enter.
68 > */
69 > onEnterRules?: OnEnterRule[];
70 > /**
71 > * The language's auto closing pairs. The 'close' character is automatically inserted with the
72 > * 'open' character is typed. If not set, the configured brackets will be used.
73 > */
74 > autoClosingPairs?: IAutoClosingPairConditional[];
75 > /**
76 > * The language's surrounding pairs. When the 'open' character is typed on a selection, the
77 > * selected string is surrounded by the open and close characters. If not set, the autoclosing pairs
78 > * settings will be used.
79 > */
80 > surroundingPairs?: IAutoClosingPair[];
81 > /**
82 > * Defines a list of bracket pairs that are colorized depending on their nesting level.
83 > * If not set, the configured brackets will be used.
84 > */
85 > colorizedBracketPairs?: CharacterPair[];
86 > /**
87 > * Defines what characters must be after the cursor for bracket or quote autoclosing to occur when using the \'languageDefined\' autoclosing setting.
88 > *
89 > * This is typically the set of characters which can not start an expression, such as whitespace, closing brackets, non-unary operators, etc.
90 > */
91 > autoCloseBefore?: string;
92 >
93 > /**
94 > * The language's folding rules.
95 > */
96 > folding?: FoldingRules;
97 >
98 > /**
99 > * **Deprecated** Do not use.
100 > *
101 > * @deprecated Will be replaced by a better API soon.
102 > */
103 > __electricCharacterSupport?: {
104 > docComment?: IDocComment;
105 > };
106 > }
107 >
108 > /**
109 > * @internal
110 > */
111 > type OrUndefined<T> = { [P in keyof T]: T[P] | undefined };
112 >
113 > /**
114 > * @internal
115 > */
116 > export type ExplicitLanguageConfiguration = OrUndefined<Required<LanguageConfiguration>>;
117 >
118 > /**
119 > * Describes indentation rules for a language.
120 > */
121 > export interface IndentationRule {
122 > /**
123 > * If a line matches this pattern, then all the lines after it should be unindented once (until another rule matches).
124 > */
125 > decreaseIndentPattern: RegExp;
126 > /**
127 > * If a line matches this pattern, then all the lines after it should be indented once (until another rule matches).
128 > */
129 > increaseIndentPattern: RegExp;
130 > /**
131 > * If a line matches this pattern, then **only the next line** after it should be indented once.
132 > */
133 > indentNextLinePattern?: RegExp | null;
134 > /**
135 > * If a line matches this pattern, then its indentation should not be changed and it should not be evaluated against the other rules.
136 > */
137 > unIndentedLinePattern?: RegExp | null;
138 >
139 > }
140 >
141 > /**
142 > * Describes language specific folding markers such as '#region' and '#endregion'.
143 > * The start and end regexes will be tested against the contents of all lines and must be designed efficiently:
144 > * - the regex should start with '^'
145 > */
146 > export interface FoldingMarkers {
147 > start: RegExp;
148 > end: RegExp;
149 > }
150 >
151 > /**
152 > * Describes folding rules for a language.
153 > */
154 > export interface FoldingRules {
155 > /**
156 > * Used by the indentation based strategy to decide whether empty lines belong to the previous or the next block.
157 > * A language adheres to the off-side rule if blocks in that language are expressed by their indentation.
158 > * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information.
159 > * If not set, `false` is used and empty lines belong to the previous block.
160 > */
161 > offSide?: boolean;
162 >
163 > /**
164 > * Region markers used by the language.
165 > */
166 > markers?: FoldingMarkers;
167 > }
168 >
169 > /**
170 > * Describes a rule to be evaluated when pressing Enter.
171 > */
172 > export interface OnEnterRule {
173 > /**
174 > * This rule will only execute if the text before the cursor matches this regular expression.
175 > */
176 > beforeText: RegExp;
177 > /**
178 > * This rule will only execute if the text after the cursor matches this regular expression.
179 > */
180 > afterText?: RegExp;
181 > /**
182 > * This rule will only execute if the text above the this line matches this regular expression.
183 > */
184 > previousLineText?: RegExp;
185 > /**
186 > * The action to execute.
187 > */
188 > action: EnterAction;
189 > }
190 >
191 > /**
192 > * Definition of documentation comments (e.g. Javadoc/JSdoc)
193 > */
194 > export interface IDocComment {
195 > /**
196 > * The string that starts a doc comment (e.g. '/**')
197 > */
198 > open: string;
199 > /**
200 > * The string that appears on the last line and closes the doc comment (e.g. ' * /').
201 > */
202 > close?: string;
203 > }
204 >
205 > /**
206 > * A tuple of two characters, like a pair of
207 > * opening and closing brackets.
208 > */
209 > export type CharacterPair = [string, string];
210 >
211 > export interface IAutoClosingPair {
212 > open: string;
213 > close: string;
214 > }
215 >
216 > export interface IAutoClosingPairConditional extends IAutoClosingPair {
217 > notIn?: string[];
218 > }
219 >
220 > /**
221 > * Describes what to do with the indentation when pressing Enter.
222 > */
223 > export enum IndentAction {
224 > /**
225 > * Insert new line and copy the previous line's indentation.
226 > */
227 > None = 0,
228 > /**
229 > * Insert new line and indent once (relative to the previous line's indentation).
230 > */
231 > Indent = 1,
232 > /**
233 > * Insert two new lines:
234 > * - the first one indented which will hold the cursor
235 > * - the second one at the same indentation level
236 > */
237 > IndentOutdent = 2,
238 > /**
239 > * Insert new line and outdent once (relative to the previous line's indentation).
240 > */
241 > Outdent = 3
242 > }
243 >
244 > /**
245 > * Describes what to do when pressing Enter.
246 > */
247 > export interface EnterAction {
248 > /**
249 > * Describe what to do with the indentation.
250 > */
251 > indentAction: IndentAction;
252 > /**
253 > * Describes text to be appended after the new line and after the indentation.
254 > */
255 > appendText?: string;
256 > /**
257 > * Describes the number of characters to remove from the new line's indentation.
258 > */
259 > removeText?: number;
260 > }
261 >
262 > /**
263 > * @internal
264 > */
265 > export interface CompleteEnterAction {
266 > /**
267 > * Describe what to do with the indentation.
268 > */
269 > indentAction: IndentAction;
270 > /**
271 > * Describes text to be appended after the new line and after the indentation.
272 > */
273 > appendText: string;
274 > /**
275 > * Describes the number of characters to remove from the new line's indentation.
276 > */
277 > removeText: number;
278 > /**
279 > * The line's indentation minus removeText
280 > */
281 > indentation: string;
282 > }
283 >
284 > /**
285 > * @internal
286 > */
287 > export class StandardAutoClosingPairConditional {
288 >
289 > readonly open: string;
290 > readonly close: string;
291 > private readonly _inString: boolean;
292 > private readonly _inComment: boolean;
293 > private readonly _inRegEx: boolean;
294 > private _neutralCharacter: string | null = null;
295 > private _neutralCharacterSearched: boolean = false;
296 >
297 > constructor(source: IAutoClosingPairConditional) {
298 this.open = source.open;
299 this.close = source.close;
321 }
322 }
324 > public isOK(standardToken: StandardTokenType): boolean {
325 switch (standardToken) {
326 case StandardTokenType.Other:
334 }
335 }
337 > public shouldAutoClose(context: ScopedLineTokens, column: number): boolean {
338 // Always complete on empty line
339 if (context.getTokenCount() === 0) {
345 return this.isOK(standardTokenType);
346 }
348 > private _findNeutralCharacterInRange(fromCharCode: number, toCharCode: number): string | null {
349 for (let charCode = fromCharCode; charCode <= toCharCode; charCode++) {
350 const character = String.fromCharCode(charCode);
355 return null;
356 }
358 > /**
359 > * Find a character in the range [0-9a-zA-Z] that does not appear in the open or close
360 > */
361 > public findNeutralCharacter(): string | null {
362 if (!this._neutralCharacterSearched) {
363 this._neutralCharacterSearched = true;
374 return this._neutralCharacter;
375 }
377 >
378 > /**
379 > * @internal
380 > */
381 > export class AutoClosingPairs {
382 > // it is useful to be able to get pairs using either end of open and close
383 >
384 > /** Key is first character of open */
385 > public readonly autoClosingPairsOpenByStart: Map<string, StandardAutoClosingPairConditional[]>;
386 > /** Key is last character of open */
387 > public readonly autoClosingPairsOpenByEnd: Map<string, StandardAutoClosingPairConditional[]>;
388 > /** Key is first character of close */
389 > public readonly autoClosingPairsCloseByStart: Map<string, StandardAutoClosingPairConditional[]>;
390 > /** Key is last character of close */
391 > public readonly autoClosingPairsCloseByEnd: Map<string, StandardAutoClosingPairConditional[]>;
392 > /** Key is close. Only has pairs that are a single character */
393 > public readonly autoClosingPairsCloseSingleChar: Map<string, StandardAutoClosingPairConditional[]>;
394 >
395 > constructor(autoClosingPairs: StandardAutoClosingPairConditional[]) {
396 this.autoClosingPairsOpenByStart = new Map<string, StandardAutoClosingPairConditional[]>();
397 this.autoClosingPairsOpenByEnd = new Map<string, StandardAutoClosingPairConditional[]>();
409 }
410 }
412 >
413 function appendEntry<K, V>(target: Map<K, V[]>, key: K, value: V): void {
414 if (target.has(key)) {
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/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/ast.ts 321 covered LOC · 82 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- ast.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 { CursorColumns } from '../../../core/cursorColumns.js';
8 > import { BracketKind } from '../../../languages/supports/languageBracketsConfiguration.js';
9 > import { ITextModel } from '../../../model.js';
10 > import { Length, lengthAdd, lengthGetLineCount, lengthToObj, lengthZero } from './length.js';
11 > import { SmallImmutableSet } from './smallImmutableSet.js';
12 > import { OpeningBracketId } from './tokenizer.js';
13 >
14 > export const enum AstNodeKind {
15 > Text = 0,
16 > Bracket = 1,
17 > Pair = 2,
18 > UnexpectedClosingBracket = 3,
19 > List = 4,
20 > }
21 >
22 > export type AstNode = PairAstNode | ListAstNode | BracketAstNode | InvalidBracketAstNode | TextAstNode;
23 >
24 > /**
25 > * The base implementation for all AST nodes.
26 > */
27 > abstract class BaseAstNode {
28 > public abstract readonly kind: AstNodeKind;
29 >
30 > public abstract readonly childrenLength: number;
31 >
32 > /**
33 > * Might return null even if {@link idx} is smaller than {@link BaseAstNode.childrenLength}.
34 > */
35 > public abstract getChild(idx: number): AstNode | null;
36 >
37 > /**
38 > * Try to avoid using this property, as implementations might need to allocate the resulting array.
39 > */
40 > public abstract readonly children: readonly AstNode[];
41 >
42 > /**
43 > * Represents the set of all (potentially) missing opening bracket ids in this node.
44 > * E.g. in `{ ] ) }` that set is {`[`, `(` }.
45 > */
46 > public abstract readonly missingOpeningBracketIds: SmallImmutableSet<OpeningBracketId>;
47 >
48 > /**
49 > * In case of a list, determines the height of the (2,3) tree.
50 > */
51 > public abstract readonly listHeight: number;
52 >
53 > protected _length: Length;
54 >
55 > /**
56 > * The length of the entire node, which should equal the sum of lengths of all children.
57 > */
58 > public get length(): Length {
59 return this._length;
60 }
61 > ast.ts
62 > public constructor(length: Length) {
63 this._length = length;
64 }
65 > ast.ts
66 > /**
67 > * @param openBracketIds The set of all opening brackets that have not yet been closed.
68 > */
69 > public abstract canBeReused(
70 > openBracketIds: SmallImmutableSet<OpeningBracketId>
71 > ): boolean;
72 >
73 > /**
74 > * Flattens all lists in this AST. Only for debugging.
75 > */
76 > public abstract flattenLists(): AstNode;
77 >
78 > /**
79 > * Creates a deep clone.
80 > */
81 > public abstract deepClone(): AstNode;
82 >
83 > public abstract computeMinIndentation(offset: Length, textModel: ITextModel): number;
84 > }
85 >
86 > /**
87 > * Represents a bracket pair including its child (e.g. `{ ... }`).
88 > * Might be unclosed.
89 > * Immutable, if all children are immutable.
90 > */
91 > export class PairAstNode extends BaseAstNode {
92 > public static create(
93 > openingBracket: BracketAstNode,
94 > child: AstNode | null,
95 > closingBracket: BracketAstNode | null
96 > ) {
97 > let length = openingBracket.length;
98 > if (child) {
99 > length = lengthAdd(length, child.length);
100 > }
101 > if (closingBracket) {
102 > length = lengthAdd(length, closingBracket.length);
103 > }
104 > return new PairAstNode(length, openingBracket, child, closingBracket, child ? child.missingOpeningBracketIds : SmallImmutableSet.getEmpty());
105 > }
106 >
107 > public get kind(): AstNodeKind.Pair {
108 return AstNodeKind.Pair;
109 }
110 > public get listHeight() { ast.ts
111 return 0;
112 }
113 > public get childrenLength(): number { ast.ts
114 return 3;
115 }
116 > public getChild(idx: number): AstNode | null { ast.ts
117 switch (idx) {
118 case 0: return this.openingBracket;
122 throw new Error('Invalid child index');
123 }
124 > ast.ts
125 > /**
126 > * Avoid using this property, it allocates an array!
127 > */
128 > public get children() {
129 const result: AstNode[] = [];
130 result.push(this.openingBracket);
137 return result;
138 }
139 > ast.ts
140 > private constructor(
141 length: Length,
142 public readonly openingBracket: BracketAstNode,
147 super(length);
148 }
149 > ast.ts
150 > public canBeReused(openBracketIds: SmallImmutableSet<OpeningBracketId>) {
151 if (this.closingBracket === null) {
152 // Unclosed pair ast nodes only
166 return true;
167 }
168 > ast.ts
169 > public flattenLists(): PairAstNode {
170 return PairAstNode.create(
171 this.openingBracket.flattenLists(),
174 );
175 }
176 > ast.ts
177 > public deepClone(): PairAstNode {
178 return new PairAstNode(
179 this.length,
184 );
185 }
186 > ast.ts
187 > public computeMinIndentation(offset: Length, textModel: ITextModel): number {
188 return this.child ? this.child.computeMinIndentation(lengthAdd(offset, this.openingBracket.length), textModel) : Number.MAX_SAFE_INTEGER;
189 }
190 > } ast.ts
191 >
192 > export abstract class ListAstNode extends BaseAstNode {
193 > /**
194 > * This method uses more memory-efficient list nodes that can only store 2 or 3 children.
195 > */
196 > public static create23(item1: AstNode, item2: AstNode, item3: AstNode | null, immutable: boolean = false): ListAstNode {
197 > let length = item1.length;
198 > let missingBracketIds = item1.missingOpeningBracketIds;
199 >
200 > if (item1.listHeight !== item2.listHeight) {
201 > throw new Error('Invalid list heights'); ast.ts
202 > }
203 > ast.ts
204 > length = lengthAdd(length, item2.length);
205 > missingBracketIds = missingBracketIds.merge(item2.missingOpeningBracketIds);
206 >
207 > if (item3) {
208 > if (item1.listHeight !== item3.listHeight) { ast.ts
209 > throw new Error('Invalid list heights'); ast.ts
210 > }
211 > length = lengthAdd(length, item3.length); ast.ts
212 > missingBracketIds = missingBracketIds.merge(item3.missingOpeningBracketIds);
213 > }
214 > return immutable ast.ts
215 > ? new Immutable23ListAstNode(length, item1.listHeight + 1, item1, item2, item3, missingBracketIds) ast.ts
216 > : new TwoThreeListAstNode(length, item1.listHeight + 1, item1, item2, item3, missingBracketIds); ast.ts
217 > } ast.ts
218 >
219 > public static create(items: AstNode[], immutable: boolean = false): ListAstNode {
220 if (items.length === 0) {
221 return this.getEmpty();
232 }
233 }
234 > ast.ts
235 > public static getEmpty() {
236 return new ImmutableArrayListAstNode(lengthZero, 0, [], SmallImmutableSet.getEmpty());
237 }
238 > ast.ts
239 > public get kind(): AstNodeKind.List {
240 return AstNodeKind.List;
241 }
242 > ast.ts
243 > public get missingOpeningBracketIds(): SmallImmutableSet<OpeningBracketId> {
244 return this._missingOpeningBracketIds;
245 }
246 > ast.ts
247 > private cachedMinIndentation: number = -1;
248 >
249 > /**
250 > * Use ListAstNode.create.
251 > */
252 > constructor(
253 length: Length,
254 public readonly listHeight: number,
257 super(length);
258 }
259 > ast.ts
260 > protected throwIfImmutable(): void {
261 // NOOP
262 }
263 > ast.ts
264 > protected abstract setChild(idx: number, child: AstNode): void;
265 >
266 > public makeLastElementMutable(): AstNode | undefined {
267 this.throwIfImmutable();
268 const childCount = this.childrenLength;
277 return mutable;
278 }
279 > ast.ts
280 > public makeFirstElementMutable(): AstNode | undefined {
281 this.throwIfImmutable();
282 const childCount = this.childrenLength;
291 return mutable;
292 }
293 > ast.ts
294 > public canBeReused(openBracketIds: SmallImmutableSet<OpeningBracketId>): boolean {
295 if (openBracketIds.intersects(this.missingOpeningBracketIds)) {
296 return false;
314 return lastChild.canBeReused(openBracketIds);
315 }
316 > ast.ts
317 > public handleChildrenChanged(): void {
318 this.throwIfImmutable();
319
333 this.cachedMinIndentation = -1;
334 }
335 > ast.ts
336 > public flattenLists(): ListAstNode {
337 const items: AstNode[] = [];
338 for (const c of this.children) {
346 return ListAstNode.create(items);
347 }
348 > ast.ts
349 > public computeMinIndentation(offset: Length, textModel: ITextModel): number {
350 if (this.cachedMinIndentation !== -1) {
351 return this.cachedMinIndentation;
365 return minIndentation;
366 }
367 > ast.ts
368 > /**
369 > * Creates a shallow clone that is mutable, or itself if it is already mutable.
370 > */
371 > public abstract toMutable(): ListAstNode;
372 >
373 > public abstract appendChildOfSameHeight(node: AstNode): void;
374 > public abstract unappendChild(): AstNode | undefined;
375 > public abstract prependChildOfSameHeight(node: AstNode): void;
376 > public abstract unprependChild(): AstNode | undefined;
377 > }
378 >
379 > class TwoThreeListAstNode extends ListAstNode {
380 > public get childrenLength(): number {
381 > return this._item3 !== null ? 3 : 2;
382 > }
383 > public getChild(idx: number): AstNode | null {
384 switch (idx) {
385 case 0: return this._item1;
389 throw new Error('Invalid child index');
390 }
391 > protected setChild(idx: number, node: AstNode): void { ast.ts
392 switch (idx) {
393 case 0: this._item1 = node; return;
397 throw new Error('Invalid child index');
398 }
399 > ast.ts
400 > public get children(): readonly AstNode[] {
401 return this._item3 ? [this._item1, this._item2, this._item3] : [this._item1, this._item2];
402 }
403 > ast.ts
404 > public get item1(): AstNode {
405 return this._item1;
406 }
407 > public get item2(): AstNode { ast.ts
408 return this._item2;
409 }
410 > public get item3(): AstNode | null { ast.ts
411 return this._item3;
412 }
413 > ast.ts
414 > public constructor(
415 length: Length,
416 listHeight: number,
422 super(length, listHeight, missingOpeningBracketIds);
423 }
424 > ast.ts
425 > public deepClone(): ListAstNode {
426 return new TwoThreeListAstNode(
427 this.length,
433 );
434 }
435 > ast.ts
436 > public appendChildOfSameHeight(node: AstNode): void {
437 if (this._item3) {
438 throw new Error('Cannot append to a full (2,3) tree node');
442 this.handleChildrenChanged();
443 }
444 > ast.ts
445 > public unappendChild(): AstNode | undefined {
446 if (!this._item3) {
447 throw new Error('Cannot remove from a non-full (2,3) tree node');
453 return result;
454 }
455 > ast.ts
456 > public prependChildOfSameHeight(node: AstNode): void {
457 if (this._item3) {
458 throw new Error('Cannot prepend to a full (2,3) tree node');
464 this.handleChildrenChanged();
465 }
466 > ast.ts
467 > public unprependChild(): AstNode | undefined {
468 if (!this._item3) {
469 throw new Error('Cannot remove from a non-full (2,3) tree node');
478 return result;
479 }
480 > ast.ts
481 > override toMutable(): ListAstNode {
482 return this;
483 }
484 > } ast.ts
485 >
486 > /**
487 > * Immutable, if all children are immutable.
488 > */
489 > class Immutable23ListAstNode extends TwoThreeListAstNode {
490 > override toMutable(): ListAstNode {
491 return new TwoThreeListAstNode(this.length, this.listHeight, this.item1, this.item2, this.item3, this.missingOpeningBracketIds);
492 }
493 > ast.ts
494 > protected override throwIfImmutable(): void {
495 throw new Error('this instance is immutable');
496 }
497 > } ast.ts
498 >
499 > /**
500 > * For debugging.
501 > */
502 > class ArrayListAstNode extends ListAstNode {
503 > get childrenLength(): number {
504 > return this._children.length;
505 > }
506 > getChild(idx: number): AstNode | null {
507 return this._children[idx];
508 }
509 > protected setChild(idx: number, child: AstNode): void { ast.ts
510 this._children[idx] = child;
511 }
512 > get children(): readonly AstNode[] { ast.ts
513 return this._children;
514 }
515 > ast.ts
516 > constructor(
517 length: Length,
518 listHeight: number,
522 super(length, listHeight, missingOpeningBracketIds);
523 }
524 > ast.ts
525 > deepClone(): ListAstNode {
526 const children = new Array<AstNode>(this._children.length);
527 for (let i = 0; i < this._children.length; i++) {
530 return new ArrayListAstNode(this.length, this.listHeight, children, this.missingOpeningBracketIds);
531 }
532 > ast.ts
533 > public appendChildOfSameHeight(node: AstNode): void {
534 this.throwIfImmutable();
535 this._children.push(node);
536 this.handleChildrenChanged();
537 }
538 > ast.ts
539 > public unappendChild(): AstNode | undefined {
540 this.throwIfImmutable();
541 const item = this._children.pop();
543 return item;
544 }
545 > ast.ts
546 > public prependChildOfSameHeight(node: AstNode): void {
547 this.throwIfImmutable();
548 this._children.unshift(node);
549 this.handleChildrenChanged();
550 }
551 > ast.ts
552 > public unprependChild(): AstNode | undefined {
553 this.throwIfImmutable();
554 const item = this._children.shift();
556 return item;
557 }
558 > ast.ts
559 > public override toMutable(): ListAstNode {
560 return this;
561 }
562 > } ast.ts
563 >
564 > /**
565 > * Immutable, if all children are immutable.
566 > */
567 > class ImmutableArrayListAstNode extends ArrayListAstNode {
568 > override toMutable(): ListAstNode {
569 return new ArrayListAstNode(this.length, this.listHeight, [...this.children], this.missingOpeningBracketIds);
570 }
571 > ast.ts
572 > protected override throwIfImmutable(): void {
573 throw new Error('this instance is immutable');
574 }
575 > } ast.ts
576 >
577 > const emptyArray: readonly AstNode[] = [];
578 >
579 > abstract class ImmutableLeafAstNode extends BaseAstNode {
580 > public get listHeight() {
581 return 0;
582 }
583 > public get childrenLength(): number { ast.ts
584 return 0;
585 }
586 > public getChild(idx: number): AstNode | null { ast.ts
587 return null;
588 }
589 > public get children(): readonly AstNode[] { ast.ts
590 return emptyArray;
591 }
592 > ast.ts
593 > public flattenLists(): this & AstNode {
594 return this as this & AstNode;
595 }
596 > public deepClone(): this & AstNode { ast.ts
597 return this as this & AstNode;
598 }
599 > } ast.ts
600 >
601 > export class TextAstNode extends ImmutableLeafAstNode {
602 > public get kind(): AstNodeKind.Text {
603 return AstNodeKind.Text;
604 }
605 > public get missingOpeningBracketIds(): SmallImmutableSet<OpeningBracketId> { ast.ts
606 return SmallImmutableSet.getEmpty();
607 }
608 > ast.ts
609 > public canBeReused(_openedBracketIds: SmallImmutableSet<OpeningBracketId>) {
610 return true;
611 }
612 > ast.ts
613 > public computeMinIndentation(offset: Length, textModel: ITextModel): number {
614 const start = lengthToObj(offset);
615 // Text ast nodes don't have partial indentation (ensured by the tokenizer).
633 return result;
634 }
635 > } ast.ts
636 >
637 > export class BracketAstNode extends ImmutableLeafAstNode {
638 > public static create(
639 > length: Length,
640 > bracketInfo: BracketKind,
641 > bracketIds: SmallImmutableSet<OpeningBracketId>
642 > ): BracketAstNode {
643 > const node = new BracketAstNode(length, bracketInfo, bracketIds);
644 > return node;
645 > }
646 >
647 > public get kind(): AstNodeKind.Bracket {
648 return AstNodeKind.Bracket;
649 }
650 > ast.ts
651 > public get missingOpeningBracketIds(): SmallImmutableSet<OpeningBracketId> {
652 return SmallImmutableSet.getEmpty();
653 }
654 > ast.ts
655 > private constructor(
656 length: Length,
657 public readonly bracketInfo: BracketKind,
664 super(length);
665 }
666 > ast.ts
667 > public get text() {
668 return this.bracketInfo.bracketText;
669 }
670 > ast.ts
671 > public get languageId() {
672 return this.bracketInfo.languageId;
673 }
674 > ast.ts
675 > public canBeReused(_openedBracketIds: SmallImmutableSet<OpeningBracketId>) {
676 // These nodes could be reused,
677 // but not in a general way.
679 return false;
680 }
681 > ast.ts
682 > public computeMinIndentation(offset: Length, textModel: ITextModel): number {
683 return Number.MAX_SAFE_INTEGER;
684 }
685 > } ast.ts
686 >
687 > export class InvalidBracketAstNode extends ImmutableLeafAstNode {
688 > public get kind(): AstNodeKind.UnexpectedClosingBracket {
689 return AstNodeKind.UnexpectedClosingBracket;
690 }
691 > ast.ts
692 > public readonly missingOpeningBracketIds: SmallImmutableSet<OpeningBracketId>;
693 >
694 > public constructor(closingBrackets: SmallImmutableSet<OpeningBracketId>, length: Length) {
695 super(length);
696 this.missingOpeningBracketIds = closingBrackets;
697 }
698 > ast.ts
699 > public canBeReused(openedBracketIds: SmallImmutableSet<OpeningBracketId>) {
700 return !openedBracketIds.intersects(this.missingOpeningBracketIds);
701 }
702 > ast.ts
703 > public computeMinIndentation(offset: Length, textModel: ITextModel): number {
704 return Number.MAX_SAFE_INTEGER;
705 }
706 > } ast.ts
src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts 309 covered LOC · 113 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- rbTreeBase.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 { Piece, PieceTreeBase } from './pieceTreeBase.js';
7 >
8 > export class TreeNode {
9 > parent: TreeNode;
10 > left: TreeNode;
11 > right: TreeNode;
12 > color: NodeColor;
13 >
14 > // Piece
15 > piece: Piece;
16 > size_left: number; // size of the left subtree (not inorder)
17 > lf_left: number; // line feeds cnt in the left subtree (not in order)
18 >
19 > constructor(piece: Piece, color: NodeColor) {
20 > this.piece = piece;
21 > this.color = color;
22 > this.size_left = 0;
23 > this.lf_left = 0;
24 > this.parent = this;
25 > this.left = this;
26 > this.right = this;
27 > }
28 >
29 > public next(): TreeNode {
30 > if (this.right !== SENTINEL) { rbTreeBase.ts
31 > return leftest(this.right); rbTreeBase.ts
32 > }
34 > let node: TreeNode = this;
35 >
36 > while (node.parent !== SENTINEL) {
37 > if (node.parent.left === node) { rbTreeBase.ts
38 > break; rbTreeBase.ts
39 > }
40
41 node = node.parent;
42 }
44 > if (node.parent === SENTINEL) {
45 return SENTINEL;
46 > } else { rbTreeBase.ts
47 > return node.parent; rbTreeBase.ts
48 > }
49 > } rbTreeBase.ts
51 > public prev(): TreeNode {
52 if (this.left !== SENTINEL) {
53 return righttest(this.left);
70 }
71 }
73 > public detach(): void {
74 > this.parent = null!; rbTreeBase.ts
75 > this.left = null!;
76 > this.right = null!;
77 > }
78 > } rbTreeBase.ts
79 >
80 > export const enum NodeColor {
81 > Black = 0,
82 > Red = 1,
83 > }
84 >
85 > export const SENTINEL: TreeNode = new TreeNode(null!, NodeColor.Black);
86 > SENTINEL.parent = SENTINEL;
87 > SENTINEL.left = SENTINEL;
88 > SENTINEL.right = SENTINEL;
89 > SENTINEL.color = NodeColor.Black;
90 >
91 > export function leftest(node: TreeNode): TreeNode {
92 > while (node.left !== SENTINEL) { rbTreeBase.ts
93 > node = node.left; rbTreeBase.ts
94 > }
95 > return node; rbTreeBase.ts
96 > }
98 > export function righttest(node: TreeNode): TreeNode {
99 while (node.right !== SENTINEL) {
100 node = node.right;
102 return node;
103 }
105 > function calculateSize(node: TreeNode): number { rbTreeBase.ts
106 > if (node === SENTINEL) {
107 > return 0;
108 > }
110 > return node.size_left + node.piece.length + calculateSize(node.right);
111 > }
113 > function calculateLF(node: TreeNode): number { rbTreeBase.ts
114 > if (node === SENTINEL) {
115 > return 0;
116 > }
118 > return node.lf_left + node.piece.lineFeedCnt + calculateLF(node.right);
119 > }
121 > function resetSentinel(): void { rbTreeBase.ts
122 > SENTINEL.parent = SENTINEL;
123 > }
125 > export function leftRotate(tree: PieceTreeBase, x: TreeNode) {
126 > const y = x.right; rbTreeBase.ts
127 >
128 > // fix size_left
129 > y.size_left += x.size_left + (x.piece ? x.piece.length : 0);
130 > y.lf_left += x.lf_left + (x.piece ? x.piece.lineFeedCnt : 0);
131 > x.right = y.left;
132 >
133 > if (y.left !== SENTINEL) {
134 > y.left.parent = x; rbTreeBase.ts
135 > }
136 > y.parent = x.parent; rbTreeBase.ts
137 > if (x.parent === SENTINEL) {
138 > tree.root = y; rbTreeBase.ts
139 > } else if (x.parent.left === x) { rbTreeBase.ts
140 > x.parent.left = y; rbTreeBase.ts
141 > } else { rbTreeBase.ts
142 > x.parent.right = y; rbTreeBase.ts
143 > }
144 > y.left = x; rbTreeBase.ts
145 > x.parent = y;
146 > }
148 > export function rightRotate(tree: PieceTreeBase, y: TreeNode) {
149 > const x = y.left; rbTreeBase.ts
150 > y.left = x.right;
151 > if (x.right !== SENTINEL) {
152 x.right.parent = y;
153 }
154 > x.parent = y.parent; rbTreeBase.ts
155 >
156 > // fix size_left
157 > y.size_left -= x.size_left + (x.piece ? x.piece.length : 0);
158 > y.lf_left -= x.lf_left + (x.piece ? x.piece.lineFeedCnt : 0);
159 >
160 > if (y.parent === SENTINEL) {
161 tree.root = x;
162 > } else if (y === y.parent.right) { rbTreeBase.ts
163 > y.parent.right = x; rbTreeBase.ts
164 > } else {
165 > y.parent.left = x; rbTreeBase.ts
166 > }
168 > x.right = y;
169 > y.parent = x;
170 > }
172 > export function rbDelete(tree: PieceTreeBase, z: TreeNode) {
173 > let x: TreeNode; rbTreeBase.ts
174 > let y: TreeNode;
175 >
176 > if (z.left === SENTINEL) {
177 > y = z; rbTreeBase.ts
178 > x = y.right;
179 > } else if (z.right === SENTINEL) { rbTreeBase.ts
180 y = z;
181 x = y.left;
182 > } else { rbTreeBase.ts
183 > y = leftest(z.right); rbTreeBase.ts
184 > x = y.right;
185 > }
187 > if (y === tree.root) {
188 tree.root = x;
189
196 return;
197 }
199 > const yWasRed = (y.color === NodeColor.Red);
200 >
201 > if (y === y.parent.left) {
202 > y.parent.left = x; rbTreeBase.ts
203 > } else { rbTreeBase.ts
204 > y.parent.right = x; rbTreeBase.ts
205 > }
207 > if (y === z) {
208 > x.parent = y.parent; rbTreeBase.ts
209 > recomputeTreeMetadata(tree, x);
210 > } else { rbTreeBase.ts
211 > if (y.parent === z) { rbTreeBase.ts
212 > x.parent = y; rbTreeBase.ts
213 > } else { rbTreeBase.ts
214 x.parent = y.parent;
215 }
217 > // as we make changes to x's hierarchy, update size_left of subtree first
218 > recomputeTreeMetadata(tree, x);
219 >
220 > y.left = z.left;
221 > y.right = z.right;
222 > y.parent = z.parent;
223 > y.color = z.color;
224 >
225 > if (z === tree.root) {
226 tree.root = y;
227 > } else { rbTreeBase.ts
228 > if (z === z.parent.left) { rbTreeBase.ts
229 z.parent.left = y;
230 > } else { rbTreeBase.ts
231 > z.parent.right = y; rbTreeBase.ts
232 > }
233 > } rbTreeBase.ts
235 > if (y.left !== SENTINEL) {
236 > y.left.parent = y;
237 > }
238 > if (y.right !== SENTINEL) {
239 y.right.parent = y;
240 }
241 > // update metadata rbTreeBase.ts
242 > // we replace z with y, so in this sub tree, the length change is z.item.length
243 > y.size_left = z.size_left;
244 > y.lf_left = z.lf_left;
245 > recomputeTreeMetadata(tree, y);
246 > }
248 > z.detach();
249 >
250 > if (x.parent.left === x) {
251 > const newSizeLeft = calculateSize(x); rbTreeBase.ts
252 > const newLFLeft = calculateLF(x);
253 > if (newSizeLeft !== x.parent.size_left || newLFLeft !== x.parent.lf_left) {
254 const delta = newSizeLeft - x.parent.size_left;
255 const lf_delta = newLFLeft - x.parent.lf_left;
258 updateTreeMetadata(tree, x.parent, delta, lf_delta);
259 }
260 > } rbTreeBase.ts
262 > recomputeTreeMetadata(tree, x.parent);
263 >
264 > if (yWasRed) {
265 > resetSentinel(); rbTreeBase.ts
266 > return;
267 > }
269 > // RB-DELETE-FIXUP
270 > let w: TreeNode;
271 > while (x !== tree.root && x.color === NodeColor.Black) { rbTreeBase.ts
272 if (x === x.parent.left) {
273 w = x.parent.right;
327 }
328 }
329 > x.color = NodeColor.Black; rbTreeBase.ts
330 > resetSentinel();
331 > }
333 > export function fixInsert(tree: PieceTreeBase, x: TreeNode) {
334 > recomputeTreeMetadata(tree, x); rbTreeBase.ts
335 >
336 > while (x !== tree.root && x.parent.color === NodeColor.Red) {
337 > if (x.parent === x.parent.parent.left) { rbTreeBase.ts
338 > const y = x.parent.parent.right; rbTreeBase.ts
339 >
340 > if (y.color === NodeColor.Red) {
341 > x.parent.color = NodeColor.Black; rbTreeBase.ts
342 > y.color = NodeColor.Black;
343 > x.parent.parent.color = NodeColor.Red;
344 > x = x.parent.parent;
345 > } else { rbTreeBase.ts
346 > if (x === x.parent.right) { rbTreeBase.ts
347 x = x.parent;
348 leftRotate(tree, x);
349 }
351 > x.parent.color = NodeColor.Black;
352 > x.parent.parent.color = NodeColor.Red;
353 > rightRotate(tree, x.parent.parent);
354 > }
355 > } else { rbTreeBase.ts
356 > const y = x.parent.parent.left; rbTreeBase.ts
357 >
358 > if (y.color === NodeColor.Red) {
359 > x.parent.color = NodeColor.Black; rbTreeBase.ts
360 > y.color = NodeColor.Black;
361 > x.parent.parent.color = NodeColor.Red;
362 > x = x.parent.parent;
363 > } else { rbTreeBase.ts
364 > if (x === x.parent.left) { rbTreeBase.ts
365 > x = x.parent; rbTreeBase.ts
366 > rightRotate(tree, x);
367 > }
368 > x.parent.color = NodeColor.Black; rbTreeBase.ts
369 > x.parent.parent.color = NodeColor.Red;
370 > leftRotate(tree, x.parent.parent);
371 > }
372 > } rbTreeBase.ts
373 > } rbTreeBase.ts
375 > tree.root.color = NodeColor.Black;
376 > }
378 > export function updateTreeMetadata(tree: PieceTreeBase, x: TreeNode, delta: number, lineFeedCntDelta: number): void {
379 > // node length change or line feed count change rbTreeBase.ts
380 > while (x !== tree.root && x !== SENTINEL) {
381 > if (x.parent.left === x) { rbTreeBase.ts
382 > x.parent.size_left += delta; rbTreeBase.ts
383 > x.parent.lf_left += lineFeedCntDelta;
384 > }
386 > x = x.parent;
387 > }
388 > } rbTreeBase.ts
390 > export function recomputeTreeMetadata(tree: PieceTreeBase, x: TreeNode) {
391 > let delta = 0; rbTreeBase.ts
392 > let lf_delta = 0;
393 > if (x === tree.root) {
394 > return;
395 > }
397 > // go upwards till the node whose left subtree is changed.
398 > while (x !== tree.root && x === x.parent.right) { rbTreeBase.ts
399 > x = x.parent; rbTreeBase.ts
400 > }
402 > if (x === tree.root) {
403 > // well, it means we add a node to the end (inorder) rbTreeBase.ts
404 > return;
405 > }
407 > // x is the node whose right subtree is changed.
408 > x = x.parent;
409 >
410 > delta = calculateSize(x.left) - x.size_left;
411 > lf_delta = calculateLF(x.left) - x.lf_left;
412 > x.size_left += delta;
413 > x.lf_left += lf_delta;
414 >
415 >
416 > // go upwards till root. O(logN)
417 > while (x !== tree.root && (delta !== 0 || lf_delta !== 0)) { rbTreeBase.ts
418 > if (x.parent.left === x) { rbTreeBase.ts
419 > x.parent.size_left += delta; rbTreeBase.ts
420 > x.parent.lf_left += lf_delta;
421 > }
423 > x = x.parent;
424 > }
425 > } rbTreeBase.ts
src/vs/base/common/types.ts 297 covered LOC · 30 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- network.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as errors from './errors.js';
7 > import * as platform from './platform.js';
8 > import { equalsIgnoreCase, startsWithIgnoreCase } from './strings.js';
9 > import { URI } from './uri.js';
10 > import * as paths from './path.js';
11 >
12 > export namespace Schemas {
13 >
14 > /**
15 > * A schema that is used for models that exist in memory
16 > * only and that have no correspondence on a server or such.
17 > */
18 > export const inMemory = 'inmemory';
19 >
20 > /**
21 > * A schema that is used for setting files
22 > */
23 > export const vscode = 'vscode';
24 >
25 > /**
26 > * A schema that is used for internal private files
27 > */
28 > export const internal = 'private';
29 >
30 > /**
31 > * A walk-through document.
32 > */
33 > export const walkThrough = 'walkThrough';
34 >
35 > /**
36 > * An embedded code snippet.
37 > */
38 > export const walkThroughSnippet = 'walkThroughSnippet';
39 >
40 > export const http = 'http';
41 >
42 > export const https = 'https';
43 >
44 > export const file = 'file';
45 >
46 > export const mailto = 'mailto';
47 >
48 > export const untitled = 'untitled';
49 >
50 > export const data = 'data';
51 >
52 > export const command = 'command';
53 >
54 > export const vscodeRemote = 'vscode-remote';
55 >
56 > export const vscodeRemoteResource = 'vscode-remote-resource';
57 >
58 > export const vscodeManagedRemoteResource = 'vscode-managed-remote-resource';
59 >
60 > export const vscodeUserData = 'vscode-userdata';
61 >
62 > export const vscodeCustomEditor = 'vscode-custom-editor';
63 >
64 > export const vscodeNotebookCell = 'vscode-notebook-cell';
65 > export const vscodeNotebookCellMetadata = 'vscode-notebook-cell-metadata';
66 > export const vscodeNotebookCellMetadataDiff = 'vscode-notebook-cell-metadata-diff';
67 > export const vscodeNotebookCellOutput = 'vscode-notebook-cell-output';
68 > export const vscodeNotebookCellOutputDiff = 'vscode-notebook-cell-output-diff';
69 > export const vscodeNotebookMetadata = 'vscode-notebook-metadata';
70 > export const vscodeInteractiveInput = 'vscode-interactive-input';
71 >
72 > export const vscodeSettings = 'vscode-settings';
73 >
74 > export const vscodeWorkspaceTrust = 'vscode-workspace-trust';
75 >
76 > export const vscodeTerminal = 'vscode-terminal';
77 >
78 > /** Scheme used for the image carousel editor. */
79 > export const vscodeImageCarousel = 'vscode-image-carousel';
80 >
81 > /** Scheme used for code blocks in chat. */
82 > export const vscodeChatCodeBlock = 'vscode-chat-code-block';
83 >
84 > /** Scheme used for LHS of code compare (aka diff) blocks in chat. */
85 > export const vscodeChatCodeCompareBlock = 'vscode-chat-code-compare-block';
86 >
87 > /** Scheme used for the chat input editor. */
88 > export const vscodeChatEditor = 'vscode-chat-editor';
89 >
90 > /** Scheme used for the chat input part */
91 > export const vscodeChatInput = 'chatSessionInput';
92 >
93 > /** Scheme used for local chat session content */
94 > export const vscodeLocalChatSession = 'vscode-chat-session';
95 >
96 > /**
97 > * Scheme used internally for webviews that aren't linked to a resource (i.e. not custom editors)
98 > */
99 > export const webviewPanel = 'webview-panel';
100 >
101 > /**
102 > * Scheme used for loading the wrapper html and script in webviews.
103 > */
104 > export const vscodeWebview = 'vscode-webview';
105 >
106 > /**
107 > * Scheme used for integrated browser tabs using WebContentsView.
108 > */
109 > export const vscodeBrowser = 'vscode-browser';
110 >
111 > /**
112 > * Scheme used for extension pages
113 > */
114 > export const extension = 'extension';
115 >
116 > /**
117 > * Scheme used as a replacement of `file` scheme to load
118 > * files with our custom protocol handler (desktop only).
119 > */
120 > export const vscodeFileResource = 'vscode-file';
121 >
122 > /**
123 > * Scheme used for temporary resources
124 > */
125 > export const tmp = 'tmp';
126 >
127 > /**
128 > * Scheme used vs live share
129 > */
130 > export const vsls = 'vsls';
131 >
132 > /**
133 > * Scheme used for the Source Control commit input's text document
134 > */
135 > export const vscodeSourceControl = 'vscode-scm';
136 >
137 > /**
138 > * Scheme used for input box for creating comments.
139 > */
140 > export const commentsInput = 'comment';
141 >
142 > /**
143 > * Scheme used for special rendering of settings in the release notes
144 > */
145 > export const codeSetting = 'code-setting';
146 >
147 > /**
148 > * Scheme used for output panel resources
149 > */
150 > export const outputChannel = 'output';
151 >
152 > /**
153 > * Scheme used for the accessible view
154 > */
155 > export const accessibleView = 'accessible-view';
156 >
157 > /**
158 > * Used for snapshots of chat edits
159 > */
160 > export const chatEditingSnapshotScheme = 'chat-editing-snapshot-text-model';
161 > export const chatEditingModel = 'chat-editing-text-model';
162 >
163 > /**
164 > * Used for rendering multidiffs in copilot agent sessions
165 > */
166 > export const copilotPr = 'copilot-pr';
167 > }
168 >
169 > export function matchesScheme(target: URI | string, scheme: string): boolean {
170 if (URI.isUri(target)) {
171 return equalsIgnoreCase(target.scheme, scheme);
174 }
175 }
176 > network.ts
177 > export function matchesSomeScheme(target: URI | string, ...schemes: string[]): boolean {
178 return schemes.some(scheme => matchesScheme(target, scheme));
179 }
180 > network.ts
181 > export const connectionTokenCookieName = 'vscode-tkn';
182 > export const connectionTokenQueryName = 'tkn';
183 >
184 > class RemoteAuthoritiesImpl {
185 > private readonly _hosts: { [authority: string]: string | undefined } = Object.create(null);
186 > private readonly _ports: { [authority: string]: number | undefined } = Object.create(null);
187 > private readonly _connectionTokens: { [authority: string]: string | undefined } = Object.create(null);
188 > private _preferredWebSchema: 'http' | 'https' = 'http';
189 > private _delegate: ((uri: URI) => URI) | null = null;
190 > private _serverRootPath: string = '/';
191 >
192 > setPreferredWebSchema(schema: 'http' | 'https') {
193 this._preferredWebSchema = schema;
194 }
195 > network.ts
196 > setDelegate(delegate: (uri: URI) => URI): void {
197 this._delegate = delegate;
198 }
199 > network.ts
200 > setServerRootPath(product: { quality?: string; commit?: string }, serverBasePath: string | undefined): void {
201 this._serverRootPath = paths.posix.join(serverBasePath ?? '/', getServerProductSegment(product));
202 }
203 > network.ts
204 > getServerRootPath(): string {
205 return this._serverRootPath;
206 }
207 > network.ts
208 > private get _remoteResourcesPath(): string {
209 return paths.posix.join(this._serverRootPath, Schemas.vscodeRemoteResource);
210 }
211 > network.ts
212 > set(authority: string, host: string, port: number): void {
213 this._hosts[authority] = host;
214 this._ports[authority] = port;
215 }
216 > network.ts
217 > setConnectionToken(authority: string, connectionToken: string): void {
218 this._connectionTokens[authority] = connectionToken;
219 }
220 > network.ts
221 > getPreferredWebSchema(): 'http' | 'https' {
222 return this._preferredWebSchema;
223 }
224 > network.ts
225 > rewrite(uri: URI): URI {
226 if (this._delegate) {
227 try {
250 });
251 }
252 > } network.ts
253 >
254 > export const RemoteAuthorities = new RemoteAuthoritiesImpl();
255 >
256 > export function getServerProductSegment(product: { quality?: string; commit?: string }) {
257 return `${product.quality ?? 'oss'}-${product.commit ?? 'dev'}`;
258 }
259 > network.ts
260 > /**
261 > * A string pointing to a path inside the app. It should not begin with ./ or ../
262 > */
263 > export type AppResourcePath = (
264 > `a${string}` | `b${string}` | `c${string}` | `d${string}` | `e${string}` | `f${string}`
265 > | `g${string}` | `h${string}` | `i${string}` | `j${string}` | `k${string}` | `l${string}`
266 > | `m${string}` | `n${string}` | `o${string}` | `p${string}` | `q${string}` | `r${string}`
267 > | `s${string}` | `t${string}` | `u${string}` | `v${string}` | `w${string}` | `x${string}`
268 > | `y${string}` | `z${string}`
269 > );
270 >
271 > export const builtinExtensionsPath: AppResourcePath = 'vs/../../extensions';
272 > export const nodeModulesPath: AppResourcePath = 'vs/../../node_modules';
273 > export const nodeModulesAsarPath: AppResourcePath = 'vs/../../node_modules.asar';
274 > export const nodeModulesAsarUnpackedPath: AppResourcePath = 'vs/../../node_modules.asar.unpacked';
275 >
276 > export const VSCODE_AUTHORITY = 'vscode-app';
277 >
278 > class FileAccessImpl {
279 >
280 > private static readonly FALLBACK_AUTHORITY = VSCODE_AUTHORITY;
281 >
282 > /**
283 > * Returns a URI to use in contexts where the browser is responsible
284 > * for loading (e.g. fetch()) or when used within the DOM.
285 > *
286 > * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context.
287 > */
288 > asBrowserUri(resourcePath: AppResourcePath | ''): URI {
289 const uri = this.toUri(resourcePath);
290 return this.uriToBrowserUri(uri);
291 }
292 > network.ts
293 > /**
294 > * Returns a URI to use in contexts where the browser is responsible
295 > * for loading (e.g. fetch()) or when used within the DOM.
296 > *
297 > * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context.
298 > */
299 > uriToBrowserUri(uri: URI): URI {
300 // Handle remote URIs via `RemoteAuthorities`
301 if (uri.scheme === Schemas.vscodeRemote) {
328 return uri;
329 }
330 > network.ts
331 > /**
332 > * Returns the `file` URI to use in contexts where node.js
333 > * is responsible for loading.
334 > */
335 > asFileUri(resourcePath: AppResourcePath | ''): URI {
336 const uri = this.toUri(resourcePath);
337 return this.uriToFileUri(uri);
338 }
339 > network.ts
340 > /**
341 > * Returns the `file` URI to use in contexts where node.js
342 > * is responsible for loading.
343 > */
344 > uriToFileUri(uri: URI): URI {
345 // Only convert the URI if it is `vscode-file:` scheme
346 if (uri.scheme === Schemas.vscodeFileResource) {
358 return uri;
359 }
360 > network.ts
361 > private toUri(uriOrModule: URI | string): URI {
362 if (URI.isUri(uriOrModule)) {
363 return uriOrModule;
379 throw new Error('Cannot determine URI for module id!');
380 }
381 > } network.ts
382 >
383 > export const FileAccess = new FileAccessImpl();
384 >
385 > export const CacheControlheaders: Record<string, string> = Object.freeze({
386 > 'Cache-Control': 'no-cache, no-store'
387 > });
388 >
389 > export const DocumentPolicyheaders: Record<string, string> = Object.freeze({
390 > 'Document-Policy': 'include-js-call-stacks-in-crash-reports'
391 > });
392 >
393 > export namespace COI {
394 >
395 > const coiHeaders = new Map<'3' | '2' | '1' | string, Record<string, string>>([
396 > ['1', { 'Cross-Origin-Opener-Policy': 'same-origin' }],
397 > ['2', { 'Cross-Origin-Embedder-Policy': 'require-corp' }],
398 > ['3', { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp' }],
399 > ]);
400 >
401 > export const CoopAndCoep = Object.freeze(coiHeaders.get('3'));
402 >
403 > const coiSearchParamName = 'vscode-coi';
404 >
405 > /**
406 > * Extract desired headers from `vscode-coi` invocation
407 > */
408 > export function getHeadersFromQuery(url: string | URI | URL): Record<string, string> | undefined {
409 let params: URLSearchParams | undefined;
410 if (typeof url === 'string') {
421 return coiHeaders.get(value);
422 }
423 > network.ts
424 > /**
425 > * Add the `vscode-coi` query attribute based on wanting `COOP` and `COEP`. Will be a noop when `crossOriginIsolated`
426 > * isn't enabled the current context
427 > */
428 > export function addSearchParam(urlOrSearch: URLSearchParams | Record<string, string>, coop: boolean, coep: boolean): void {
429 if (!(globalThis as typeof globalThis & { crossOriginIsolated?: boolean }).crossOriginIsolated) {
430 // depends on the current context being COI
src/vs/base/common/uri.ts 283 covered LOC · 27 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 {
16
47 }
48 }
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 {
55 if (!scheme && !_strict) {
58 return scheme;
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 {
63
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
163 if (typeof schemeOrData === 'object') {
180 }
181 }
182 > uri.ts
183 > // ---- filesystem path -----------------------
184 >
185 > /**
186 > * Returns a string representing the corresponding file system path of this URI.
187 > * Will handle UNC paths, normalizes windows drive letters to lower-case, and uses the
188 > * platform specific path separator.
189 > *
190 > * * Will *not* validate the path for invalid characters and semantics.
191 > * * Will *not* look at the scheme of this URI.
192 > * * The result shall *not* be used for display purposes but for accessing a file on disk.
193 > *
194 > *
195 > * The *difference* to `URI#path` is the use of the platform specific separator and the handling
196 > * of UNC paths. See the below sample of a file-uri with an authority (UNC path).
197 > *
198 > * ```ts
199 > const u = URI.parse('file://server/c$/folder/file.txt')
200 > u.authority === 'server'
201 > u.path === '/shares/c$/file.txt'
202 > u.fsPath === '\\server\c$\folder\file.txt'
203 > ```
204 > *
205 > * Using `URI#path` to read a file (using fs-apis) would not be enough because parts of the path,
206 > * namely the server name, would be missing. Therefore `URI#fsPath` exists - it's sugar to ease working
207 > * with URIs that represent files on disk (`file` scheme).
208 > */
209 > get fsPath(): string {
210 // if (this.scheme !== 'file') {
211 // console.warn(`[UriError] calling fsPath with scheme ${this.scheme}`);
213 return uriToFsPath(this, false);
214 }
215 > uri.ts
216 > // ---- modify to new -------------------------
217 >
218 > with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI {
219
220 if (!change) {
260 return new Uri(scheme, authority, path, query, fragment);
261 }
262 > uri.ts
263 > // ---- parse & validate ------------------------
264 >
265 > /**
266 > * Creates a new URI from a string, e.g. `http://www.example.com/some/path`,
267 > * `file:///usr/home`, or `scheme:with/path`.
268 > *
269 > * @param value A string which represents an URI (see `URI#toString`).
270 > */
271 > static parse(value: string, _strict: boolean = false): URI {
272 const match = _regexp.exec(value);
273 if (!match) {
283 );
284 }
285 > uri.ts
286 > /**
287 > * Creates a new URI from a file system path, e.g. `c:\my\files`,
288 > * `/usr/home`, or `\\server\share\some\path`.
289 > *
290 > * The *difference* between `URI#parse` and `URI#file` is that the latter treats the argument
291 > * as path, not as stringified-uri. E.g. `URI.file(path)` is **not the same as**
292 > * `URI.parse('file://' + path)` because the path might contain characters that are
293 > * interpreted (# and ?). See the following sample:
294 > * ```ts
295 > const good = URI.file('/coding/c#/project1');
296 > good.scheme === 'file';
297 > good.path === '/coding/c#/project1';
298 > good.fragment === '';
299 > const bad = URI.parse('file://' + '/coding/c#/project1');
300 > bad.scheme === 'file';
301 > bad.path === '/coding/c'; // path is now broken
302 > bad.fragment === '/project1';
303 > ```
304 > *
305 > * @param path A file system path (see `URI#fsPath`)
306 > */
307 > static file(path: string): URI {
308
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 {
456
457 _formatted: string | null = null;
458 _fsPath: string | null = null;
459 > uri.ts
460 > override get fsPath(): string {
461 if (!this._fsPath) {
462 this._fsPath = uriToFsPath(this, false);
464 return this._fsPath;
465 }
466 > uri.ts
467 > override toString(skipEncoding: boolean = false): string {
468 if (!skipEncoding) {
469 if (!this._formatted) {
476 }
477 }
478 > uri.ts
479 > override toJSON(): UriComponents {
480 // eslint-disable-next-line local/code-no-dangerous-type-assertions
481 const res = <UriState>{
512 return res;
513 }
514 > } uri.ts
515 >
516 > // reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2
517 > const encodeTable: { [ch: number]: string } = {
518 > [CharCode.Colon]: '%3A', // gen-delims
519 > [CharCode.Slash]: '%2F',
520 > [CharCode.QuestionMark]: '%3F',
521 > [CharCode.Hash]: '%23',
522 > [CharCode.OpenSquareBracket]: '%5B',
523 > [CharCode.CloseSquareBracket]: '%5D',
524 > [CharCode.AtSign]: '%40',
525 >
526 > [CharCode.ExclamationMark]: '%21', // sub-delims
527 > [CharCode.DollarSign]: '%24',
528 > [CharCode.Ampersand]: '%26',
529 > [CharCode.SingleQuote]: '%27',
530 > [CharCode.OpenParen]: '%28',
531 > [CharCode.CloseParen]: '%29',
532 > [CharCode.Asterisk]: '%2A',
533 > [CharCode.Plus]: '%2B',
534 > [CharCode.Comma]: '%2C',
535 > [CharCode.Semicolon]: '%3B',
536 > [CharCode.Equals]: '%3D',
537 >
538 > [CharCode.Space]: '%20',
539 > };
540 >
541 function encodeURIComponentFast(uriComponent: string, isPath: boolean, isAuthority: boolean): string {
542 let res: string | undefined = undefined;
602 return res !== undefined ? res : uriComponent;
603 }
604 > uri.ts
605 function encodeURIComponentMinimal(path: string): string {
606 let res: string | undefined = undefined;
620 return res !== undefined ? res : path;
621 }
622 > uri.ts
623 > /**
624 > * Compute `fsPath` for the given uri
625 > */
626 > export function uriToFsPath(uri: URI, keepDriveLetterCasing: boolean): string {
627
628 let value: string;
650 return value;
651 }
652 > uri.ts
653 > /**
654 > * Create the external version of a uri
655 > */
656 function _asFormatted(uri: URI, skipEncoding: boolean): string {
657
723 return res;
724 }
725 > uri.ts
726 > // --- decode
727 >
728 function decodeURIComponentGraceful(str: string): string {
729 try {
737 }
738 }
739 > uri.ts
740 > const _rEncodedAsHex = /(%[0-9A-Za-z][0-9A-Za-z])+/g;
741 >
742 function percentDecode(str: string): string {
743 if (!str.match(_rEncodedAsHex)) {
746 return str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match));
747 }
748 > uri.ts
749 > /**
750 > * Mapped-type that replaces all occurrences of URI with UriComponents
751 > */
752 > export type UriDto<T> = { [K in keyof T]: T[K] extends URI
753 > ? UriComponents
754 > : UriDto<T[K]> };
src/vs/editor/common/model/intervalTree.ts 277 covered LOC · 44 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- intervalTree.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 { Range } from '../core/range.js';
7 > import { TrackedRangeStickiness, TrackedRangeStickiness as ActualTrackedRangeStickiness } from '../model.js';
8 > import { ModelDecorationOptions } from './textModel.js';
9 >
10 > //
11 > // The red-black tree is based on the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
12 > //
13 >
14 > export const enum ClassName {
15 > EditorHintDecoration = 'squiggly-hint',
16 > EditorInfoDecoration = 'squiggly-info',
17 > EditorWarningDecoration = 'squiggly-warning',
18 > EditorErrorDecoration = 'squiggly-error',
19 > EditorUnnecessaryDecoration = 'squiggly-unnecessary',
20 > EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary',
21 > EditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated'
22 > }
23 >
24 > export const enum NodeColor {
25 > Black = 0,
26 > Red = 1,
27 > }
28 >
29 > const enum Constants {
30 > ColorMask = 0b00000001,
31 > ColorMaskInverse = 0b11111110,
32 > ColorOffset = 0,
33 >
34 > IsVisitedMask = 0b00000010,
35 > IsVisitedMaskInverse = 0b11111101,
36 > IsVisitedOffset = 1,
37 >
38 > IsForValidationMask = 0b00000100,
39 > IsForValidationMaskInverse = 0b11111011,
40 > IsForValidationOffset = 2,
41 >
42 > StickinessMask = 0b00011000,
43 > StickinessMaskInverse = 0b11100111,
44 > StickinessOffset = 3,
45 >
46 > CollapseOnReplaceEditMask = 0b00100000,
47 > CollapseOnReplaceEditMaskInverse = 0b11011111,
48 > CollapseOnReplaceEditOffset = 5,
49 >
50 > IsMarginMask = 0b01000000,
51 > IsMarginMaskInverse = 0b10111111,
52 > IsMarginOffset = 6,
53 >
54 > AffectsFontMask = 0b10000000,
55 > AffectsFontMaskInverse = 0b01111111,
56 > AffectsFontOffset = 7,
57 >
58 > /**
59 > * Due to how deletion works (in order to avoid always walking the right subtree of the deleted node),
60 > * the deltas for nodes can grow and shrink dramatically. It has been observed, in practice, that unless
61 > * the deltas are corrected, integer overflow will occur.
62 > *
63 > * The integer overflow occurs when 53 bits are used in the numbers, but we will try to avoid it as
64 > * a node's delta gets below a negative 30 bits number.
65 > *
66 > * MIN SMI (SMall Integer) as defined in v8.
67 > * one bit is lost for boxing/unboxing flag.
68 > * one bit is lost for sign flag.
69 > * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values
70 > */
71 > MIN_SAFE_DELTA = -(1 << 30),
72 > /**
73 > * MAX SMI (SMall Integer) as defined in v8.
74 > * one bit is lost for boxing/unboxing flag.
75 > * one bit is lost for sign flag.
76 > * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values
77 > */
78 > MAX_SAFE_DELTA = 1 << 30,
79 > }
80 >
81 > export function getNodeColor(node: IntervalNode): NodeColor {
82 return ((node.metadata & Constants.ColorMask) >>> Constants.ColorOffset);
83 }
84 > function setNodeColor(node: IntervalNode, color: NodeColor): void { intervalTree.ts
85 > node.metadata = (
86 > (node.metadata & Constants.ColorMaskInverse) | (color << Constants.ColorOffset)
87 > );
88 > }
89 function getNodeIsVisited(node: IntervalNode): boolean {
90 return ((node.metadata & Constants.IsVisitedMask) >>> Constants.IsVisitedOffset) === 1;
91 }
92 > function setNodeIsVisited(node: IntervalNode, value: boolean): void { intervalTree.ts
93 > node.metadata = (
94 > (node.metadata & Constants.IsVisitedMaskInverse) | ((value ? 1 : 0) << Constants.IsVisitedOffset)
95 > );
96 > }
97 function getNodeIsForValidation(node: IntervalNode): boolean {
98 return ((node.metadata & Constants.IsForValidationMask) >>> Constants.IsForValidationOffset) === 1;
99 }
100 > function setNodeIsForValidation(node: IntervalNode, value: boolean): void { intervalTree.ts
101 > node.metadata = (
102 > (node.metadata & Constants.IsForValidationMaskInverse) | ((value ? 1 : 0) << Constants.IsForValidationOffset)
103 > );
104 > }
105 function getNodeIsInGlyphMargin(node: IntervalNode): boolean {
106 return ((node.metadata & Constants.IsMarginMask) >>> Constants.IsMarginOffset) === 1;
107 }
108 > function setNodeIsInGlyphMargin(node: IntervalNode, value: boolean): void { intervalTree.ts
109 > node.metadata = (
110 > (node.metadata & Constants.IsMarginMaskInverse) | ((value ? 1 : 0) << Constants.IsMarginOffset)
111 > );
112 > }
113 function getNodeAffectsFont(node: IntervalNode): boolean {
114 return ((node.metadata & Constants.AffectsFontMask) >>> Constants.AffectsFontOffset) === 1;
115 }
116 > function setNodeAffectsFont(node: IntervalNode, value: boolean): void { intervalTree.ts
117 > node.metadata = (
118 > (node.metadata & Constants.AffectsFontMaskInverse) | ((value ? 1 : 0) << Constants.AffectsFontOffset)
119 > );
120 > }
121 function getNodeStickiness(node: IntervalNode): TrackedRangeStickiness {
122 return ((node.metadata & Constants.StickinessMask) >>> Constants.StickinessOffset);
123 }
124 > function _setNodeStickiness(node: IntervalNode, stickiness: TrackedRangeStickiness): void { intervalTree.ts
125 > node.metadata = (
126 > (node.metadata & Constants.StickinessMaskInverse) | (stickiness << Constants.StickinessOffset)
127 > );
128 > }
129 function getCollapseOnReplaceEdit(node: IntervalNode): boolean {
130 return ((node.metadata & Constants.CollapseOnReplaceEditMask) >>> Constants.CollapseOnReplaceEditOffset) === 1;
131 }
132 > function setCollapseOnReplaceEdit(node: IntervalNode, value: boolean): void { intervalTree.ts
133 > node.metadata = (
134 > (node.metadata & Constants.CollapseOnReplaceEditMaskInverse) | ((value ? 1 : 0) << Constants.CollapseOnReplaceEditOffset)
135 > );
136 > }
137 > export function setNodeStickiness(node: IntervalNode, stickiness: ActualTrackedRangeStickiness): void {
138 _setNodeStickiness(node, <number>stickiness);
139 }
141 > export class IntervalNode {
142 >
143 > /**
144 > * contains binary encoded information for color, visited, isForValidation and stickiness.
145 > */
146 > public metadata: number;
147 >
148 > public parent: IntervalNode;
149 > public left: IntervalNode;
150 > public right: IntervalNode;
151 >
152 > public start: number;
153 > public end: number;
154 > public delta: number;
155 > public maxEnd: number;
156 >
157 > public id: string;
158 > public ownerId: number;
159 > public options: ModelDecorationOptions;
160 >
161 > public cachedVersionId: number;
162 > public cachedAbsoluteStart: number;
163 > public cachedAbsoluteEnd: number;
164 > public range: Range | null;
165 >
166 > constructor(id: string, start: number, end: number) {
167 > this.metadata = 0;
168 >
169 > this.parent = this;
170 > this.left = this;
171 > this.right = this;
172 > setNodeColor(this, NodeColor.Red);
173 >
174 > this.start = start;
175 > this.end = end;
176 > // FORCE_OVERFLOWING_TEST: this.delta = start;
177 > this.delta = 0;
178 > this.maxEnd = end;
179 >
180 > this.id = id;
181 > this.ownerId = 0;
182 > this.options = null!;
183 > setNodeIsForValidation(this, false);
184 > setNodeIsInGlyphMargin(this, false);
185 > _setNodeStickiness(this, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);
186 > setCollapseOnReplaceEdit(this, false);
187 > setNodeAffectsFont(this, false);
188 >
189 > this.cachedVersionId = 0;
190 > this.cachedAbsoluteStart = start;
191 > this.cachedAbsoluteEnd = end;
192 > this.range = null;
193 >
194 > setNodeIsVisited(this, false);
195 > }
196 >
197 > public reset(versionId: number, start: number, end: number, range: Range): void {
198 this.start = start;
199 this.end = end;
204 this.range = range;
205 }
207 > public setOptions(options: ModelDecorationOptions) {
208 this.options = options;
209 const className = this.options.className;
218 setNodeAffectsFont(this, this.options.affectsFont ?? false);
219 }
221 > public setCachedOffsets(absoluteStart: number, absoluteEnd: number, cachedVersionId: number): void {
222 if (this.cachedVersionId !== cachedVersionId) {
223 this.range = null;
227 this.cachedAbsoluteEnd = absoluteEnd;
228 }
230 > public detach(): void {
231 this.parent = null!;
232 this.left = null!;
233 this.right = null!;
234 }
235 > } intervalTree.ts
236 >
237 > export const SENTINEL: IntervalNode = new IntervalNode(null!, 0, 0);
238 > SENTINEL.parent = SENTINEL;
239 > SENTINEL.left = SENTINEL;
240 > SENTINEL.right = SENTINEL;
241 > setNodeColor(SENTINEL, NodeColor.Black);
242 >
243 > export class IntervalTree {
244 >
245 > public root: IntervalNode;
246 > public requestNormalizeDelta: boolean;
247 >
248 > constructor() {
249 this.root = SENTINEL;
250 this.requestNormalizeDelta = false;
251 }
253 > public intervalSearch(start: number, end: number, filterOwnerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {
254 if (this.root === SENTINEL) {
255 return [];
257 return intervalSearch(this, start, end, filterOwnerId, filterOutValidation, filterFontDecorations, cachedVersionId, onlyMarginDecorations);
258 }
260 > public search(filterOwnerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {
261 if (this.root === SENTINEL) {
262 return [];
264 return search(this, filterOwnerId, filterOutValidation, filterFontDecorations, cachedVersionId, onlyMarginDecorations);
265 }
267 > /**
268 > * Will not set `cachedAbsoluteStart` nor `cachedAbsoluteEnd` on the returned nodes!
269 > */
270 > public collectNodesFromOwner(ownerId: number): IntervalNode[] {
271 return collectNodesFromOwner(this, ownerId);
272 }
274 > /**
275 > * Will not set `cachedAbsoluteStart` nor `cachedAbsoluteEnd` on the returned nodes!
276 > */
277 > public collectNodesPostOrder(): IntervalNode[] {
278 return collectNodesPostOrder(this);
279 }
281 > public insert(node: IntervalNode): void {
282 rbTreeInsert(this, node);
283 this._normalizeDeltaIfNecessary();
284 }
286 > public delete(node: IntervalNode): void {
287 rbTreeDelete(this, node);
288 this._normalizeDeltaIfNecessary();
289 }
291 > public resolveNode(node: IntervalNode, cachedVersionId: number): void {
292 const initialNode = node;
293 let delta = 0;
303 initialNode.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId);
304 }
306 > public acceptReplace(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void {
307 // Our strategy is to remove all directly impacted nodes, and then add them back to the tree.
308
332 this._normalizeDeltaIfNecessary();
333 }
335 > public getAllInOrder(): IntervalNode[] {
336 return search(this, 0, false, false, 0, false);
337 }
339 > private _normalizeDeltaIfNecessary(): void {
340 if (!this.requestNormalizeDelta) {
341 return;
344 normalizeDelta(this);
345 }
346 > } intervalTree.ts
347 >
348 > //#region Delta Normalization
349 function normalizeDelta(T: IntervalTree): void {
350 let node = T.root;
384 setNodeIsVisited(T.root, false);
385 }
386 > //#endregion intervalTree.ts
387 >
388 > //#region Editing
389 >
390 > const enum MarkerMoveSemantics {
391 > MarkerDefined = 0,
392 > ForceMove = 1,
393 > ForceStay = 2
394 > }
395 >
396 function adjustMarkerBeforeColumn(markerOffset: number, markerStickToPreviousCharacter: boolean, checkOffset: number, moveSemantics: MarkerMoveSemantics): boolean {
397 if (markerOffset < checkOffset) {
409 return markerStickToPreviousCharacter;
410 }
412 > /**
413 > * This is a lot more complicated than strictly necessary to maintain the same behaviour
414 > * as when decorations were implemented using two markers.
415 > */
416 > export function nodeAcceptEdit(node: IntervalNode, start: number, end: number, textLength: number, forceMoveMarkers: boolean): void {
417 const nodeStickiness = getNodeStickiness(node);
418 const startStickToPreviousCharacter = (
489 }
490 }
492 function searchForEditing(T: IntervalTree, start: number, end: number): IntervalNode[] {
493 // https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree
561 return result;
562 }
564 function noOverlapReplace(T: IntervalTree, start: number, end: number, textLength: number): void {
565 // https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree
631 setNodeIsVisited(T.root, false);
632 }
634 > //#endregion
635 >
636 > //#region Searching
637 >
638 function collectNodesFromOwner(T: IntervalTree, ownerId: number): IntervalNode[] {
639 let node = T.root;
673 return result;
674 }
676 function collectNodesPostOrder(T: IntervalTree): IntervalNode[] {
677 let node = T.root;
708 return result;
709 }
711 function search(T: IntervalTree, filterOwnerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {
712 let node = T.root;
772 return result;
773 }
775 function intervalSearch(T: IntervalTree, intervalStart: number, intervalEnd: number, filterOwnerId: number, filterOutValidation: boolean, filterFontDecorations: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {
776 // https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree
865 return result;
866 }
868 > //#endregion
869 >
870 > //#region Insertion
871 function rbTreeInsert(T: IntervalTree, newNode: IntervalNode): IntervalNode {
872 if (T.root === SENTINEL) {
927 return newNode;
928 }
930 function treeInsert(T: IntervalTree, z: IntervalNode): void {
931 let delta: number = 0;
968 setNodeColor(z, NodeColor.Red);
969 }
970 > //#endregion intervalTree.ts
971 >
972 > //#region Deletion
973 function rbTreeDelete(T: IntervalTree, z: IntervalNode): void {
974
1154 resetSentinel();
1155 }
1157 function leftest(node: IntervalNode): IntervalNode {
1158 while (node.left !== SENTINEL) {
1161 return node;
1162 }
1164 function resetSentinel(): void {
1165 SENTINEL.parent = SENTINEL;
1168 SENTINEL.end = 0; // optional
1169 }
1170 > //#endregion intervalTree.ts
1171 >
1172 > //#region Rotations
1173 function leftRotate(T: IntervalTree, x: IntervalNode): void {
1174 const y = x.right; // set y.
1200 recomputeMaxEnd(y);
1201 }
1203 function rightRotate(T: IntervalTree, y: IntervalNode): void {
1204 const x = y.left;
1230 recomputeMaxEnd(x);
1231 }
1232 > //#endregion intervalTree.ts
1233 >
1234 > //#region max end computation
1235 >
1236 function computeMaxEnd(node: IntervalNode): number {
1237 let maxEnd = node.end;
1250 return maxEnd;
1251 }
1253 > export function recomputeMaxEnd(node: IntervalNode): void {
1254 node.maxEnd = computeMaxEnd(node);
1255 }
1257 function recomputeMaxEndWalkToRoot(node: IntervalNode): void {
1258 while (node !== SENTINEL) {
1269 }
1270 }
1272 > //#endregion
1273 >
1274 > //#region utils
1275 > export function intervalCompare(aStart: number, aEnd: number, bStart: number, bEnd: number): number {
1276 if (aStart === bStart) {
1277 return aEnd - bEnd;
src/vs/platform/undoRedo/common/undoRedoService.ts 266 covered LOC · 83 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- undoRedoService.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 { onUnexpectedError } from '../../../base/common/errors.js';
7 > import { Disposable, IDisposable, isDisposable } from '../../../base/common/lifecycle.js';
8 > import { Schemas } from '../../../base/common/network.js';
9 > import Severity from '../../../base/common/severity.js';
10 > import { URI } from '../../../base/common/uri.js';
11 > import * as nls from '../../../nls.js';
12 > import { IDialogService } from '../../dialogs/common/dialogs.js';
13 > import { InstantiationType, registerSingleton } from '../../instantiation/common/extensions.js';
14 > import { INotificationService } from '../../notification/common/notification.js';
15 > import { IPastFutureElements, IResourceUndoRedoElement, IUndoRedoElement, IUndoRedoService, IWorkspaceUndoRedoElement, ResourceEditStackSnapshot, UndoRedoElementType, UndoRedoGroup, UndoRedoSource, UriComparisonKeyComputer } from './undoRedo.js';
16 >
17 > const DEBUG = false;
18 >
19 function getResourceLabel(resource: URI): string {
20 return resource.scheme === Schemas.file ? resource.fsPath : resource.path;
21 }
23 > let stackElementCounter = 0;
24 >
25 > class ResourceStackElement {
26 > public readonly id = (++stackElementCounter);
27 > public readonly type = UndoRedoElementType.Resource;
28 > public readonly actual: IUndoRedoElement;
29 > public readonly label: string;
30 > public readonly confirmBeforeUndo: boolean;
31 >
32 > public readonly resourceLabel: string;
33 > public readonly strResource: string;
34 > public readonly resourceLabels: string[];
35 > public readonly strResources: string[];
36 > public readonly groupId: number;
37 > public readonly groupOrder: number;
38 > public readonly sourceId: number;
39 > public readonly sourceOrder: number;
40 > public isValid: boolean;
41 >
42 > constructor(actual: IUndoRedoElement, resourceLabel: string, strResource: string, groupId: number, groupOrder: number, sourceId: number, sourceOrder: number) {
43 this.actual = actual;
44 this.label = actual.label;
54 this.isValid = true;
55 }
57 > public setValid(isValid: boolean): void {
58 this.isValid = isValid;
59 }
61 > public toString(): string {
62 return `[id:${this.id}] [group:${this.groupId}] [${this.isValid ? ' VALID' : 'INVALID'}] ${this.actual.constructor.name} - ${this.actual}`;
63 }
65 >
66 > const enum RemovedResourceReason {
67 > ExternalRemoval = 0,
68 > NoParallelUniverses = 1
69 > }
70 >
71 > class ResourceReasonPair {
72 > constructor(
73 public readonly resourceLabel: string,
74 public readonly reason: RemovedResourceReason
75 ) { }
77 >
78 class RemovedResources {
79 private readonly elements = new Map<string, ResourceReasonPair>();
81 > public createMessage(): string {
82 const externalRemoval: string[] = [];
83 const noParallelUniverses: string[] = [];
109 return messages.join('\n');
110 }
112 > public get size(): number {
113 return this.elements.size;
114 }
116 > public has(strResource: string): boolean {
117 return this.elements.has(strResource);
118 }
120 > public set(strResource: string, value: ResourceReasonPair): void {
121 this.elements.set(strResource, value);
122 }
124 > public delete(strResource: string): boolean {
125 return this.elements.delete(strResource);
126 }
128 >
129 > class WorkspaceStackElement {
130 > public readonly id = (++stackElementCounter);
131 > public readonly type = UndoRedoElementType.Workspace;
132 > public readonly actual: IWorkspaceUndoRedoElement;
133 > public readonly label: string;
134 > public readonly confirmBeforeUndo: boolean;
135 >
136 > public readonly resourceLabels: string[];
137 > public readonly strResources: string[];
138 > public readonly groupId: number;
139 > public readonly groupOrder: number;
140 > public readonly sourceId: number;
141 > public readonly sourceOrder: number;
142 > public removedResources: RemovedResources | null;
143 > public invalidatedResources: RemovedResources | null;
144 >
145 > constructor(actual: IWorkspaceUndoRedoElement, resourceLabels: string[], strResources: string[], groupId: number, groupOrder: number, sourceId: number, sourceOrder: number) {
146 this.actual = actual;
147 this.label = actual.label;
156 this.invalidatedResources = null;
157 }
159 > public canSplit(): this is WorkspaceStackElement & { actual: { split(): IResourceUndoRedoElement[] } } {
160 return (typeof this.actual.split === 'function');
161 }
163 > public removeResource(resourceLabel: string, strResource: string, reason: RemovedResourceReason): void {
164 if (!this.removedResources) {
165 this.removedResources = new RemovedResources();
169 }
170 }
172 > public setValid(resourceLabel: string, strResource: string, isValid: boolean): void {
173 if (isValid) {
174 if (this.invalidatedResources) {
187 }
188 }
190 > public toString(): string {
191 return `[id:${this.id}] [group:${this.groupId}] [${this.invalidatedResources ? 'INVALID' : ' VALID'}] ${this.actual.constructor.name} - ${this.actual}`;
192 }
194 >
195 > type StackElement = ResourceStackElement | WorkspaceStackElement;
196 >
197 > class ResourceEditStack {
198 > public readonly resourceLabel: string;
199 > private readonly strResource: string;
200 > private _past: StackElement[];
201 > private _future: StackElement[];
202 > public locked: boolean;
203 > public versionId: number;
204 >
205 > constructor(resourceLabel: string, strResource: string) {
206 > this.resourceLabel = resourceLabel;
207 > this.strResource = strResource;
208 > this._past = [];
209 > this._future = [];
210 > this.locked = false;
211 > this.versionId = 1;
212 > }
213 >
214 > public dispose(): void {
215 for (const element of this._past) {
216 if (element.type === UndoRedoElementType.Workspace) {
225 this.versionId++;
226 }
228 > public toString(): string {
229 const result: string[] = [];
230 result.push(`* ${this.strResource}:`);
237 return result.join('\n');
238 }
240 > public flushAllElements(): void {
241 this._past = [];
242 this._future = [];
243 this.versionId++;
244 }
246 > public setElementsIsValid(isValid: boolean): void {
247 for (const element of this._past) {
248 if (element.type === UndoRedoElementType.Workspace) {
260 }
261 }
263 > private _setElementValidFlag(element: StackElement, isValid: boolean): void {
264 if (element.type === UndoRedoElementType.Workspace) {
265 element.setValid(this.resourceLabel, this.strResource, isValid);
268 }
269 }
271 > public setElementsValidFlag(isValid: boolean, filter: (element: IUndoRedoElement) => boolean): void {
272 for (const element of this._past) {
273 if (filter(element.actual)) {
281 }
282 }
284 > public pushElement(element: StackElement): void {
285 // remove the future
286 for (const futureElement of this._future) {
293 this.versionId++;
294 }
296 > public createSnapshot(resource: URI): ResourceEditStackSnapshot {
297 const elements: number[] = [];
298
306 return new ResourceEditStackSnapshot(resource, elements);
307 }
309 > public restoreSnapshot(snapshot: ResourceEditStackSnapshot): void {
310 const snapshotLength = snapshot.elements.length;
311 let isOK = true;
341 this.versionId++;
342 }
344 > public getElements(): IPastFutureElements {
345 const past: IUndoRedoElement[] = [];
346 const future: IUndoRedoElement[] = [];
355 return { past, future };
356 }
358 > public getClosestPastElement(): StackElement | null {
359 if (this._past.length === 0) {
360 return null;
362 return this._past[this._past.length - 1];
363 }
365 > public getSecondClosestPastElement(): StackElement | null {
366 if (this._past.length < 2) {
367 return null;
369 return this._past[this._past.length - 2];
370 }
372 > public getClosestFutureElement(): StackElement | null {
373 if (this._future.length === 0) {
374 return null;
376 return this._future[this._future.length - 1];
377 }
379 > public hasPastElements(): boolean {
380 return (this._past.length > 0);
381 }
383 > public hasFutureElements(): boolean {
384 return (this._future.length > 0);
385 }
387 > public splitPastWorkspaceElement(toRemove: WorkspaceStackElement, individualMap: Map<string, ResourceStackElement>): void {
388 for (let j = this._past.length - 1; j >= 0; j--) {
389 if (this._past[j] === toRemove) {
400 this.versionId++;
401 }
403 > public splitFutureWorkspaceElement(toRemove: WorkspaceStackElement, individualMap: Map<string, ResourceStackElement>): void {
404 for (let j = this._future.length - 1; j >= 0; j--) {
405 if (this._future[j] === toRemove) {
416 this.versionId++;
417 }
419 > public moveBackward(element: StackElement): void {
420 this._past.pop();
421 this._future.push(element);
422 this.versionId++;
423 }
425 > public moveForward(element: StackElement): void {
426 this._future.pop();
427 this._past.push(element);
428 this.versionId++;
429 }
431 >
432 > class EditStackSnapshot {
433 >
434 > public readonly editStacks: ResourceEditStack[];
435 > private readonly _versionIds: number[];
436 >
437 > constructor(editStacks: ResourceEditStack[]) {
438 this.editStacks = editStacks;
439 this._versionIds = [];
442 }
443 }
445 > public isValid(): boolean {
446 for (let i = 0, len = this.editStacks.length; i < len; i++) {
447 if (this._versionIds[i] !== this.editStacks[i].versionId) {
451 return true;
452 }
454 >
455 > const missingEditStack = new ResourceEditStack('', '');
456 > missingEditStack.locked = true;
457 >
458 > export class UndoRedoService implements IUndoRedoService {
459 > declare readonly _serviceBrand: undefined;
460 >
461 > private readonly _editStacks: Map<string, ResourceEditStack>;
462 > private readonly _uriComparisonKeyComputers: [string, UriComparisonKeyComputer][];
463 >
464 > constructor(
465 @IDialogService private readonly _dialogService: IDialogService,
466 @INotificationService private readonly _notificationService: INotificationService,
469 this._uriComparisonKeyComputers = [];
470 }
472 > public registerUriComparisonKeyComputer(scheme: string, uriComparisonKeyComputer: UriComparisonKeyComputer): IDisposable {
473 this._uriComparisonKeyComputers.push([scheme, uriComparisonKeyComputer]);
474 return {
483 };
484 }
486 > public getUriComparisonKey(resource: URI): string {
487 for (const uriComparisonKeyComputer of this._uriComparisonKeyComputers) {
488 if (uriComparisonKeyComputer[0] === resource.scheme) {
492 return resource.toString();
493 }
495 > private _print(label: string): void {
496 console.log(`------------------------------------`);
497 console.log(`AFTER ${label}: `);
502 console.log(str.join('\n'));
503 }
505 > public pushElement(element: IUndoRedoElement, group: UndoRedoGroup = UndoRedoGroup.None, source: UndoRedoSource = UndoRedoSource.None): void {
506 if (element.type === UndoRedoElementType.Resource) {
507 const resourceLabel = getResourceLabel(element.resource);
534 }
535 }
537 > private _pushElement(element: StackElement): void {
538 for (let i = 0, len = element.strResources.length; i < len; i++) {
539 const resourceLabel = element.resourceLabels[i];
551 }
552 }
554 > public getLastElement(resource: URI): IUndoRedoElement | null {
555 const strResource = this.getUriComparisonKey(resource);
556 if (this._editStacks.has(strResource)) {
564 return null;
565 }
567 > private _splitPastWorkspaceElement(toRemove: WorkspaceStackElement & { actual: { split(): IResourceUndoRedoElement[] } }, ignoreResources: RemovedResources | null): void {
568 const individualArr = toRemove.actual.split();
569 const individualMap = new Map<string, ResourceStackElement>();
583 }
584 }
586 > private _splitFutureWorkspaceElement(toRemove: WorkspaceStackElement & { actual: { split(): IResourceUndoRedoElement[] } }, ignoreResources: RemovedResources | null): void {
587 const individualArr = toRemove.actual.split();
588 const individualMap = new Map<string, ResourceStackElement>();
602 }
603 }
605 > public removeElements(resource: URI | string): void {
606 const strResource = typeof resource === 'string' ? resource : this.getUriComparisonKey(resource);
607 if (this._editStacks.has(strResource)) {
614 }
615 }
617 > public setElementsValidFlag(resource: URI, isValid: boolean, filter: (element: IUndoRedoElement) => boolean): void {
618 const strResource = this.getUriComparisonKey(resource);
619 if (this._editStacks.has(strResource)) {
625 }
626 }
628 > public hasElements(resource: URI): boolean {
629 const strResource = this.getUriComparisonKey(resource);
630 if (this._editStacks.has(strResource)) {
634 return false;
635 }
637 > public createSnapshot(resource: URI): ResourceEditStackSnapshot {
638 const strResource = this.getUriComparisonKey(resource);
639 if (this._editStacks.has(strResource)) {
643 return new ResourceEditStackSnapshot(resource, []);
644 }
646 > public restoreSnapshot(snapshot: ResourceEditStackSnapshot): void {
647 const strResource = this.getUriComparisonKey(snapshot.resource);
648 if (this._editStacks.has(strResource)) {
660 }
661 }
663 > public getElements(resource: URI): IPastFutureElements {
664 const strResource = this.getUriComparisonKey(resource);
665 if (this._editStacks.has(strResource)) {
669 return { past: [], future: [] };
670 }
672 > private _findClosestUndoElementWithSource(sourceId: number): [StackElement | null, string | null] {
673 if (!sourceId) {
674 return [null, null];
694 return [matchedElement, matchedStrResource];
695 }
697 > public canUndo(resourceOrSource: URI | UndoRedoSource): boolean {
698 if (resourceOrSource instanceof UndoRedoSource) {
699 const [, matchedStrResource] = this._findClosestUndoElementWithSource(resourceOrSource.id);
707 return false;
708 }
710 > private _onError(err: Error, element: StackElement): void {
711 onUnexpectedError(err);
712 // An error occurred while undoing or redoing => drop the undo/redo stack for all affected resources
716 this._notificationService.error(err);
717 }
719 > private _acquireLocks(editStackSnapshot: EditStackSnapshot): () => void {
720 // first, check if all locks can be acquired
721 for (const editStack of editStackSnapshot.editStacks) {
737 };
738 }
740 > private _safeInvokeWithLocks(element: StackElement, invoke: () => Promise<void> | void, editStackSnapshot: EditStackSnapshot, cleanup: IDisposable, continuation: () => Promise<void> | void): Promise<void> | void {
741 const releaseLocks = this._acquireLocks(editStackSnapshot);
742
771 }
772 }
774 > private async _invokeWorkspacePrepare(element: WorkspaceStackElement): Promise<IDisposable> {
775 if (typeof element.actual.prepareUndoRedo === 'undefined') {
776 return Disposable.None;
782 return result;
783 }
785 > private _invokeResourcePrepare(element: ResourceStackElement, callback: (disposable: IDisposable) => Promise<void> | void): void | Promise<void> {
786 if (element.actual.type !== UndoRedoElementType.Workspace || typeof element.actual.prepareUndoRedo === 'undefined') {
787 // no preparation needed
803 });
804 }
806 > private _getAffectedEditStacks(element: WorkspaceStackElement): EditStackSnapshot {
807 const affectedEditStacks: ResourceEditStack[] = [];
808 for (const strResource of element.strResources) {
811 return new EditStackSnapshot(affectedEditStacks);
812 }
814 > private _tryToSplitAndUndo(strResource: string, element: WorkspaceStackElement, ignoreResources: RemovedResources | null, message: string): WorkspaceVerificationError {
815 if (element.canSplit()) {
816 this._splitPastWorkspaceElement(element, ignoreResources);
826 }
827 }
829 > private _checkWorkspaceUndo(strResource: string, element: WorkspaceStackElement, editStackSnapshot: EditStackSnapshot, checkInvalidatedResources: boolean): WorkspaceVerificationError | null {
830 if (element.removedResources) {
831 return this._tryToSplitAndUndo(
903 return null;
904 }
906 > private _workspaceUndo(strResource: string, element: WorkspaceStackElement, undoConfirmed: boolean): Promise<void> | void {
907 const affectedEditStacks = this._getAffectedEditStacks(element);
908 const verificationError = this._checkWorkspaceUndo(strResource, element, affectedEditStacks, /*invalidated resources will be checked after the prepare call*/false);
912 return this._confirmAndExecuteWorkspaceUndo(strResource, element, affectedEditStacks, undoConfirmed);
913 }
915 > private _isPartOfUndoGroup(element: WorkspaceStackElement): boolean {
916 if (!element.groupId) {
917 return false;
937 return false;
938 }
940 > private async _confirmAndExecuteWorkspaceUndo(strResource: string, element: WorkspaceStackElement, editStackSnapshot: EditStackSnapshot, undoConfirmed: boolean): Promise<void> {
941
942 if (element.canSplit() && !this._isPartOfUndoGroup(element)) {
1009 return this._safeInvokeWithLocks(element, () => element.actual.undo(), editStackSnapshot, cleanup, () => this._continueUndoInGroup(element.groupId, undoConfirmed));
1010 }
1012 > private _resourceUndo(editStack: ResourceEditStack, element: ResourceStackElement, undoConfirmed: boolean): Promise<void> | void {
1013 if (!element.isValid) {
1014 // invalid element => immediately flush edit stack!
1029 });
1030 }
1032 > private _findClosestUndoElementInGroup(groupId: number): [StackElement | null, string | null] {
1033 if (!groupId) {
1034 return [null, null];
1054 return [matchedElement, matchedStrResource];
1055 }
1057 > private _continueUndoInGroup(groupId: number, undoConfirmed: boolean): Promise<void> | void {
1058 if (!groupId) {
1059 return;
1065 }
1066 }
1068 > public undo(resourceOrSource: URI | UndoRedoSource): Promise<void> | void {
1069 if (resourceOrSource instanceof UndoRedoSource) {
1070 const [, matchedStrResource] = this._findClosestUndoElementWithSource(resourceOrSource.id);
1076 return this._undo(this.getUriComparisonKey(resourceOrSource), 0, false);
1077 }
1079 > private _undo(strResource: string, sourceId: number = 0, undoConfirmed: boolean): Promise<void> | void {
1080 if (!this._editStacks.has(strResource)) {
1081 return;
1115 }
1116 }
1118 > private async _confirmAndContinueUndo(strResource: string, sourceId: number, element: StackElement): Promise<void> {
1119 const result = await this._dialogService.confirm({
1120 message: nls.localize('confirmDifferentSource', "Would you like to undo '{0}'?", element.label),
1129 return this._undo(strResource, sourceId, true);
1130 }
1132 > private _findClosestRedoElementWithSource(sourceId: number): [StackElement | null, string | null] {
1133 if (!sourceId) {
1134 return [null, null];
1154 return [matchedElement, matchedStrResource];
1155 }
1157 > public canRedo(resourceOrSource: URI | UndoRedoSource): boolean {
1158 if (resourceOrSource instanceof UndoRedoSource) {
1159 const [, matchedStrResource] = this._findClosestRedoElementWithSource(resourceOrSource.id);
1167 return false;
1168 }
1170 > private _tryToSplitAndRedo(strResource: string, element: WorkspaceStackElement, ignoreResources: RemovedResources | null, message: string): WorkspaceVerificationError {
1171 if (element.canSplit()) {
1172 this._splitFutureWorkspaceElement(element, ignoreResources);
1182 }
1183 }
1185 > private _checkWorkspaceRedo(strResource: string, element: WorkspaceStackElement, editStackSnapshot: EditStackSnapshot, checkInvalidatedResources: boolean): WorkspaceVerificationError | null {
1186 if (element.removedResources) {
1187 return this._tryToSplitAndRedo(
1259 return null;
1260 }
1262 > private _workspaceRedo(strResource: string, element: WorkspaceStackElement): Promise<void> | void {
1263 const affectedEditStacks = this._getAffectedEditStacks(element);
1264 const verificationError = this._checkWorkspaceRedo(strResource, element, affectedEditStacks, /*invalidated resources will be checked after the prepare call*/false);
1268 return this._executeWorkspaceRedo(strResource, element, affectedEditStacks);
1269 }
1271 > private async _executeWorkspaceRedo(strResource: string, element: WorkspaceStackElement, editStackSnapshot: EditStackSnapshot): Promise<void> {
1272 // prepare
1273 let cleanup: IDisposable;
1290 return this._safeInvokeWithLocks(element, () => element.actual.redo(), editStackSnapshot, cleanup, () => this._continueRedoInGroup(element.groupId));
1291 }
1293 > private _resourceRedo(editStack: ResourceEditStack, element: ResourceStackElement): Promise<void> | void {
1294 if (!element.isValid) {
1295 // invalid element => immediately flush edit stack!
1311 });
1312 }
1314 > private _findClosestRedoElementInGroup(groupId: number): [StackElement | null, string | null] {
1315 if (!groupId) {
1316 return [null, null];
1336 return [matchedElement, matchedStrResource];
1337 }
1339 > private _continueRedoInGroup(groupId: number): Promise<void> | void {
1340 if (!groupId) {
1341 return;
1347 }
1348 }
1350 > public redo(resourceOrSource: URI | UndoRedoSource | string): Promise<void> | void {
1351 if (resourceOrSource instanceof UndoRedoSource) {
1352 const [, matchedStrResource] = this._findClosestRedoElementWithSource(resourceOrSource.id);
1358 return this._redo(this.getUriComparisonKey(resourceOrSource));
1359 }
1361 > private _redo(strResource: string): Promise<void> | void {
1362 if (!this._editStacks.has(strResource)) {
1363 return;
1391 }
1392 }
1394 >
1395 > class WorkspaceVerificationError {
1396 > constructor(public readonly returnValue: Promise<void> | void) { }
1397 > }
1398 >
1399 > registerSingleton(IUndoRedoService, UndoRedoService, InstantiationType.Delayed);
src/vs/platform/theme/common/colorUtils.ts 256 covered LOC · 16 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- colorUtils.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 { assertNever } from '../../../base/common/assert.js';
7 > import { RunOnceScheduler } from '../../../base/common/async.js';
8 > import { Color } from '../../../base/common/color.js';
9 > import { Emitter, Event } from '../../../base/common/event.js';
10 > import { IJSONSchema, IJSONSchemaSnippet } from '../../../base/common/jsonSchema.js';
11 > import { IJSONContributionRegistry, Extensions as JSONExtensions } from '../../jsonschemas/common/jsonContributionRegistry.js';
12 > import * as platform from '../../registry/common/platform.js';
13 > import { IColorTheme } from './themeService.js';
14 > import * as nls from '../../../nls.js';
15 > import { Disposable } from '../../../base/common/lifecycle.js';
16 >
17 > // ------ API types
18 >
19 > export type ColorIdentifier = string;
20 >
21 > export interface ColorContribution {
22 > readonly id: ColorIdentifier;
23 > readonly description: string;
24 > readonly defaults: ColorDefaults | ColorValue | null;
25 > readonly needsTransparency: boolean;
26 > readonly deprecationMessage: string | undefined;
27 > }
28 >
29 > /**
30 > * Returns the css variable name for the given color identifier. Dots (`.`) are replaced with hyphens (`-`) and
31 > * everything is prefixed with `--vscode-`.
32 > *
33 > * @sample `editorSuggestWidget.background` is `--vscode-editorSuggestWidget-background`.
34 > */
35 > export function asCssVariableName(colorIdent: ColorIdentifier): string {
36 return `--vscode-${colorIdent.replace(/\./g, '-')}`;
37 }
39 > export function asCssVariable(color: ColorIdentifier): string {
40 return `var(${asCssVariableName(color)})`;
41 }
43 > export function asCssVariableWithDefault(color: ColorIdentifier, defaultCssValue: string): string {
44 return `var(${asCssVariableName(color)}, ${defaultCssValue})`;
45 }
47 > export const enum ColorTransformType {
48 > Darken,
49 > Lighten,
50 > Transparent,
51 > Opaque,
52 > OneOf,
53 > LessProminent,
54 > IfDefinedThenElse,
55 > Mix,
56 > }
57 >
58 > export type ColorTransform =
59 > | { op: ColorTransformType.Darken; value: ColorValue; factor: number }
60 > | { op: ColorTransformType.Lighten; value: ColorValue; factor: number }
61 > | { op: ColorTransformType.Transparent; value: ColorValue; factor: number }
62 > | { op: ColorTransformType.Opaque; value: ColorValue; background: ColorValue }
63 > | { op: ColorTransformType.OneOf; values: readonly ColorValue[] }
64 > | { op: ColorTransformType.LessProminent; value: ColorValue; background: ColorValue; factor: number; transparency: number }
65 > | { op: ColorTransformType.IfDefinedThenElse; if: ColorIdentifier; then: ColorValue; else: ColorValue }
66 > | { op: ColorTransformType.Mix; color: ColorValue; with: ColorValue; ratio?: number };
67 >
68 > export interface ColorDefaults {
69 > light: ColorValue | null;
70 > dark: ColorValue | null;
71 > hcDark: ColorValue | null;
72 > hcLight: ColorValue | null;
73 > }
74 >
75 > export function isColorDefaults(value: unknown): value is ColorDefaults {
76 return value !== null && typeof value === 'object' && 'light' in value && 'dark' in value;
77 }
79 > /**
80 > * A Color Value is either a color literal, a reference to an other color or a derived color
81 > */
82 > export type ColorValue = Color | string | ColorIdentifier | ColorTransform;
83 >
84 > // color registry
85 > export const Extensions = {
86 > ColorContribution: 'base.contributions.colors'
87 > };
88 >
89 > export const DEFAULT_COLOR_CONFIG_VALUE = 'default';
90 >
91 > export interface IColorRegistry {
92 >
93 > readonly onDidChangeSchema: Event<void>;
94 >
95 > /**
96 > * Register a color to the registry.
97 > * @param id The color id as used in theme description files
98 > * @param defaults The default values
99 > * @param needsTransparency Whether the color requires transparency
100 > * @description the description
101 > */
102 > registerColor(id: string, defaults: ColorDefaults, description: string, needsTransparency?: boolean): ColorIdentifier;
103 >
104 > /**
105 > * Register a color to the registry.
106 > */
107 > deregisterColor(id: string): void;
108 >
109 > /**
110 > * Get all color contributions
111 > */
112 > getColors(): ColorContribution[];
113 >
114 > /**
115 > * Gets the default color of the given id
116 > */
117 > resolveDefaultColor(id: ColorIdentifier, theme: IColorTheme): Color | undefined;
118 >
119 > /**
120 > * JSON schema for an object to assign color values to one of the color contributions.
121 > */
122 > getColorSchema(): IJSONSchema;
123 >
124 > /**
125 > * JSON schema to for a reference to a color contribution.
126 > */
127 > getColorReferenceSchema(): IJSONSchema;
128 >
129 > /**
130 > * Update the default color of a color identifier.
131 > */
132 > updateDefaultColor(id: string, defaults: ColorDefaults | ColorValue | null): void;
133 >
134 > /**
135 > * Notify when the color theme or settings change.
136 > */
137 > notifyThemeUpdate(theme: IColorTheme): void;
138 >
139 > }
140 >
141 > type IJSONSchemaForColors = IJSONSchema & { properties: { [name: string]: { oneOf: [IJSONSchemaWithSnippets, IJSONSchema] } } };
142 > type IJSONSchemaWithSnippets = IJSONSchema & { defaultSnippets: IJSONSchemaSnippet[] };
143 >
144 > class ColorRegistry extends Disposable implements IColorRegistry {
145 >
146 > private readonly _onDidChangeSchema = this._register(new Emitter<void>());
147 > readonly onDidChangeSchema: Event<void> = this._onDidChangeSchema.event;
148 >
149 > private colorsById: { [key: string]: ColorContribution };
150 > private colorSchema: IJSONSchemaForColors = { type: 'object', properties: {} };
151 > private colorReferenceSchema: IJSONSchema & { enum: string[]; enumDescriptions: string[] } = { type: 'string', enum: [], enumDescriptions: [] };
152 >
153 > constructor() {
154 > super();
155 > this.colorsById = {};
156 > }
157 >
158 > public notifyThemeUpdate(colorThemeData: IColorTheme) {
159 for (const key of Object.keys(this.colorsById)) {
160 const color = colorThemeData.getColor(key);
165 this._onDidChangeSchema.fire();
166 }
168 > public registerColor(id: string, defaults: ColorDefaults | ColorValue | null, description: string, needsTransparency = false, deprecationMessage?: string): ColorIdentifier {
169 > const colorContribution: ColorContribution = { id, description, defaults, needsTransparency, deprecationMessage };
170 > this.colorsById[id] = colorContribution;
171 > const propertySchema: IJSONSchemaWithSnippets = { type: 'string', format: 'color-hex', defaultSnippets: [{ body: '${1:#ff0000}' }] };
172 > if (deprecationMessage) {
173 > propertySchema.deprecationMessage = deprecationMessage;
174 > }
175 > if (needsTransparency) {
176 > propertySchema.pattern = '^#(?:(?<rgba>[0-9a-fA-f]{3}[0-9a-eA-E])|(?:[0-9a-fA-F]{6}(?:(?![fF]{2})(?:[0-9a-fA-F]{2}))))?$';
177 > propertySchema.patternErrorMessage = nls.localize('transparecyRequired', 'This color must be transparent or it will obscure content');
178 > }
179 > this.colorSchema.properties[id] = {
180 > description,
181 > oneOf: [
182 > propertySchema,
183 > { type: 'string', const: DEFAULT_COLOR_CONFIG_VALUE, description: nls.localize('useDefault', 'Use the default color.') }
184 > ]
185 > };
186 > this.colorReferenceSchema.enum.push(id);
187 > this.colorReferenceSchema.enumDescriptions.push(description);
188 >
189 > this._onDidChangeSchema.fire();
190 > return id;
191 > }
192 >
193 >
194 > public updateDefaultColor(id: string, defaults: ColorDefaults | ColorValue | null): void {
195 const existing = this.colorsById[id];
196 if (existing) {
198 }
199 }
201 > public deregisterColor(id: string): void {
202 delete this.colorsById[id];
203 delete this.colorSchema.properties[id];
209 this._onDidChangeSchema.fire();
210 }
212 > public getColors(): ColorContribution[] {
213 return Object.keys(this.colorsById).map(id => this.colorsById[id]);
214 }
216 > public resolveDefaultColor(id: ColorIdentifier, theme: IColorTheme): Color | undefined {
217 const colorDesc = this.colorsById[id];
218 if (colorDesc?.defaults) {
222 return undefined;
223 }
225 > public getColorSchema(): IJSONSchema {
226 > return this.colorSchema;
227 > }
228 >
229 > public getColorReferenceSchema(): IJSONSchema {
230 return this.colorReferenceSchema;
231 }
233 > public override toString() {
234 const sorter = (a: string, b: string) => {
235 const cat1 = a.indexOf('.') === -1 ? 0 : 1;
243 return Object.keys(this.colorsById).sort(sorter).map(k => `- \`${k}\`: ${this.colorsById[k].description}`).join('\n');
244 }
246 > }
247 >
248 > const colorRegistry = new ColorRegistry();
249 > platform.Registry.add(Extensions.ColorContribution, colorRegistry);
250 >
251 >
252 > export function registerColor(id: string, defaults: ColorDefaults | ColorValue | null, description: string, needsTransparency?: boolean, deprecationMessage?: string): ColorIdentifier {
253 > return colorRegistry.registerColor(id, defaults, description, needsTransparency, deprecationMessage);
254 > }
255 >
256 > export function getColorRegistry(): IColorRegistry {
257 return colorRegistry;
258 }
260 > // ----- color functions
261 >
262 > export function executeTransform(transform: ColorTransform, theme: IColorTheme): Color | undefined {
263 switch (transform.op) {
264 case ColorTransformType.Darken:
316 }
317 }
319 > export function darken(colorValue: ColorValue, factor: number): ColorTransform {
320 > return { op: ColorTransformType.Darken, value: colorValue, factor };
321 > }
322 >
323 > export function lighten(colorValue: ColorValue, factor: number): ColorTransform {
324 > return { op: ColorTransformType.Lighten, value: colorValue, factor };
325 > }
326 >
327 > export function transparent(colorValue: ColorValue, factor: number): ColorTransform {
328 > return { op: ColorTransformType.Transparent, value: colorValue, factor };
329 > }
330 >
331 > export function opaque(colorValue: ColorValue, background: ColorValue): ColorTransform {
332 return { op: ColorTransformType.Opaque, value: colorValue, background };
333 }
335 > export function oneOf(...colorValues: ColorValue[]): ColorTransform {
336 > return { op: ColorTransformType.OneOf, values: colorValues };
337 > }
338 >
339 > export function ifDefinedThenElse(ifArg: ColorIdentifier, thenArg: ColorValue, elseArg: ColorValue): ColorTransform {
340 > return { op: ColorTransformType.IfDefinedThenElse, if: ifArg, then: thenArg, else: elseArg };
341 > }
342 >
343 > export function lessProminent(colorValue: ColorValue, backgroundColorValue: ColorValue, factor: number, transparency: number): ColorTransform {
344 > return { op: ColorTransformType.LessProminent, value: colorValue, background: backgroundColorValue, factor, transparency };
345 > }
346 >
347 > // ----- implementation
348 >
349 > /**
350 > * @param colorValue Resolve a color value in the context of a theme
351 > */
352 > export function resolveColorValue(colorValue: ColorValue | null, theme: IColorTheme): Color | undefined {
353 if (colorValue === null) {
354 return undefined;
365 return undefined;
366 }
368 > export const workbenchColorsSchemaId = 'vscode://schemas/workbench-colors';
369 >
370 > const schemaRegistry = platform.Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
371 > schemaRegistry.registerSchema(workbenchColorsSchemaId, colorRegistry.getColorSchema());
372 >
373 > const delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(workbenchColorsSchemaId), 200);
374 >
375 > colorRegistry.onDidChangeSchema(() => {
376 > if (!delayer.isScheduled()) {
377 > delayer.schedule();
378 > }
379 > });
380 >
381 > // setTimeout(_ => console.log(colorRegistry.toString()), 5000);
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/core/range.ts 247 covered LOC · 40 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)) {
54 this.startLineNumber = endLineNumber;
63 }
64 }
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);
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);
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);
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);
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);
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 + ']';
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);
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) {
388 return null;
390 return new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
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/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/languages/supports/richEditBrackets.ts 228 covered LOC · 22 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- richEditBrackets.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 strings from '../../../../base/common/strings.js';
7 > import * as stringBuilder from '../../core/stringBuilder.js';
8 > import { Range } from '../../core/range.js';
9 > import { CharacterPair } from '../languageConfiguration.js';
10 >
11 > interface InternalBracket {
12 > open: string[];
13 > close: string[];
14 > }
15 >
16 > /**
17 > * Represents a grouping of colliding bracket pairs.
18 > *
19 > * Most of the times this contains a single bracket pair,
20 > * but sometimes this contains multiple bracket pairs in cases
21 > * where the same string appears as a closing bracket for multiple
22 > * bracket pairs, or the same string appears an opening bracket for
23 > * multiple bracket pairs.
24 > *
25 > * e.g. of a group containing a single pair:
26 > * open: ['{'], close: ['}']
27 > *
28 > * e.g. of a group containing multiple pairs:
29 > * open: ['if', 'for'], close: ['end', 'end']
30 > */
31 > export class RichEditBracket {
32 > _richEditBracketBrand: void = undefined;
33 >
34 > readonly languageId: string;
35 > /**
36 > * A 0-based consecutive unique identifier for this bracket pair.
37 > * If a language has 5 bracket pairs, out of which 2 are grouped together,
38 > * it is expected that the `index` goes from 0 to 4.
39 > */
40 > readonly index: number;
41 > /**
42 > * The open sequence for each bracket pair contained in this group.
43 > *
44 > * The open sequence at a specific index corresponds to the
45 > * closing sequence at the same index.
46 > *
47 > * [ open[i], closed[i] ] represent a bracket pair.
48 > */
49 > readonly open: string[];
50 > /**
51 > * The close sequence for each bracket pair contained in this group.
52 > *
53 > * The close sequence at a specific index corresponds to the
54 > * opening sequence at the same index.
55 > *
56 > * [ open[i], closed[i] ] represent a bracket pair.
57 > */
58 > readonly close: string[];
59 > /**
60 > * A regular expression that is useful to search for this bracket pair group in a string.
61 > *
62 > * This regular expression is built in a way that it is aware of the other bracket
63 > * pairs defined for the language, so it might match brackets from other groups.
64 > *
65 > * See the fine details in `getRegexForBracketPair`.
66 > */
67 > readonly forwardRegex: RegExp;
68 > /**
69 > * A regular expression that is useful to search for this bracket pair group in a string backwards.
70 > *
71 > * This regular expression is built in a way that it is aware of the other bracket
72 > * pairs defined for the language, so it might match brackets from other groups.
73 > *
74 > * See the fine defails in `getReversedRegexForBracketPair`.
75 > */
76 > readonly reversedRegex: RegExp;
77 > private readonly _openSet: Set<string>;
78 > private readonly _closeSet: Set<string>;
79 >
80 > constructor(languageId: string, index: number, open: string[], close: string[], forwardRegex: RegExp, reversedRegex: RegExp) {
81 this.languageId = languageId;
82 this.index = index;
88 this._closeSet = RichEditBracket._toSet(this.close);
89 }
91 > /**
92 > * Check if the provided `text` is an open bracket in this group.
93 > */
94 > public isOpen(text: string) {
95 return this._openSet.has(text);
96 }
98 > /**
99 > * Check if the provided `text` is a close bracket in this group.
100 > */
101 > public isClose(text: string) {
102 return this._closeSet.has(text);
103 }
105 > private static _toSet(arr: string[]): Set<string> {
106 const result = new Set<string>();
107 for (const element of arr) {
110 return result;
111 }
113 >
114 > /**
115 > * Groups together brackets that have equal open or close sequences.
116 > *
117 > * For example, if the following brackets are defined:
118 > * ['IF','END']
119 > * ['for','end']
120 > * ['{','}']
121 > *
122 > * Then the grouped brackets would be:
123 > * { open: ['if', 'for'], close: ['end', 'end'] }
124 > * { open: ['{'], close: ['}'] }
125 > *
126 > */
127 function groupFuzzyBrackets(brackets: readonly CharacterPair[]): InternalBracket[] {
128 const N = brackets.length;
182 return result;
183 }
185 > export class RichEditBrackets {
186 > _richEditBracketsBrand: void = undefined;
187 >
188 > /**
189 > * All groups of brackets defined for this language.
190 > */
191 > public readonly brackets: RichEditBracket[];
192 > /**
193 > * A regular expression that is useful to search for all bracket pairs in a string.
194 > *
195 > * See the fine details in `getRegexForBrackets`.
196 > */
197 > public readonly forwardRegex: RegExp;
198 > /**
199 > * A regular expression that is useful to search for all bracket pairs in a string backwards.
200 > *
201 > * See the fine details in `getReversedRegexForBrackets`.
202 > */
203 > public readonly reversedRegex: RegExp;
204 > /**
205 > * The length (i.e. str.length) for the longest bracket pair.
206 > */
207 > public readonly maxBracketLength: number;
208 > /**
209 > * A map useful for decoding a regex match and finding which bracket group was matched.
210 > */
211 > public readonly textIsBracket: { [text: string]: RichEditBracket };
212 > /**
213 > * A set useful for decoding if a regex match is the open bracket of a bracket pair.
214 > */
215 > public readonly textIsOpenBracket: { [text: string]: boolean };
216 >
217 > constructor(languageId: string, _brackets: readonly CharacterPair[]) {
218 const brackets = groupFuzzyBrackets(_brackets);
219
249 }
250 }
252 >
253 function collectSuperstrings(str: string, brackets: InternalBracket[], currentIndex: number, dest: string[]): void {
254 for (let i = 0, len = brackets.length; i < len; i++) {
269 }
270 }
272 function lengthcmp(a: string, b: string) {
273 return a.length - b.length;
274 }
276 function unique(arr: string[]): string[] {
277 if (arr.length <= 1) {
289 return result;
290 }
292 > /**
293 > * Create a regular expression that can be used to search forward in a piece of text
294 > * for a group of bracket pairs. But this regex must be built in a way in which
295 > * it is aware of the other bracket pairs defined for the language.
296 > *
297 > * For example, if a language contains the following bracket pairs:
298 > * ['begin', 'end']
299 > * ['if', 'end if']
300 > * The two bracket pairs do not collide because no open or close brackets are equal.
301 > * So the function getRegexForBracketPair is called twice, once with
302 > * the ['begin'], ['end'] group consisting of one bracket pair, and once with
303 > * the ['if'], ['end if'] group consiting of the other bracket pair.
304 > *
305 > * But there could be a situation where an occurrence of 'end if' is mistaken
306 > * for an occurrence of 'end'.
307 > *
308 > * Therefore, for the bracket pair ['begin', 'end'], the regex will also
309 > * target 'end if'. The regex will be something like:
310 > * /(\bend if\b)|(\bend\b)|(\bif\b)/
311 > *
312 > * The regex also searches for "superstrings" (other brackets that might be mistaken with the current bracket).
313 > *
314 > */
315 function getRegexForBracketPair(open: string[], close: string[], brackets: InternalBracket[], currentIndex: number): RegExp {
316 // search in all brackets for other brackets that are a superstring of these brackets
326 return createBracketOrRegExp(pieces);
327 }
329 > /**
330 > * Matching a regular expression in JS can only be done "forwards". So JS offers natively only
331 > * methods to find the first match of a regex in a string. But sometimes, it is useful to
332 > * find the last match of a regex in a string. For such a situation, a nice solution is to
333 > * simply reverse the string and then search for a reversed regex.
334 > *
335 > * This function also has the fine details of `getRegexForBracketPair`. For the same example
336 > * given above, the regex produced here would look like:
337 > * /(\bfi dne\b)|(\bdne\b)|(\bfi\b)/
338 > */
339 function getReversedRegexForBracketPair(open: string[], close: string[], brackets: InternalBracket[], currentIndex: number): RegExp {
340 // search in all brackets for other brackets that are a superstring of these brackets
350 return createBracketOrRegExp(pieces.map(toReversedString));
351 }
353 > /**
354 > * Creates a regular expression that targets all bracket pairs.
355 > *
356 > * e.g. for the bracket pairs:
357 > * ['{','}']
358 > * ['begin,'end']
359 > * ['for','end']
360 > * the regex would look like:
361 > * /(\{)|(\})|(\bbegin\b)|(\bend\b)|(\bfor\b)/
362 > */
363 function getRegexForBrackets(brackets: RichEditBracket[]): RegExp {
364 let pieces: string[] = [];
374 return createBracketOrRegExp(pieces);
375 }
377 > /**
378 > * Matching a regular expression in JS can only be done "forwards". So JS offers natively only
379 > * methods to find the first match of a regex in a string. But sometimes, it is useful to
380 > * find the last match of a regex in a string. For such a situation, a nice solution is to
381 > * simply reverse the string and then search for a reversed regex.
382 > *
383 > * e.g. for the bracket pairs:
384 > * ['{','}']
385 > * ['begin,'end']
386 > * ['for','end']
387 > * the regex would look like:
388 > * /(\{)|(\})|(\bnigeb\b)|(\bdne\b)|(\brof\b)/
389 > */
390 function getReversedRegexForBrackets(brackets: RichEditBracket[]): RegExp {
391 let pieces: string[] = [];
401 return createBracketOrRegExp(pieces.map(toReversedString));
402 }
404 function prepareBracketForRegExp(str: string): string {
405 // This bracket pair uses letters like e.g. "begin" - "end"
408 return (insertWordBoundaries ? `\\b${str}\\b` : str);
409 }
411 > export function createBracketOrRegExp(pieces: string[], options?: strings.RegExpOptions): RegExp {
412 const regexStr = `(${pieces.map(prepareBracketForRegExp).join(')|(')})`;
413 return strings.createRegExp(regexStr, true, options);
414 }
416 > const toReversedString = (function () {
417 >
418 > function reverse(str: string): string {
419 // create a Uint16Array and then use a TextDecoder to create a string
420 const arr = new Uint16Array(str.length);
425 return stringBuilder.getPlatformTextDecoder().decode(arr);
426 }
428 > let lastInput: string | null = null;
429 > let lastOutput: string | null = null;
430 > return function toReversedString(str: string): string {
431 if (lastInput !== str) {
432 lastInput = str;
435 return lastOutput!;
436 };
437 > })(); richEditBrackets.ts
438 >
439 > export class BracketsUtils {
440 >
441 > private static _findPrevBracketInText(reversedBracketRegex: RegExp, lineNumber: number, reversedText: string, offset: number): Range | null {
442 const m = reversedText.match(reversedBracketRegex);
443
452 return new Range(lineNumber, absoluteMatchOffset - matchLength + 1, lineNumber, absoluteMatchOffset + 1);
453 }
455 > public static findPrevBracketInRange(reversedBracketRegex: RegExp, lineNumber: number, lineText: string, startOffset: number, endOffset: number): Range | null {
456 // Because JS does not support backwards regex search, we search forwards in a reversed string with a reversed regex ;)
457 const reversedLineText = toReversedString(lineText);
459 return this._findPrevBracketInText(reversedBracketRegex, lineNumber, reversedSubstr, startOffset);
460 }
462 > public static findNextBracketInText(bracketRegex: RegExp, lineNumber: number, text: string, offset: number): Range | null {
463 const m = text.match(bracketRegex);
464
476 return new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength);
477 }
479 > public static findNextBracketInRange(bracketRegex: RegExp, lineNumber: number, lineText: string, startOffset: number, endOffset: number): Range | null {
480 const substr = lineText.substring(startOffset, endOffset);
481 return this.findNextBracketInText(bracketRegex, lineNumber, substr, startOffset);
482 }
src/vs/platform/theme/common/colors/inputColors.ts 226 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- inputColors.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 > // Import the effects we need
9 > import { Color, RGBA } from '../../../../base/common/color.js';
10 > import { registerColor, transparent, lighten, darken, ColorTransformType } from '../colorUtils.js';
11 >
12 > // Import the colors we need
13 > import { foreground, contrastBorder, focusBorder, iconForeground } from './baseColors.js';
14 > import { editorWidgetBackground } from './editorColors.js';
15 > import { listHoverBackground } from './listColors.js';
16 >
17 >
18 > // ----- input
19 >
20 > export const inputBackground = registerColor('input.background',
21 > { dark: '#3C3C3C', light: Color.white, hcDark: Color.black, hcLight: Color.white },
22 > nls.localize('inputBoxBackground', "Input box background."));
23 >
24 > export const inputForeground = registerColor('input.foreground',
25 > foreground,
26 > nls.localize('inputBoxForeground', "Input box foreground."));
27 >
28 > export const inputBorder = registerColor('input.border',
29 > { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },
30 > nls.localize('inputBoxBorder', "Input box border."));
31 >
32 > export const inputActiveOptionBorder = registerColor('inputOption.activeBorder',
33 > { dark: '#007ACC', light: '#007ACC', hcDark: contrastBorder, hcLight: contrastBorder },
34 > nls.localize('inputBoxActiveOptionBorder', "Border color of activated options in input fields."));
35 >
36 > export const inputActiveOptionHoverBackground = registerColor('inputOption.hoverBackground',
37 > { dark: '#5a5d5e80', light: '#b8b8b850', hcDark: null, hcLight: null },
38 > nls.localize('inputOption.hoverBackground', "Background color of activated options in input fields."));
39 >
40 > export const inputActiveOptionBackground = registerColor('inputOption.activeBackground',
41 > { dark: transparent(focusBorder, 0.4), light: transparent(focusBorder, 0.2), hcDark: Color.transparent, hcLight: Color.transparent },
42 > nls.localize('inputOption.activeBackground', "Background hover color of options in input fields."));
43 >
44 > export const inputActiveOptionForeground = registerColor('inputOption.activeForeground',
45 > { dark: Color.white, light: Color.black, hcDark: foreground, hcLight: foreground },
46 > nls.localize('inputOption.activeForeground', "Foreground color of activated options in input fields."));
47 >
48 > export const inputPlaceholderForeground = registerColor('input.placeholderForeground',
49 > { light: transparent(foreground, 0.5), dark: transparent(foreground, 0.5), hcDark: transparent(foreground, 0.7), hcLight: transparent(foreground, 0.7) },
50 > nls.localize('inputPlaceholderForeground', "Input box foreground color for placeholder text."));
51 >
52 >
53 > // ----- input validation
54 >
55 > export const inputValidationInfoBackground = registerColor('inputValidation.infoBackground',
56 > { dark: '#063B49', light: '#D6ECF2', hcDark: Color.black, hcLight: Color.white },
57 > nls.localize('inputValidationInfoBackground', "Input validation background color for information severity."));
58 >
59 > export const inputValidationInfoForeground = registerColor('inputValidation.infoForeground',
60 > { dark: null, light: null, hcDark: null, hcLight: foreground },
61 > nls.localize('inputValidationInfoForeground', "Input validation foreground color for information severity."));
62 >
63 > export const inputValidationInfoBorder = registerColor('inputValidation.infoBorder',
64 > { dark: '#007acc', light: '#007acc', hcDark: contrastBorder, hcLight: contrastBorder },
65 > nls.localize('inputValidationInfoBorder', "Input validation border color for information severity."));
66 >
67 > export const inputValidationWarningBackground = registerColor('inputValidation.warningBackground',
68 > { dark: '#352A05', light: '#F6F5D2', hcDark: Color.black, hcLight: Color.white },
69 > nls.localize('inputValidationWarningBackground', "Input validation background color for warning severity."));
70 >
71 > export const inputValidationWarningForeground = registerColor('inputValidation.warningForeground',
72 > { dark: null, light: null, hcDark: null, hcLight: foreground },
73 > nls.localize('inputValidationWarningForeground', "Input validation foreground color for warning severity."));
74 >
75 > export const inputValidationWarningBorder = registerColor('inputValidation.warningBorder',
76 > { dark: '#B89500', light: '#B89500', hcDark: contrastBorder, hcLight: contrastBorder },
77 > nls.localize('inputValidationWarningBorder', "Input validation border color for warning severity."));
78 >
79 > export const inputValidationErrorBackground = registerColor('inputValidation.errorBackground',
80 > { dark: '#5A1D1D', light: '#F2DEDE', hcDark: Color.black, hcLight: Color.white },
81 > nls.localize('inputValidationErrorBackground', "Input validation background color for error severity."));
82 >
83 > export const inputValidationErrorForeground = registerColor('inputValidation.errorForeground',
84 > { dark: null, light: null, hcDark: null, hcLight: foreground },
85 > nls.localize('inputValidationErrorForeground', "Input validation foreground color for error severity."));
86 >
87 > export const inputValidationErrorBorder = registerColor('inputValidation.errorBorder',
88 > { dark: '#BE1100', light: '#BE1100', hcDark: contrastBorder, hcLight: contrastBorder },
89 > nls.localize('inputValidationErrorBorder', "Input validation border color for error severity."));
90 >
91 >
92 > // ----- select
93 >
94 > export const selectBackground = registerColor('dropdown.background',
95 > { dark: '#3C3C3C', light: Color.white, hcDark: Color.black, hcLight: Color.white },
96 > nls.localize('dropdownBackground', "Dropdown background."));
97 >
98 > export const selectListBackground = registerColor('dropdown.listBackground',
99 > { dark: null, light: null, hcDark: Color.black, hcLight: Color.white },
100 > nls.localize('dropdownListBackground', "Dropdown list background."));
101 >
102 > export const selectForeground = registerColor('dropdown.foreground',
103 > { dark: '#F0F0F0', light: foreground, hcDark: Color.white, hcLight: foreground },
104 > nls.localize('dropdownForeground', "Dropdown foreground."));
105 >
106 > export const selectBorder = registerColor('dropdown.border',
107 > { dark: selectBackground, light: '#CECECE', hcDark: contrastBorder, hcLight: contrastBorder },
108 > nls.localize('dropdownBorder', "Dropdown border."));
109 >
110 >
111 > // ------ button
112 >
113 > export const buttonForeground = registerColor('button.foreground',
114 > Color.white,
115 > nls.localize('buttonForeground', "Button foreground color."));
116 >
117 > export const buttonSeparator = registerColor('button.separator',
118 > transparent(buttonForeground, .4),
119 > nls.localize('buttonSeparator', "Button separator color."));
120 >
121 > export const buttonBackground = registerColor('button.background',
122 > { dark: '#0E639C', light: '#007ACC', hcDark: Color.black, hcLight: '#0F4A85' },
123 > nls.localize('buttonBackground', "Button background color."));
124 >
125 > export const buttonHoverBackground = registerColor('button.hoverBackground',
126 > { dark: lighten(buttonBackground, 0.2), light: darken(buttonBackground, 0.2), hcDark: buttonBackground, hcLight: buttonBackground },
127 > nls.localize('buttonHoverBackground', "Button background color when hovering."));
128 >
129 > export const buttonBorder = registerColor('button.border',
130 > contrastBorder,
131 > nls.localize('buttonBorder', "Button border color."));
132 >
133 > export const buttonSecondaryForeground = registerColor('button.secondaryForeground',
134 > { dark: foreground, light: foreground, hcDark: Color.white, hcLight: foreground },
135 > nls.localize('buttonSecondaryForeground', "Secondary button foreground color."));
136 >
137 > export const buttonSecondaryBackground = registerColor('button.secondaryBackground',
138 > { dark: listHoverBackground, light: listHoverBackground, hcDark: null, hcLight: Color.white },
139 > nls.localize('buttonSecondaryBackground', "Secondary button background color."));
140 >
141 > export const buttonSecondaryBorder = registerColor('button.secondaryBorder',
142 > { dark: transparent(foreground, 0.15), light: transparent(foreground, 0.15), hcDark: contrastBorder, hcLight: contrastBorder },
143 > nls.localize('buttonSecondaryBorder', "Secondary button border color."));
144 >
145 > export const buttonSecondaryHoverBackground = registerColor('button.secondaryHoverBackground',
146 > { dark: lighten(listHoverBackground, 0.2), light: lighten(listHoverBackground, 0.2), hcDark: null, hcLight: null },
147 > nls.localize('buttonSecondaryHoverBackground', "Secondary button background color when hovering."));
148 >
149 > // ------ radio
150 >
151 > export const radioActiveForeground = registerColor('radio.activeForeground',
152 > inputActiveOptionForeground,
153 > nls.localize('radioActiveForeground', "Foreground color of active radio option."));
154 >
155 > export const radioActiveBackground = registerColor('radio.activeBackground',
156 > inputActiveOptionBackground,
157 > nls.localize('radioBackground', "Background color of active radio option."));
158 >
159 > export const radioActiveBorder = registerColor('radio.activeBorder',
160 > inputActiveOptionBorder,
161 > nls.localize('radioActiveBorder', "Border color of the active radio option."));
162 >
163 > export const radioInactiveForeground = registerColor('radio.inactiveForeground',
164 > null,
165 > nls.localize('radioInactiveForeground', "Foreground color of inactive radio option."));
166 >
167 > export const radioInactiveBackground = registerColor('radio.inactiveBackground',
168 > null,
169 > nls.localize('radioInactiveBackground', "Background color of inactive radio option."));
170 >
171 > export const radioInactiveBorder = registerColor('radio.inactiveBorder',
172 > { light: transparent(radioActiveForeground, .2), dark: transparent(radioActiveForeground, .2), hcDark: transparent(radioActiveForeground, .4), hcLight: transparent(radioActiveForeground, .2) },
173 > nls.localize('radioInactiveBorder', "Border color of the inactive radio option."));
174 >
175 > export const radioInactiveHoverBackground = registerColor('radio.inactiveHoverBackground',
176 > inputActiveOptionHoverBackground,
177 > nls.localize('radioHoverBackground', "Background color of inactive active radio option when hovering."));
178 >
179 > // ------ checkbox
180 >
181 > export const checkboxBackground = registerColor('checkbox.background',
182 > selectBackground,
183 > nls.localize('checkbox.background', "Background color of checkbox widget."));
184 >
185 > export const checkboxSelectBackground = registerColor('checkbox.selectBackground',
186 > editorWidgetBackground,
187 > nls.localize('checkbox.select.background', "Background color of checkbox widget when the element it's in is selected."));
188 >
189 > export const checkboxForeground = registerColor('checkbox.foreground',
190 > selectForeground,
191 > nls.localize('checkbox.foreground', "Foreground color of checkbox widget."));
192 >
193 > export const checkboxBorder = registerColor('checkbox.border',
194 > selectBorder,
195 > nls.localize('checkbox.border', "Border color of checkbox widget."));
196 >
197 > export const checkboxSelectBorder = registerColor('checkbox.selectBorder',
198 > iconForeground,
199 > nls.localize('checkbox.select.border', "Border color of checkbox widget when the element it's in is selected."));
200 >
201 > export const checkboxDisabledBackground = registerColor('checkbox.disabled.background',
202 > { op: ColorTransformType.Mix, color: checkboxBackground, with: checkboxForeground, ratio: 0.33 },
203 > nls.localize('checkbox.disabled.background', "Background of a disabled checkbox."));
204 >
205 > export const checkboxDisabledForeground = registerColor('checkbox.disabled.foreground',
206 > { op: ColorTransformType.Mix, color: checkboxForeground, with: checkboxBackground, ratio: 0.33 },
207 > nls.localize('checkbox.disabled.foreground', "Foreground of a disabled checkbox."));
208 >
209 >
210 > // ------ keybinding label
211 >
212 > export const keybindingLabelBackground = registerColor('keybindingLabel.background',
213 > { dark: new Color(new RGBA(128, 128, 128, 0.17)), light: new Color(new RGBA(221, 221, 221, 0.4)), hcDark: Color.transparent, hcLight: Color.transparent },
214 > nls.localize('keybindingLabelBackground', "Keybinding label background color. The keybinding label is used to represent a keyboard shortcut."));
215 >
216 > export const keybindingLabelForeground = registerColor('keybindingLabel.foreground',
217 > { dark: Color.fromHex('#CCCCCC'), light: Color.fromHex('#555555'), hcDark: Color.white, hcLight: foreground },
218 > nls.localize('keybindingLabelForeground', "Keybinding label foreground color. The keybinding label is used to represent a keyboard shortcut."));
219 >
220 > export const keybindingLabelBorder = registerColor('keybindingLabel.border',
221 > { dark: new Color(new RGBA(51, 51, 51, 0.6)), light: new Color(new RGBA(204, 204, 204, 0.4)), hcDark: new Color(new RGBA(111, 195, 223)), hcLight: contrastBorder },
222 > nls.localize('keybindingLabelBorder', "Keybinding label border color. The keybinding label is used to represent a keyboard shortcut."));
223 >
224 > export const keybindingLabelBottomBorder = registerColor('keybindingLabel.bottomBorder',
225 > { dark: new Color(new RGBA(68, 68, 68, 0.6)), light: new Color(new RGBA(187, 187, 187, 0.4)), hcDark: new Color(new RGBA(111, 195, 223)), hcLight: foreground },
226 > nls.localize('keybindingLabelBottomBorder', "Keybinding label border bottom color. The keybinding label is used to represent a keyboard shortcut."));
src/vs/platform/theme/common/themeService.ts 223 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- themeService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Codicon } from '../../../base/common/codicons.js';
7 > import { Color } from '../../../base/common/color.js';
8 > import { Emitter, Event } from '../../../base/common/event.js';
9 > import { Disposable, IDisposable, toDisposable } from '../../../base/common/lifecycle.js';
10 > import { IEnvironmentService } from '../../environment/common/environment.js';
11 > import { createDecorator } from '../../instantiation/common/instantiation.js';
12 > import * as platform from '../../registry/common/platform.js';
13 > import { ColorIdentifier } from './colorRegistry.js';
14 > import { IconContribution, IconDefinition } from './iconRegistry.js';
15 > import { ColorScheme, ThemeTypeSelector } from './theme.js';
16 >
17 > export const IThemeService = createDecorator<IThemeService>('themeService');
18 >
19 > export function themeColorFromId(id: ColorIdentifier) {
20 return { id };
21 }
23 > export const FileThemeIcon = Codicon.file;
24 > export const FolderThemeIcon = Codicon.folder;
25 >
26 > export function getThemeTypeSelector(type: ColorScheme): ThemeTypeSelector {
27 switch (type) {
28 case ColorScheme.DARK: return ThemeTypeSelector.VS_DARK;
32 }
33 }
35 > export interface ITokenStyle {
36 > readonly foreground: number | undefined;
37 > readonly bold: boolean | undefined;
38 > readonly underline: boolean | undefined;
39 > readonly strikethrough: boolean | undefined;
40 > readonly italic: boolean | undefined;
41 > }
42 >
43 > export interface IColorTheme {
44 >
45 > readonly type: ColorScheme;
46 >
47 > readonly label: string;
48 >
49 > /**
50 > * Resolves the color of the given color identifier. If the theme does not
51 > * specify the color, the default color is returned unless <code>useDefault</code> is set to false.
52 > * @param color the id of the color
53 > * @param useDefault specifies if the default color should be used. If not set, the default is used.
54 > */
55 > getColor(color: ColorIdentifier, useDefault?: boolean): Color | undefined;
56 >
57 > /**
58 > * Returns whether the theme defines a value for the color. If not, that means the
59 > * default color will be used.
60 > */
61 > defines(color: ColorIdentifier): boolean;
62 >
63 > /**
64 > * Returns the token style for a given classification. The result uses the <code>MetadataConsts</code> format
65 > */
66 > getTokenStyleMetadata(type: string, modifiers: string[], modelLanguage: string): ITokenStyle | undefined;
67 >
68 > /**
69 > * List of all colors used with tokens. <code>getTokenStyleMetadata</code> references the colors by index into this list.
70 > */
71 > readonly tokenColorMap: string[];
72 >
73 > /**
74 > * List of all the fonts used with tokens.
75 > */
76 > readonly tokenFontMap: IFontTokenOptions[];
77 >
78 > /**
79 > * Defines whether semantic highlighting should be enabled for the theme.
80 > */
81 > readonly semanticHighlighting: boolean;
82 > }
83 >
84 > export class IFontTokenOptions {
85 > fontFamily?: string;
86 > fontSizeMultiplier?: number;
87 > lineHeightMultiplier?: number;
88 > }
89 >
90 > export interface IFileIconTheme {
91 > readonly hasFileIcons: boolean;
92 > readonly hasFolderIcons: boolean;
93 > readonly hidesExplorerArrows: boolean;
94 > }
95 >
96 > export interface IProductIconTheme {
97 > /**
98 > * Resolves the definition for the given icon as defined by the theme.
99 > *
100 > * @param iconContribution The icon
101 > */
102 > getIcon(iconContribution: IconContribution): IconDefinition | undefined;
103 > }
104 >
105 >
106 > export interface ICssStyleCollector {
107 > addRule(rule: string): void;
108 > }
109 >
110 > export interface IThemingParticipant {
111 > (theme: IColorTheme, collector: ICssStyleCollector, environment: IEnvironmentService): void;
112 > }
113 >
114 > export interface IThemeService {
115 > readonly _serviceBrand: undefined;
116 >
117 > getColorTheme(): IColorTheme;
118 >
119 > readonly onDidColorThemeChange: Event<IColorTheme>;
120 >
121 > getFileIconTheme(): IFileIconTheme;
122 >
123 > readonly onDidFileIconThemeChange: Event<IFileIconTheme>;
124 >
125 > getProductIconTheme(): IProductIconTheme;
126 >
127 > readonly onDidProductIconThemeChange: Event<IProductIconTheme>;
128 >
129 > }
130 >
131 > // static theming participant
132 > export const Extensions = {
133 > ThemingContribution: 'base.contributions.theming'
134 > };
135 >
136 > export interface IThemingRegistry {
137 >
138 > /**
139 > * Register a theming participant that is invoked on every theme change.
140 > */
141 > onColorThemeChange(participant: IThemingParticipant): IDisposable;
142 >
143 > getThemingParticipants(): IThemingParticipant[];
144 >
145 > readonly onThemingParticipantAdded: Event<IThemingParticipant>;
146 > }
147 >
148 > class ThemingRegistry extends Disposable implements IThemingRegistry {
149 > private themingParticipants: IThemingParticipant[] = [];
150 > private readonly onThemingParticipantAddedEmitter: Emitter<IThemingParticipant>;
151 >
152 > constructor() {
153 > super();
154 > this.themingParticipants = [];
155 > this.onThemingParticipantAddedEmitter = this._register(new Emitter<IThemingParticipant>());
156 > }
157 >
158 > public onColorThemeChange(participant: IThemingParticipant): IDisposable {
159 > this.themingParticipants.push(participant); themeService.ts
160 > this.onThemingParticipantAddedEmitter.fire(participant);
161 > return toDisposable(() => {
162 const idx = this.themingParticipants.indexOf(participant);
163 this.themingParticipants.splice(idx, 1);
164 > }); themeService.ts
165 > }
167 > public get onThemingParticipantAdded(): Event<IThemingParticipant> {
168 return this.onThemingParticipantAddedEmitter.event;
169 }
171 > public getThemingParticipants(): IThemingParticipant[] {
172 return this.themingParticipants;
173 }
174 > } themeService.ts
175 >
176 > const themingRegistry = new ThemingRegistry();
177 > platform.Registry.add(Extensions.ThemingContribution, themingRegistry);
178 >
179 > export function registerThemingParticipant(participant: IThemingParticipant): IDisposable {
180 > return themingRegistry.onColorThemeChange(participant); themeService.ts
181 > }
183 > /**
184 > * Utility base class for all themable components.
185 > */
186 > export class Themable extends Disposable {
187 > protected theme: IColorTheme;
188 >
189 > constructor(
190 protected themeService: IThemeService
191 ) {
197 this._register(this.themeService.onDidColorThemeChange(theme => this.onThemeChange(theme)));
198 }
200 > protected onThemeChange(theme: IColorTheme): void {
201 this.theme = theme;
202
203 this.updateStyles();
204 }
206 > updateStyles(): void {
207 // Subclasses to override
208 }
210 > protected getColor(id: string, modify?: (color: Color, theme: IColorTheme) => Color): string | null {
211 let color = this.theme.getColor(id);
212
217 return color ? color.toString() : null;
218 }
219 > } themeService.ts
220 >
221 > export interface IPartsSplash {
222 > zoomLevel: number | undefined;
223 > baseTheme: ThemeTypeSelector;
224 > colorInfo: {
225 > background: string;
226 > foreground: string | undefined;
227 > editorBackground: string | undefined;
228 > titleBarBackground: string | undefined;
229 > titleBarBorder: string | undefined;
230 > activityBarBackground: string | undefined;
231 > activityBarBorder: string | undefined;
232 > sideBarBackground: string | undefined;
233 > sideBarBorder: string | undefined;
234 > panelBackground: string | undefined;
235 > editorGroupBorder: string | undefined;
236 > agentsPanelBackground: string | undefined;
237 > agentsPanelBorder: string | undefined;
238 > statusBarBackground: string | undefined;
239 > statusBarBorder: string | undefined;
240 > statusBarNoFolderBackground: string | undefined;
241 > windowBorder: string | undefined;
242 > };
243 > layoutInfo: {
244 > sideBarSide: string;
245 > editorPartMinWidth: number;
246 > titleBarHeight: number;
247 > activityBarWidth: number;
248 > sideBarWidth: number;
249 > auxiliaryBarWidth: number;
250 > statusBarHeight: number;
251 > windowBorder: boolean;
252 > windowBorderRadius: string | undefined;
253 > modernUI: boolean;
254 > partBounds: {
255 > sideBar: { top: number; left: number; width: number; height: number } | undefined;
256 > auxiliaryBar: { top: number; left: number; width: number; height: number } | undefined;
257 > panel: { top: number; left: number; width: number; height: number } | undefined;
258 > editor: { top: number; left: number; width: number; height: number } | undefined;
259 > } | undefined;
260 > } | undefined;
261 > }
src/vs/editor/common/tokens/lineTokens.ts 214 covered LOC · 55 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lineTokens.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 { ILanguageIdCodec } from '../languages.js';
7 > import { FontStyle, ColorId, StandardTokenType, MetadataConsts, ITokenPresentation, TokenMetadata } from '../encodedTokenAttributes.js';
8 > import { IPosition } from '../core/position.js';
9 > import { ITextModel } from '../model.js';
10 > import { OffsetRange } from '../core/ranges/offsetRange.js';
11 > import { onUnexpectedError } from '../../../base/common/errors.js';
12 >
13 >
14 > export interface IViewLineTokens {
15 > languageIdCodec: ILanguageIdCodec;
16 > equals(other: IViewLineTokens): boolean;
17 > getCount(): number;
18 > getStandardTokenType(tokenIndex: number): StandardTokenType;
19 > getForeground(tokenIndex: number): ColorId;
20 > getEndOffset(tokenIndex: number): number;
21 > getClassName(tokenIndex: number): string;
22 > getInlineStyle(tokenIndex: number, colorMap: string[]): string;
23 > getPresentation(tokenIndex: number): ITokenPresentation;
24 > findTokenIndexAtOffset(offset: number): number;
25 > getLineContent(): string;
26 > getMetadata(tokenIndex: number): number;
27 > getLanguageId(tokenIndex: number): string;
28 > getTokenText(tokenIndex: number): string;
29 > forEach(callback: (tokenIndex: number) => void): void;
30 > }
31 >
32 > export class LineTokens implements IViewLineTokens {
33 > public static createEmpty(lineContent: string, decoder: ILanguageIdCodec): LineTokens {
34 > const defaultMetadata = LineTokens.defaultTokenMetadata;
35 >
36 > const tokens = new Uint32Array(2);
37 > tokens[0] = lineContent.length;
38 > tokens[1] = defaultMetadata;
39 >
40 > return new LineTokens(tokens, lineContent, decoder);
41 > }
42 >
43 > public static createFromTextAndMetadata(data: { text: string; metadata: number }[], decoder: ILanguageIdCodec): LineTokens {
44 let offset: number = 0;
45 let fullText: string = '';
52 return new LineTokens(new Uint32Array(tokens), fullText, decoder);
53 }
55 > public static convertToEndOffset(tokens: Uint32Array, lineTextLength: number): void {
56 const tokenCount = (tokens.length >>> 1);
57 const lastTokenIndex = tokenCount - 1;
61 tokens[lastTokenIndex << 1] = lineTextLength;
62 }
64 > public static findIndexInTokensArray(tokens: Uint32Array, desiredIndex: number): number {
65 if (tokens.length <= 2) {
66 return 0;
86 return low;
87 }
89 > _lineTokensBrand: void = undefined;
90 >
91 > private readonly _tokens: Uint32Array;
92 > private readonly _tokensCount: number;
93 > private readonly _text: string;
94 >
95 > public readonly languageIdCodec: ILanguageIdCodec;
96 >
97 > public static defaultTokenMetadata = (
98 > (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)
99 > | (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)
100 > | (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)
101 > ) >>> 0;
102 >
103 > constructor(tokens: Uint32Array, text: string, decoder: ILanguageIdCodec) {
104 const tokensLength = tokens.length > 1 ? tokens[tokens.length - 2] : 0;
105 if (tokensLength !== text.length) {
111 this.languageIdCodec = decoder;
112 }
114 > public getTextLength(): number {
115 return this._text.length;
116 }
118 > public equals(other: IViewLineTokens): boolean {
119 if (other instanceof LineTokens) {
120 return this.slicedEquals(other, 0, this._tokensCount);
122 return false;
123 }
125 > public slicedEquals(other: LineTokens, sliceFromTokenIndex: number, sliceTokenCount: number): boolean {
126 if (this._text !== other._text) {
127 return false;
139 return true;
140 }
142 > public getLineContent(): string {
143 return this._text;
144 }
146 > public getCount(): number {
147 return this._tokensCount;
148 }
150 > public getStartOffset(tokenIndex: number): number {
151 if (tokenIndex > 0) {
152 return this._tokens[(tokenIndex - 1) << 1];
154 return 0;
155 }
157 > public getMetadata(tokenIndex: number): number {
158 const metadata = this._tokens[(tokenIndex << 1) + 1];
159 return metadata;
160 }
162 > public getLanguageId(tokenIndex: number): string {
163 const metadata = this._tokens[(tokenIndex << 1) + 1];
164 const languageId = TokenMetadata.getLanguageId(metadata);
165 return this.languageIdCodec.decodeLanguageId(languageId);
166 }
168 > public getStandardTokenType(tokenIndex: number): StandardTokenType {
169 const metadata = this._tokens[(tokenIndex << 1) + 1];
170 return TokenMetadata.getTokenType(metadata);
171 }
173 > public getForeground(tokenIndex: number): ColorId {
174 const metadata = this._tokens[(tokenIndex << 1) + 1];
175 return TokenMetadata.getForeground(metadata);
176 }
178 > public getClassName(tokenIndex: number): string {
179 const metadata = this._tokens[(tokenIndex << 1) + 1];
180 return TokenMetadata.getClassNameFromMetadata(metadata);
181 }
183 > public getInlineStyle(tokenIndex: number, colorMap: string[]): string {
184 const metadata = this._tokens[(tokenIndex << 1) + 1];
185 return TokenMetadata.getInlineStyleFromMetadata(metadata, colorMap);
186 }
188 > public getPresentation(tokenIndex: number): ITokenPresentation {
189 const metadata = this._tokens[(tokenIndex << 1) + 1];
190 return TokenMetadata.getPresentationFromMetadata(metadata);
191 }
193 > public getEndOffset(tokenIndex: number): number {
194 return this._tokens[tokenIndex << 1];
195 }
197 > /**
198 > * Find the token containing offset `offset`.
199 > * @param offset The search offset
200 > * @return The index of the token containing the offset.
201 > */
202 > public findTokenIndexAtOffset(offset: number): number {
203 return LineTokens.findIndexInTokensArray(this._tokens, offset);
204 }
206 > public inflate(): IViewLineTokens {
207 return this;
208 }
210 > public sliceAndInflate(startOffset: number, endOffset: number, deltaOffset: number): IViewLineTokens {
211 return new SliceLineTokens(this, startOffset, endOffset, deltaOffset);
212 }
214 > public sliceZeroCopy(range: OffsetRange): IViewLineTokens {
215 return this.sliceAndInflate(range.start, range.endExclusive, 0);
216 }
218 > /**
219 > * @pure
220 > * @param insertTokens Must be sorted by offset.
221 > */
222 > public withInserted(insertTokens: { offset: number; text: string; tokenMetadata: number }[]): LineTokens {
223 if (insertTokens.length === 0) {
224 return this;
262 return new LineTokens(new Uint32Array(newTokens), text, this.languageIdCodec);
263 }
265 > public getTokensInRange(range: OffsetRange): TokenArray {
266 const builder = new TokenArrayBuilder();
267
279 return builder.build();
280 }
282 > public getTokenText(tokenIndex: number): string {
283 const startOffset = this.getStartOffset(tokenIndex);
284 const endOffset = this.getEndOffset(tokenIndex);
286 return text;
287 }
289 > public forEach(callback: (tokenIndex: number) => void): void {
290 const tokenCount = this.getCount();
291 for (let tokenIndex = 0; tokenIndex < tokenCount; tokenIndex++) {
293 }
294 }
296 > toString(): string {
297 let result = '';
298 this.forEach((i) => {
301 return result;
302 }
303 > } lineTokens.ts
304 >
305 > class SliceLineTokens implements IViewLineTokens {
306 >
307 > private readonly _source: LineTokens;
308 > private readonly _startOffset: number;
309 > private readonly _endOffset: number;
310 > private readonly _deltaOffset: number;
311 >
312 > private readonly _firstTokenIndex: number;
313 > private readonly _tokensCount: number;
314 >
315 > public readonly languageIdCodec: ILanguageIdCodec;
316 >
317 > constructor(source: LineTokens, startOffset: number, endOffset: number, deltaOffset: number) {
318 this._source = source;
319 this._startOffset = startOffset;
332 }
333 }
335 > public getMetadata(tokenIndex: number): number {
336 return this._source.getMetadata(this._firstTokenIndex + tokenIndex);
337 }
339 > public getLanguageId(tokenIndex: number): string {
340 return this._source.getLanguageId(this._firstTokenIndex + tokenIndex);
341 }
343 > public getLineContent(): string {
344 return this._source.getLineContent().substring(this._startOffset, this._endOffset);
345 }
347 > public equals(other: IViewLineTokens): boolean {
348 if (other instanceof SliceLineTokens) {
349 return (
356 return false;
357 }
359 > public getCount(): number {
360 return this._tokensCount;
361 }
363 > public getStandardTokenType(tokenIndex: number): StandardTokenType {
364 return this._source.getStandardTokenType(this._firstTokenIndex + tokenIndex);
365 }
367 > public getForeground(tokenIndex: number): ColorId {
368 return this._source.getForeground(this._firstTokenIndex + tokenIndex);
369 }
371 > public getEndOffset(tokenIndex: number): number {
372 const tokenEndOffset = this._source.getEndOffset(this._firstTokenIndex + tokenIndex);
373 return Math.min(this._endOffset, tokenEndOffset) - this._startOffset + this._deltaOffset;
374 }
376 > public getClassName(tokenIndex: number): string {
377 return this._source.getClassName(this._firstTokenIndex + tokenIndex);
378 }
380 > public getInlineStyle(tokenIndex: number, colorMap: string[]): string {
381 return this._source.getInlineStyle(this._firstTokenIndex + tokenIndex, colorMap);
382 }
384 > public getPresentation(tokenIndex: number): ITokenPresentation {
385 return this._source.getPresentation(this._firstTokenIndex + tokenIndex);
386 }
388 > public findTokenIndexAtOffset(offset: number): number {
389 return this._source.findTokenIndexAtOffset(offset + this._startOffset - this._deltaOffset) - this._firstTokenIndex;
390 }
392 > public getTokenText(tokenIndex: number): string {
393 const adjustedTokenIndex = this._firstTokenIndex + tokenIndex;
394 const tokenStartOffset = this._source.getStartOffset(adjustedTokenIndex);
403 return text;
404 }
406 > public forEach(callback: (tokenIndex: number) => void): void {
407 for (let tokenIndex = 0; tokenIndex < this.getCount(); tokenIndex++) {
408 callback(tokenIndex);
409 }
410 }
411 > } lineTokens.ts
412 >
413 > export function getStandardTokenTypeAtPosition(model: ITextModel, position: IPosition): StandardTokenType | undefined {
414 const lineNumber = position.lineNumber;
415 if (!model.tokenization.isCheapToTokenize(lineNumber)) {
422 return tokenType;
423 }
425 >
426 >
427 > /**
428 > * This class represents a sequence of tokens.
429 > * Conceptually, each token has a length and a metadata number.
430 > * A token array might be used to annotate a string with metadata.
431 > * Use {@link TokenArrayBuilder} to efficiently create a token array.
432 > *
433 > * TODO: Make this class more efficient (e.g. by using a Int32Array).
434 > */
435 > export class TokenArray {
436 > public static fromLineTokens(lineTokens: LineTokens): TokenArray {
437 > const tokenInfo: TokenInfo[] = [];
438 > for (let i = 0; i < lineTokens.getCount(); i++) {
439 > tokenInfo.push(new TokenInfo(lineTokens.getEndOffset(i) - lineTokens.getStartOffset(i), lineTokens.getMetadata(i)));
440 > }
441 > return TokenArray.create(tokenInfo);
442 > }
443 >
444 > public static create(tokenInfo: TokenInfo[]): TokenArray {
445 return new TokenArray(tokenInfo);
446 }
448 > private constructor(
449 private readonly _tokenInfo: TokenInfo[]
450 ) { }
452 > public toLineTokens(lineContent: string, decoder: ILanguageIdCodec): LineTokens {
453 return LineTokens.createFromTextAndMetadata(this.map((r, t) => ({ text: r.substring(lineContent), metadata: t.metadata })), decoder);
454 }
456 > public forEach(cb: (range: OffsetRange, tokenInfo: TokenInfo) => void): void {
457 let lengthSum = 0;
458 for (const tokenInfo of this._tokenInfo) {
462 }
463 }
465 > public map<T>(cb: (range: OffsetRange, tokenInfo: TokenInfo) => T): T[] {
466 const result: T[] = [];
467 let lengthSum = 0;
473 return result;
474 }
476 > public slice(range: OffsetRange): TokenArray {
477 const result: TokenInfo[] = [];
478 let lengthSum = 0;
495 return TokenArray.create(result);
496 }
498 > public append(other: TokenArray): TokenArray {
499 const result: TokenInfo[] = this._tokenInfo.concat(other._tokenInfo);
500 return TokenArray.create(result);
501 }
502 > } lineTokens.ts
503 >
504 > export type ITokenMetadata = number;
505 >
506 > export class TokenInfo {
507 > constructor(
508 public readonly length: number,
509 public readonly metadata: ITokenMetadata
510 ) { }
511 > } lineTokens.ts
512 > /**
513 > * TODO: Make this class more efficient (e.g. by using a Int32Array).
514 > */
515 >
516 > export class TokenArrayBuilder {
517 private readonly _tokens: TokenInfo[] = [];
519 > public add(length: number, metadata: ITokenMetadata): void {
520 this._tokens.push(new TokenInfo(length, metadata));
521 }
523 > public build(): TokenArray {
524 return TokenArray.create(this._tokens);
525 }
526 > } lineTokens.ts
527
src/vs/nls.ts 211 covered LOC · 17 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) => { nls.ts
34 > const index = rest[0];
35 > const arg = args[index];
36 > let result = match;
37 > if (typeof arg === 'string') {
38 > result = arg; nls.ts
39 > } else if (typeof arg === 'number' || typeof arg === 'boolean' || arg === void 0 || arg === null) { nls.ts
40 result = String(arg);
41 }
42 > return result; nls.ts
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/config/fontInfo.ts 208 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- fontInfo.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 platform from '../../../base/common/platform.js';
7 > import { EditorOption, FindComputedEditorOptionValueById } from './editorOptions.js';
8 > import { EditorZoom } from './editorZoom.js';
9 >
10 > /**
11 > * Determined from empirical observations.
12 > * @internal
13 > */
14 > export const GOLDEN_LINE_HEIGHT_RATIO = platform.isMacintosh ? 1.5 : 1.35;
15 >
16 > /**
17 > * @internal
18 > */
19 > export const MINIMUM_LINE_HEIGHT = 8;
20 >
21 > /**
22 > * @internal
23 > */
24 > export interface IValidatedEditorOptions {
25 > get<T extends EditorOption>(id: T): FindComputedEditorOptionValueById<T>;
26 > }
27 >
28 > export class BareFontInfo {
29 > readonly _bareFontInfoBrand: void = undefined;
30 >
31 > /**
32 > * @internal
33 > */
34 > public static _create(fontFamily: string, fontWeight: string, fontSize: number, fontFeatureSettings: string, fontVariationSettings: string, lineHeight: number, letterSpacing: number, pixelRatio: number, ignoreEditorZoom: boolean): BareFontInfo {
35 > if (lineHeight === 0) {
36 > lineHeight = GOLDEN_LINE_HEIGHT_RATIO * fontSize;
37 > } else if (lineHeight < MINIMUM_LINE_HEIGHT) {
38 > // Values too small to be line heights in pixels are in ems.
39 > lineHeight = lineHeight * fontSize;
40 > }
41 >
42 > // Enforce integer, minimum constraints
43 > lineHeight = Math.round(lineHeight);
44 > if (lineHeight < MINIMUM_LINE_HEIGHT) {
45 > lineHeight = MINIMUM_LINE_HEIGHT;
46 > }
47 >
48 > const editorZoomLevelMultiplier = 1 + (ignoreEditorZoom ? 0 : EditorZoom.getZoomLevel() * 0.1);
49 > fontSize *= editorZoomLevelMultiplier;
50 > lineHeight *= editorZoomLevelMultiplier;
51 >
52 > if (fontVariationSettings === FONT_VARIATION_TRANSLATE) {
53 > if (fontWeight === 'normal' || fontWeight === 'bold') {
54 > fontVariationSettings = FONT_VARIATION_OFF;
55 > } else {
56 > const fontWeightAsNumber = parseInt(fontWeight, 10);
57 > fontVariationSettings = `'wght' ${fontWeightAsNumber}`;
58 > fontWeight = 'normal';
59 > }
60 > }
61 >
62 > return new BareFontInfo({
63 > pixelRatio: pixelRatio,
64 > fontFamily: fontFamily,
65 > fontWeight: fontWeight,
66 > fontSize: fontSize,
67 > fontFeatureSettings: fontFeatureSettings,
68 > fontVariationSettings,
69 > lineHeight: lineHeight,
70 > letterSpacing: letterSpacing
71 > });
72 > }
73 >
74 > readonly pixelRatio: number;
75 > readonly fontFamily: string;
76 > readonly fontWeight: string;
77 > readonly fontSize: number;
78 > readonly fontFeatureSettings: string;
79 > readonly fontVariationSettings: string;
80 > readonly lineHeight: number;
81 > readonly letterSpacing: number;
82 >
83 > /**
84 > * @internal
85 > */
86 > protected constructor(opts: {
87 > pixelRatio: number;
88 > fontFamily: string;
89 > fontWeight: string;
90 > fontSize: number;
91 > fontFeatureSettings: string;
92 > fontVariationSettings: string;
93 > lineHeight: number;
94 > letterSpacing: number;
95 > }) {
96 > this.pixelRatio = opts.pixelRatio;
97 > this.fontFamily = String(opts.fontFamily);
98 > this.fontWeight = String(opts.fontWeight);
99 > this.fontSize = opts.fontSize;
100 > this.fontFeatureSettings = opts.fontFeatureSettings;
101 > this.fontVariationSettings = opts.fontVariationSettings;
102 > this.lineHeight = opts.lineHeight | 0;
103 > this.letterSpacing = opts.letterSpacing;
104 > }
105 >
106 > /**
107 > * @internal
108 > */
109 > public getId(): string {
110 return `${this.pixelRatio}-${this.fontFamily}-${this.fontWeight}-${this.fontSize}-${this.fontFeatureSettings}-${this.fontVariationSettings}-${this.lineHeight}-${this.letterSpacing}`;
111 }
112 > fontInfo.ts
113 > /**
114 > * @internal
115 > */
116 > public getMassagedFontFamily(): string {
117 const fallbackFontFamily = EDITOR_FONT_DEFAULTS.fontFamily;
118 const fontFamily = BareFontInfo._wrapInQuotes(this.fontFamily);
122 return fontFamily;
123 }
124 > fontInfo.ts
125 > private static _wrapInQuotes(fontFamily: string): string {
126 if (/[,"']/.test(fontFamily)) {
127 // Looks like the font family might be already escaped
134 return fontFamily;
135 }
136 > } fontInfo.ts
137 >
138 > // change this whenever `FontInfo` members are changed
139 > export const SERIALIZED_FONT_INFO_VERSION = 2;
140 >
141 > export class FontInfo extends BareFontInfo {
142 > readonly _editorStylingBrand: void = undefined;
143 >
144 > readonly version: number = SERIALIZED_FONT_INFO_VERSION;
145 > readonly isTrusted: boolean;
146 > readonly isMonospace: boolean;
147 > readonly typicalHalfwidthCharacterWidth: number;
148 > readonly typicalFullwidthCharacterWidth: number;
149 > readonly canUseHalfwidthRightwardsArrow: boolean;
150 > readonly spaceWidth: number;
151 > readonly middotWidth: number;
152 > readonly wsmiddotWidth: number;
153 > readonly maxDigitWidth: number;
154 >
155 > /**
156 > * @internal
157 > */
158 > constructor(opts: {
159 > pixelRatio: number;
160 > fontFamily: string;
161 > fontWeight: string;
162 > fontSize: number;
163 > fontFeatureSettings: string;
164 > fontVariationSettings: string;
165 > lineHeight: number;
166 > letterSpacing: number;
167 > isMonospace: boolean;
168 > typicalHalfwidthCharacterWidth: number;
169 > typicalFullwidthCharacterWidth: number;
170 > canUseHalfwidthRightwardsArrow: boolean;
171 > spaceWidth: number;
172 > middotWidth: number;
173 > wsmiddotWidth: number;
174 > maxDigitWidth: number;
175 > }, isTrusted: boolean) {
176 > super(opts);
177 > this.isTrusted = isTrusted;
178 > this.isMonospace = opts.isMonospace;
179 > this.typicalHalfwidthCharacterWidth = opts.typicalHalfwidthCharacterWidth;
180 > this.typicalFullwidthCharacterWidth = opts.typicalFullwidthCharacterWidth;
181 > this.canUseHalfwidthRightwardsArrow = opts.canUseHalfwidthRightwardsArrow;
182 > this.spaceWidth = opts.spaceWidth;
183 > this.middotWidth = opts.middotWidth;
184 > this.wsmiddotWidth = opts.wsmiddotWidth;
185 > this.maxDigitWidth = opts.maxDigitWidth;
186 > }
187 >
188 > /**
189 > * @internal
190 > */
191 > public equals(other: FontInfo): boolean {
192 return (
193 this.fontFamily === other.fontFamily
207 );
208 }
209 > } fontInfo.ts
210 > /**
211 > * @internal
212 > */
213 > export const FONT_VARIATION_OFF = 'normal';
214 > /**
215 > * @internal
216 > */
217 > export const FONT_VARIATION_TRANSLATE = 'translate';
218 >
219 > /**
220 > * @internal
221 > */
222 > export const DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \'Courier New\', monospace';
223 > /**
224 > * @internal
225 > */
226 > export const DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \'Courier New\', monospace';
227 > /**
228 > * @internal
229 > */
230 > export const DEFAULT_LINUX_FONT_FAMILY = '\'Droid Sans Mono\', monospace';
231 > /**
232 > * @internal
233 > */
234 > export const EDITOR_FONT_DEFAULTS = {
235 > fontFamily: (
236 > platform.isMacintosh ? DEFAULT_MAC_FONT_FAMILY : (platform.isWindows ? DEFAULT_WINDOWS_FONT_FAMILY : DEFAULT_LINUX_FONT_FAMILY)
237 > ),
238 > fontWeight: 'normal',
239 > fontSize: (
240 > platform.isMacintosh ? 12 : 14
241 > ),
242 > lineHeight: 0,
243 > letterSpacing: 0,
244 > };
src/vs/platform/configuration/common/configuration.ts 208 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- configuration.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 { assertNever } from '../../../base/common/assert.js';
7 > import { IStringDictionary } from '../../../base/common/collections.js';
8 > import { Event } from '../../../base/common/event.js';
9 > import * as types from '../../../base/common/types.js';
10 > import { URI, UriComponents } from '../../../base/common/uri.js';
11 > import { createDecorator } from '../../instantiation/common/instantiation.js';
12 > import { IWorkspaceFolder } from '../../workspace/common/workspace.js';
13 >
14 > export const IConfigurationService = createDecorator<IConfigurationService>('configurationService');
15 >
16 > export function isConfigurationOverrides(obj: unknown): obj is IConfigurationOverrides {
17 const thing = obj as IConfigurationOverrides;
18 return thing
21 && (!thing.resource || thing.resource instanceof URI);
22 }
24 > export interface IConfigurationOverrides {
25 > overrideIdentifier?: string | null;
26 > resource?: URI | null;
27 > }
28 >
29 > export function isConfigurationUpdateOverrides(obj: unknown): obj is IConfigurationUpdateOverrides {
30 const thing = obj as IConfigurationUpdateOverrides | IConfigurationOverrides;
31 return thing
35 && (!thing.resource || thing.resource instanceof URI);
36 }
38 > export type IConfigurationUpdateOverrides = Omit<IConfigurationOverrides, 'overrideIdentifier'> & { overrideIdentifiers?: string[] | null };
39 >
40 > export const enum ConfigurationTarget {
41 > APPLICATION = 1,
42 > USER,
43 > USER_LOCAL,
44 > USER_REMOTE,
45 > WORKSPACE,
46 > WORKSPACE_FOLDER,
47 > DEFAULT,
48 > MEMORY
49 > }
50 > export function ConfigurationTargetToString(configurationTarget: ConfigurationTarget) {
51 switch (configurationTarget) {
52 case ConfigurationTarget.APPLICATION: return 'APPLICATION';
60 }
61 }
63 > export interface IConfigurationChange {
64 > keys: string[];
65 > overrides: [string, string[]][];
66 > }
67 >
68 > export interface IConfigurationChangeEvent {
69 >
70 > readonly source: ConfigurationTarget;
71 > readonly affectedKeys: ReadonlySet<string>;
72 > readonly change: IConfigurationChange;
73 >
74 > affectsConfiguration(configuration: string, overrides?: IConfigurationOverrides): boolean;
75 > }
76 >
77 > export interface IInspectValue<T> {
78 > readonly value?: T;
79 > readonly override?: T;
80 > readonly overrides?: { readonly identifiers: string[]; readonly value: T }[];
81 > }
82 >
83 > export interface IConfigurationValue<T> {
84 >
85 > readonly defaultValue?: T;
86 > readonly applicationValue?: T;
87 > readonly userValue?: T;
88 > readonly userLocalValue?: T;
89 > readonly userRemoteValue?: T;
90 > readonly workspaceValue?: T;
91 > readonly workspaceFolderValue?: T;
92 > readonly memoryValue?: T;
93 > readonly policyValue?: T;
94 > readonly value?: T;
95 >
96 > readonly default?: IInspectValue<T>;
97 > readonly application?: IInspectValue<T>;
98 > readonly user?: IInspectValue<T>;
99 > readonly userLocal?: IInspectValue<T>;
100 > readonly userRemote?: IInspectValue<T>;
101 > readonly workspace?: IInspectValue<T>;
102 > readonly workspaceFolder?: IInspectValue<T>;
103 > readonly memory?: IInspectValue<T>;
104 > readonly policy?: { value?: T };
105 >
106 > readonly overrideIdentifiers?: string[];
107 > }
108 >
109 > export function getConfigValueInTarget<T>(configValue: IConfigurationValue<T>, scope: ConfigurationTarget): T | undefined {
110 switch (scope) {
111 case ConfigurationTarget.APPLICATION:
129 }
130 }
132 > export function isConfigured<T>(configValue: IConfigurationValue<T>): configValue is IConfigurationValue<T> & { value: T } {
133 return configValue.applicationValue !== undefined ||
134 configValue.userValue !== undefined ||
138 configValue.workspaceFolderValue !== undefined;
139 }
141 > export interface IConfigurationUpdateOptions {
142 > /**
143 > * If `true`, do not notifies the error to user by showing the message box. Default is `false`.
144 > */
145 > donotNotifyError?: boolean;
146 > /**
147 > * How to handle dirty file when updating the configuration.
148 > */
149 > handleDirtyFile?: 'save' | 'revert';
150 > }
151 >
152 > export interface IConfigurationService {
153 > readonly _serviceBrand: undefined;
154 >
155 > readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent>;
156 >
157 > getConfigurationData(): IConfigurationData | null;
158 >
159 > /**
160 > * Fetches the value of the section for the given overrides.
161 > * Value can be of native type or an object keyed off the section name.
162 > *
163 > * @param section - Section of the configuration. Can be `null` or `undefined`.
164 > * @param overrides - Overrides that has to be applied while fetching
165 > *
166 > */
167 > getValue<T>(): T;
168 > getValue<T>(section: string): T;
169 > getValue<T>(overrides: IConfigurationOverrides): T;
170 > getValue<T>(section: string, overrides: IConfigurationOverrides): T;
171 >
172 > /**
173 > * Update a configuration value.
174 > *
175 > * Use `target` to update the configuration in a specific `ConfigurationTarget`.
176 > *
177 > * Use `overrides` to update the configuration for a resource or for override identifiers or both.
178 > *
179 > * Passing a resource through overrides will update the configuration in the workspace folder containing that resource.
180 > *
181 > * *Note 1:* Updating configuration to a default value will remove the configuration from the requested target. If not target is passed, it will be removed from all writeable targets.
182 > *
183 > * *Note 2:* Use `undefined` value to remove the configuration from the given target. If not target is passed, it will be removed from all writeable targets.
184 > *
185 > * Use `donotNotifyError` and set it to `true` to surpresss errors.
186 > *
187 > * @param key setting to be updated
188 > * @param value The new value
189 > */
190 > updateValue(key: string, value: unknown): Promise<void>;
191 > updateValue(key: string, value: unknown, target: ConfigurationTarget): Promise<void>;
192 > updateValue(key: string, value: unknown, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides): Promise<void>;
193 > updateValue(key: string, value: unknown, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides, target: ConfigurationTarget, options?: IConfigurationUpdateOptions): Promise<void>;
194 >
195 > inspect<T>(key: string, overrides?: IConfigurationOverrides): IConfigurationValue<Readonly<T>>;
196 >
197 > reloadConfiguration(target?: ConfigurationTarget | IWorkspaceFolder): Promise<void>;
198 >
199 > keys(): {
200 > default: string[];
201 > policy: string[];
202 > user: string[];
203 > workspace: string[];
204 > workspaceFolder: string[];
205 > memory?: string[];
206 > };
207 > }
208 >
209 > export interface IConfigurationModel {
210 > contents: IStringDictionary<unknown>;
211 > keys: string[];
212 > overrides: IOverrides[];
213 > raw?: ReadonlyArray<IStringDictionary<unknown>> | IStringDictionary<unknown>;
214 > }
215 >
216 > export interface IOverrides {
217 > keys: string[];
218 > contents: IStringDictionary<unknown>;
219 > identifiers: string[];
220 > }
221 >
222 > export interface IConfigurationData {
223 > defaults: IConfigurationModel;
224 > policy: IConfigurationModel;
225 > application: IConfigurationModel;
226 > userLocal: IConfigurationModel;
227 > userRemote: IConfigurationModel;
228 > workspace: IConfigurationModel;
229 > folders: [UriComponents, IConfigurationModel][];
230 > }
231 >
232 > export interface IConfigurationCompareResult {
233 > added: string[];
234 > removed: string[];
235 > updated: string[];
236 > overrides: [string, string[]][];
237 > }
238 >
239 > export function toValuesTree(properties: IStringDictionary<unknown>, conflictReporter: (message: string) => void): IStringDictionary<unknown> {
240 const root = Object.create(null);
241
246 return root;
247 }
249 > export function addToValueTree(settingsTreeRoot: IStringDictionary<unknown>, key: string, value: unknown, conflictReporter: (message: string) => void): void {
250 const segments = key.split('.');
251 const last = segments.pop()!;
282 }
283 }
285 > export function removeFromValueTree(valueTree: IStringDictionary<unknown>, key: string): void {
286 const segments = key.split('.');
287 doRemoveFromValueTree(valueTree, segments);
288 }
290 function doRemoveFromValueTree(valueTree: IStringDictionary<unknown> | unknown, segments: string[]): void {
291 if (!valueTree) {
311 }
312 }
314 > /**
315 > * A helper function to get the configuration value with a specific settings path (e.g. config.some.setting)
316 > */
317 > export function getConfigurationValue<T>(config: IStringDictionary<unknown>, settingPath: string): T | undefined;
318 > export function getConfigurationValue<T>(config: IStringDictionary<unknown>, settingPath: string, defaultValue: T): T;
319 > export function getConfigurationValue<T>(config: IStringDictionary<unknown>, settingPath: string, defaultValue?: T): T | undefined {
320 function accessSetting(config: IStringDictionary<unknown>, path: string[]): unknown {
321 let current: unknown = config;
334 return typeof result === 'undefined' ? defaultValue : result as T;
335 }
337 > export function merge(base: IStringDictionary<unknown>, add: IStringDictionary<unknown>, overwrite: boolean): void {
338 Object.keys(add).forEach(key => {
339 if (key !== '__proto__') {
350 });
351 }
353 > export function getLanguageTagSettingPlainKey(settingKey: string) {
354 > return settingKey configuration.ts
355 > .replace(/^\[/, '')
356 > .replace(/]$/g, '')
357 > .replace(/\]\[/g, ', ');
358 > }
src/vs/base/common/observableInternal/base.ts 206 covered LOC · 2 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- scrollable.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 { Disposable, IDisposable } from './lifecycle.js';
8 >
9 > export const enum ScrollbarVisibility {
10 > Auto = 1,
11 > Hidden = 2,
12 > Visible = 3
13 > }
14 >
15 > export interface ScrollEvent {
16 > inSmoothScrolling: boolean;
17 >
18 > oldWidth: number;
19 > oldScrollWidth: number;
20 > oldScrollLeft: number;
21 >
22 > width: number;
23 > scrollWidth: number;
24 > scrollLeft: number;
25 >
26 > oldHeight: number;
27 > oldScrollHeight: number;
28 > oldScrollTop: number;
29 >
30 > height: number;
31 > scrollHeight: number;
32 > scrollTop: number;
33 >
34 > widthChanged: boolean;
35 > scrollWidthChanged: boolean;
36 > scrollLeftChanged: boolean;
37 >
38 > heightChanged: boolean;
39 > scrollHeightChanged: boolean;
40 > scrollTopChanged: boolean;
41 > }
42 >
43 > export class ScrollState implements IScrollDimensions, IScrollPosition {
44 > _scrollStateBrand: void = undefined;
45 >
46 > public readonly rawScrollLeft: number;
47 > public readonly rawScrollTop: number;
48 >
49 > public readonly width: number;
50 > public readonly scrollWidth: number;
51 > public readonly scrollLeft: number;
52 > public readonly height: number;
53 > public readonly scrollHeight: number;
54 > public readonly scrollTop: number;
55 >
56 > constructor(
57 private readonly _forceIntegerValues: boolean,
58 width: number,
102 this.scrollTop = scrollTop;
103 }
105 > public equals(other: ScrollState): boolean {
106 return (
107 this.rawScrollLeft === other.rawScrollLeft
115 );
116 }
118 > public withScrollDimensions(update: INewScrollDimensions, useRawScrollPositions: boolean): ScrollState {
119 return new ScrollState(
120 this._forceIntegerValues,
127 );
128 }
130 > public withScrollPosition(update: INewScrollPosition): ScrollState {
131 return new ScrollState(
132 this._forceIntegerValues,
139 );
140 }
142 > public createScrollEvent(previous: ScrollState, inSmoothScrolling: boolean): ScrollEvent {
143 const widthChanged = (this.width !== previous.width);
144 const scrollWidthChanged = (this.scrollWidth !== previous.scrollWidth);
176 };
177 }
179 > }
180 >
181 > export interface IScrollDimensions {
182 > readonly width: number;
183 > readonly scrollWidth: number;
184 > readonly height: number;
185 > readonly scrollHeight: number;
186 > }
187 > export interface INewScrollDimensions {
188 > width?: number;
189 > scrollWidth?: number;
190 > height?: number;
191 > scrollHeight?: number;
192 > }
193 >
194 > export interface IScrollPosition {
195 > readonly scrollLeft: number;
196 > readonly scrollTop: number;
197 > }
198 > export interface ISmoothScrollPosition {
199 > readonly scrollLeft: number;
200 > readonly scrollTop: number;
201 >
202 > readonly width: number;
203 > readonly height: number;
204 > }
205 > export interface INewScrollPosition {
206 > scrollLeft?: number;
207 > scrollTop?: number;
208 > }
209 >
210 > export interface IScrollableOptions {
211 > /**
212 > * Define if the scroll values should always be integers.
213 > */
214 > forceIntegerValues: boolean;
215 > /**
216 > * Set the duration (ms) used for smooth scroll animations.
217 > */
218 > smoothScrollDuration: number;
219 > /**
220 > * A function to schedule an update at the next frame (used for smooth scroll animations).
221 > */
222 > scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable;
223 > }
224 >
225 > export class Scrollable extends Disposable {
226 >
227 > _scrollableBrand: void = undefined;
228 >
229 > private _smoothScrollDuration: number;
230 > private readonly _scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable;
231 > private _state: ScrollState;
232 > private _smoothScrolling: SmoothScrollingOperation | null;
233 >
234 > private _onScroll = this._register(new Emitter<ScrollEvent>());
235 > public readonly onScroll: Event<ScrollEvent> = this._onScroll.event;
236 >
237 > constructor(options: IScrollableOptions) {
238 super();
239
243 this._smoothScrolling = null;
244 }
246 > public override dispose(): void {
247 if (this._smoothScrolling) {
248 this._smoothScrolling.dispose();
251 super.dispose();
252 }
254 > public setSmoothScrollDuration(smoothScrollDuration: number): void {
255 this._smoothScrollDuration = smoothScrollDuration;
256 }
258 > public validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition {
259 return this._state.withScrollPosition(scrollPosition);
260 }
262 > public getScrollDimensions(): IScrollDimensions {
263 return this._state;
264 }
266 > public setScrollDimensions(dimensions: INewScrollDimensions, useRawScrollPositions: boolean): void {
267 const newState = this._state.withScrollDimensions(dimensions, useRawScrollPositions);
268 this._setState(newState, Boolean(this._smoothScrolling));
271 this._smoothScrolling?.acceptScrollDimensions(this._state);
272 }
274 > /**
275 > * Returns the final scroll position that the instance will have once the smooth scroll animation concludes.
276 > * If no scroll animation is occurring, it will return the current scroll position instead.
277 > */
278 > public getFutureScrollPosition(): IScrollPosition {
279 if (this._smoothScrolling) {
280 return this._smoothScrolling.to;
282 return this._state;
283 }
285 > /**
286 > * Returns the current scroll position.
287 > * Note: This result might be an intermediate scroll position, as there might be an ongoing smooth scroll animation.
288 > */
289 > public getCurrentScrollPosition(): IScrollPosition {
290 return this._state;
291 }
293 > public setScrollPositionNow(update: INewScrollPosition): void {
294 // no smooth scrolling requested
295 const newState = this._state.withScrollPosition(update);
303 this._setState(newState, false);
304 }
306 > public setScrollPositionSmooth(update: INewScrollPosition, reuseAnimation?: boolean): void {
307 if (this._smoothScrollDuration === 0) {
308 // Smooth scrolling not supported.
348 });
349 }
351 > public hasPendingScrollAnimation(): boolean {
352 return Boolean(this._smoothScrolling);
353 }
355 > private _performSmoothScrolling(): void {
356 if (!this._smoothScrolling) {
357 return;
383 });
384 }
386 > private _setState(newState: ScrollState, inSmoothScrolling: boolean): void {
387 const oldState = this._state;
388 if (oldState.equals(newState)) {
393 this._onScroll.fire(this._state.createScrollEvent(oldState, inSmoothScrolling));
394 }
395 > } scrollable.ts
396 >
397 > export class SmoothScrollingUpdate {
398 >
399 > public readonly scrollLeft: number;
400 > public readonly scrollTop: number;
401 > public readonly isDone: boolean;
402 >
403 > constructor(scrollLeft: number, scrollTop: number, isDone: boolean) {
404 this.scrollLeft = scrollLeft;
405 this.scrollTop = scrollTop;
406 this.isDone = isDone;
407 }
409 > }
410 >
411 > interface IAnimation {
412 > (completion: number): number;
413 > }
414 >
415 function createEaseOutCubic(from: number, to: number): IAnimation {
416 const delta = to - from;
419 };
420 }
422 function createComposed(a: IAnimation, b: IAnimation, cut: number): IAnimation {
423 return function (completion: number): number {
428 };
429 }
431 > export class SmoothScrollingOperation {
432 >
433 > public readonly from: ISmoothScrollPosition;
434 > public to: ISmoothScrollPosition;
435 > public readonly duration: number;
436 > public readonly startTime: number;
437 > public animationFrameDisposable: IDisposable | null;
438 >
439 > private scrollLeft!: IAnimation;
440 > private scrollTop!: IAnimation;
441 >
442 > constructor(from: ISmoothScrollPosition, to: ISmoothScrollPosition, startTime: number, duration: number) {
443 this.from = from;
444 this.to = to;
450 this._initAnimations();
451 }
453 > private _initAnimations(): void {
454 this.scrollLeft = this._initAnimation(this.from.scrollLeft, this.to.scrollLeft, this.to.width);
455 this.scrollTop = this._initAnimation(this.from.scrollTop, this.to.scrollTop, this.to.height);
456 }
458 > private _initAnimation(from: number, to: number, viewportSize: number): IAnimation {
459 const delta = Math.abs(from - to);
460 if (delta > 2.5 * viewportSize) {
472 return createEaseOutCubic(from, to);
473 }
475 > public dispose(): void {
476 if (this.animationFrameDisposable !== null) {
477 this.animationFrameDisposable.dispose();
479 }
480 }
482 > public acceptScrollDimensions(state: ScrollState): void {
483 this.to = state.withScrollPosition(this.to);
484 this._initAnimations();
485 }
487 > public tick(): SmoothScrollingUpdate {
488 return this._tick(Date.now());
489 }
491 > protected _tick(now: number): SmoothScrollingUpdate {
492 const completion = (now - this.startTime) / this.duration;
493
500 return new SmoothScrollingUpdate(this.to.scrollLeft, this.to.scrollTop, true);
501 }
503 > public combine(from: ISmoothScrollPosition, to: ISmoothScrollPosition, duration: number): SmoothScrollingOperation {
504 return SmoothScrollingOperation.start(from, to, duration);
505 }
507 > public static start(from: ISmoothScrollPosition, to: ISmoothScrollPosition, duration: number): SmoothScrollingOperation {
508 // +10 / -10 : pretend the animation already started for a quicker response to a scroll request
509 duration = duration + 10;
512 return new SmoothScrollingOperation(from, to, startTime, duration);
513 }
514 > } scrollable.ts
515 >
516 function easeInCubic(t: number) {
517 return Math.pow(t, 3);
518 }
520 function easeOutCubic(t: number) {
521 return 1 - easeInCubic(1 - t);
src/vs/base/common/observableInternal/logging/debugger/devToolsLogger.ts 204 covered LOC · 24 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- scanner.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 { illegalState } from '../../../base/common/errors.js';
8 > import { localize } from '../../../nls.js';
9 >
10 > export const enum TokenType {
11 > LParen,
12 > RParen,
13 > Neg,
14 > Eq,
15 > NotEq,
16 > Lt,
17 > LtEq,
18 > Gt,
19 > GtEq,
20 > RegexOp,
21 > RegexStr,
22 > True,
23 > False,
24 > In,
25 > Not,
26 > And,
27 > Or,
28 > Str,
29 > QuotedStr,
30 > Error,
31 > EOF,
32 > }
33 >
34 > export type Token =
35 > | { type: TokenType.LParen; offset: number }
36 > | { type: TokenType.RParen; offset: number }
37 > | { type: TokenType.Neg; offset: number }
38 > | { type: TokenType.Eq; offset: number; isTripleEq: boolean }
39 > | { type: TokenType.NotEq; offset: number; isTripleEq: boolean }
40 > | { type: TokenType.Lt; offset: number }
41 > | { type: TokenType.LtEq; offset: number }
42 > | { type: TokenType.Gt; offset: number }
43 > | { type: TokenType.GtEq; offset: number }
44 > | { type: TokenType.RegexOp; offset: number }
45 > | { type: TokenType.RegexStr; offset: number; lexeme: string }
46 > | { type: TokenType.True; offset: number }
47 > | { type: TokenType.False; offset: number }
48 > | { type: TokenType.In; offset: number }
49 > | { type: TokenType.Not; offset: number }
50 > | { type: TokenType.And; offset: number }
51 > | { type: TokenType.Or; offset: number }
52 > | { type: TokenType.Str; offset: number; lexeme: string }
53 > | { type: TokenType.QuotedStr; offset: number; lexeme: string }
54 > | { type: TokenType.Error; offset: number; lexeme: string }
55 > | { type: TokenType.EOF; offset: number };
56 >
57 > type KeywordTokenType = TokenType.Not | TokenType.In | TokenType.False | TokenType.True;
58 > type TokenTypeWithoutLexeme =
59 > TokenType.LParen |
60 > TokenType.RParen |
61 > TokenType.Neg |
62 > TokenType.Lt |
63 > TokenType.LtEq |
64 > TokenType.Gt |
65 > TokenType.GtEq |
66 > TokenType.RegexOp |
67 > TokenType.True |
68 > TokenType.False |
69 > TokenType.In |
70 > TokenType.Not |
71 > TokenType.And |
72 > TokenType.Or |
73 > TokenType.EOF;
74 >
75 > /**
76 > * Example:
77 > * `foo == bar'` - note how single quote doesn't have a corresponding closing quote,
78 > * so it's reported as unexpected
79 > */
80 > export type LexingError = {
81 > offset: number; /** note that this doesn't take into account escape characters from the original encoding of the string, e.g., within an extension manifest file's JSON encoding */
82 > lexeme: string;
83 > additionalInfo?: string;
84 > };
85 >
86 function hintDidYouMean(...meant: string[]) {
87 switch (meant.length) {
96 }
97 }
98 > scanner.ts
99 > const hintDidYouForgetToOpenOrCloseQuote = localize('contextkey.scanner.hint.didYouForgetToOpenOrCloseQuote', "Did you forget to open or close the quote?");
100 > const hintDidYouForgetToEscapeSlash = localize('contextkey.scanner.hint.didYouForgetToEscapeSlash', "Did you forget to escape the '/' (slash) character? Put two backslashes before it to escape, e.g., '\\\\/\'.");
101 >
102 > /**
103 > * A simple scanner for context keys.
104 > *
105 > * Example:
106 > *
107 > * ```ts
108 > * const scanner = new Scanner().reset('resourceFileName =~ /docker/ && !config.docker.enabled');
109 > * const tokens = [...scanner];
110 > * if (scanner.errorTokens.length > 0) {
111 > * scanner.errorTokens.forEach(err => console.error(`Unexpected token at ${err.offset}: ${err.lexeme}\nHint: ${err.additional}`));
112 > * } else {
113 > * // process tokens
114 > * }
115 > * ```
116 > */
117 > export class Scanner {
118 >
119 > static getLexeme(token: Token): string {
120 > switch (token.type) {
121 > case TokenType.LParen:
122 > return '('; scanner.ts
123 > case TokenType.RParen: scanner.ts
124 > return ')'; scanner.ts
125 > case TokenType.Neg: scanner.ts
126 > return '!'; scanner.ts
127 > case TokenType.Eq: scanner.ts
128 > return token.isTripleEq ? '===' : '=='; scanner.ts
129 > case TokenType.NotEq: scanner.ts
130 > return token.isTripleEq ? '!==' : '!='; scanner.ts
131 > case TokenType.Lt: scanner.ts
132 > return '<'; scanner.ts
133 > case TokenType.LtEq: scanner.ts
134 > return '<='; scanner.ts
135 > case TokenType.Gt: scanner.ts
136 > return '>'; scanner.ts
137 > case TokenType.GtEq: scanner.ts
138 > return '>='; scanner.ts
139 > case TokenType.RegexOp: scanner.ts
140 > return '=~'; scanner.ts
141 > case TokenType.RegexStr: scanner.ts
142 > return token.lexeme; scanner.ts
143 > case TokenType.True: scanner.ts
144 > return 'true'; scanner.ts
145 > case TokenType.False: scanner.ts
146 > return 'false'; scanner.ts
147 > case TokenType.In: scanner.ts
148 > return 'in'; scanner.ts
149 > case TokenType.Not: scanner.ts
150 > return 'not'; scanner.ts
151 > case TokenType.And: scanner.ts
152 > return '&&'; scanner.ts
153 > case TokenType.Or: scanner.ts
154 > return '||'; scanner.ts
155 > case TokenType.Str: scanner.ts
156 > return token.lexeme; scanner.ts
157 > case TokenType.QuotedStr: scanner.ts
158 > return token.lexeme; scanner.ts
159 > case TokenType.Error: scanner.ts
160 > return token.lexeme; scanner.ts
161 > case TokenType.EOF: scanner.ts
162 > return 'EOF'; scanner.ts
163 > default: scanner.ts
164 > throw illegalState(`unhandled token type: ${JSON.stringify(token)}; have you forgotten to add a case?`); scanner.ts
165 > } scanner.ts
166 > }
167 >
168 > private static _regexFlags = new Set(['i', 'g', 's', 'm', 'y', 'u'].map(ch => ch.charCodeAt(0)));
169 >
170 > private static _keywords = new Map<string, KeywordTokenType>([
171 > ['not', TokenType.Not],
172 > ['in', TokenType.In],
173 > ['false', TokenType.False],
174 > ['true', TokenType.True],
175 > ]);
176 >
177 > private _input: string = '';
178 > private _start: number = 0;
179 > private _current: number = 0;
180 > private _tokens: Token[] = [];
181 > private _errors: LexingError[] = [];
182 >
183 > get errors(): Readonly<LexingError[]> {
184 return this._errors;
185 }
186 > scanner.ts
187 > reset(value: string) {
188 this._input = value;
189
195 return this;
196 }
197 > scanner.ts
198 > scan() {
199 while (!this._isAtEnd()) {
200
267 return Array.from(this._tokens);
268 }
269 > scanner.ts
270 > private _match(expected: number): boolean {
271 if (this._isAtEnd()) {
272 return false;
278 return true;
279 }
280 > scanner.ts
281 > private _advance(): number {
282 return this._input.charCodeAt(this._current++);
283 }
284 > scanner.ts
285 > private _peek(): number {
286 return this._isAtEnd() ? CharCode.Null : this._input.charCodeAt(this._current);
287 }
288 > scanner.ts
289 > private _addToken(type: TokenTypeWithoutLexeme) {
290 this._tokens.push({ type, offset: this._start });
291 }
292 > scanner.ts
293 > private _error(additional?: string) {
294 const offset = this._start;
295 const lexeme = this._input.substring(this._start, this._current);
298 this._tokens.push(errToken);
299 }
300 > scanner.ts
301 > // u - unicode, y - sticky // TODO@ulugbekna: we accept double quotes as part of the string rather than as a delimiter (to preserve old parser's behavior)
302 > private stringRe = /[a-zA-Z0-9_<>\-\./\\:\*\?\+\[\]\^,#@;"%\$\p{L}-]+/uy;
303 > private _string() {
304 this.stringRe.lastIndex = this._start;
305 const match = this.stringRe.exec(this._input);
315 }
316 }
317 > scanner.ts
318 > // captures the lexeme without the leading and trailing '
319 > private _quotedString() {
320 while (this._peek() !== CharCode.SingleQuote && !this._isAtEnd()) { // TODO@ulugbekna: add support for escaping ' ?
321 this._advance();
332 this._tokens.push({ type: TokenType.QuotedStr, lexeme: this._input.substring(this._start + 1, this._current - 1), offset: this._start + 1 });
333 }
334 > scanner.ts
335 > /*
336 > * Lexing a regex expression: /.../[igsmyu]*
337 > * Based on https://github.com/microsoft/TypeScript/blob/9247ef115e617805983740ba795d7a8164babf89/src/compiler/scanner.ts#L2129-L2181
338 > *
339 > * Note that we want slashes within a regex to be escaped, e.g., /file:\\/\\/\\// should match `file:///`
340 > */
341 > private _regex() {
342 let p = this._current;
343
378 this._tokens.push({ type: TokenType.RegexStr, lexeme, offset: this._start });
379 }
380 > scanner.ts
381 > private _isAtEnd() {
382 return this._current >= this._input.length;
383 }
384 > } scanner.ts
src/vs/base/common/jsonSchema.ts 194 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- jsonSchema.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > export type JSONSchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'null' | 'array' | 'object';
7 >
8 > export interface IJSONSchema {
9 > id?: string;
10 > $id?: string;
11 > $schema?: string;
12 > type?: JSONSchemaType | JSONSchemaType[];
13 > title?: string;
14 > default?: any;
15 > definitions?: IJSONSchemaMap;
16 > description?: string;
17 > properties?: IJSONSchemaMap;
18 > patternProperties?: IJSONSchemaMap;
19 > additionalProperties?: boolean | IJSONSchema;
20 > minProperties?: number;
21 > maxProperties?: number;
22 > dependencies?: IJSONSchemaMap | { [prop: string]: string[] };
23 > items?: IJSONSchema | IJSONSchema[];
24 > minItems?: number;
25 > maxItems?: number;
26 > uniqueItems?: boolean;
27 > additionalItems?: boolean | IJSONSchema;
28 > pattern?: string;
29 > minLength?: number;
30 > maxLength?: number;
31 > minimum?: number;
32 > maximum?: number;
33 > exclusiveMinimum?: boolean | number;
34 > exclusiveMaximum?: boolean | number;
35 > multipleOf?: number;
36 > required?: string[];
37 > $ref?: string;
38 > anyOf?: IJSONSchema[];
39 > allOf?: IJSONSchema[];
40 > oneOf?: IJSONSchema[];
41 > not?: IJSONSchema;
42 > enum?: any[];
43 > format?: string;
44 >
45 > // schema draft 06
46 > const?: any;
47 > contains?: IJSONSchema;
48 > propertyNames?: IJSONSchema;
49 > examples?: any[];
50 >
51 > // schema draft 07
52 > $comment?: string;
53 > if?: IJSONSchema;
54 > then?: IJSONSchema;
55 > else?: IJSONSchema;
56 >
57 > // schema 2019-09
58 > unevaluatedProperties?: boolean | IJSONSchema;
59 > unevaluatedItems?: boolean | IJSONSchema;
60 > minContains?: number;
61 > maxContains?: number;
62 > deprecated?: boolean;
63 > dependentRequired?: { [prop: string]: string[] };
64 > dependentSchemas?: IJSONSchemaMap;
65 > $defs?: { [name: string]: IJSONSchema };
66 > $anchor?: string;
67 > $recursiveRef?: string;
68 > $recursiveAnchor?: string;
69 > $vocabulary?: any;
70 >
71 > // schema 2020-12
72 > prefixItems?: IJSONSchema[];
73 > $dynamicRef?: string;
74 > $dynamicAnchor?: string;
75 >
76 > // VSCode extensions
77 >
78 > defaultSnippets?: IJSONSchemaSnippet[];
79 > errorMessage?: string;
80 > patternErrorMessage?: string;
81 > deprecationMessage?: string;
82 > markdownDeprecationMessage?: string;
83 > enumDescriptions?: string[];
84 > markdownEnumDescriptions?: string[];
85 > markdownDescription?: string;
86 > doNotSuggest?: boolean;
87 > suggestSortText?: string;
88 > allowComments?: boolean;
89 > allowTrailingCommas?: boolean;
90 > secret?: boolean;
91 > }
92 >
93 > export interface IJSONSchemaMap {
94 > [name: string]: IJSONSchema;
95 > }
96 >
97 > export interface IJSONSchemaSnippet {
98 > label?: string;
99 > description?: string;
100 > body?: any; // a object that will be JSON stringified
101 > bodyText?: string; // an already stringified JSON object that can contain new lines (\n) and tabs (\t)
102 > }
103 >
104 > /**
105 > * Converts a basic JSON schema to a TypeScript type.
106 > */
107 > export type TypeFromJsonSchema<T> =
108 > // enum
109 > T extends { enum: infer EnumValues }
110 > ? UnionOf<EnumValues>
111 >
112 > // Object with list of required properties.
113 > // Values are required or optional based on `required` list.
114 > : T extends { type: 'object'; properties: infer P; required: infer RequiredList }
115 > ? {
116 > [K in keyof P]: IsRequired<K, RequiredList> extends true ? TypeFromJsonSchema<P[K]> : TypeFromJsonSchema<P[K]> | undefined;
117 > } & AdditionalPropertiesType<T>
118 >
119 > // Object with no required properties.
120 > // All values are optional
121 > : T extends { type: 'object'; properties: infer P }
122 > ? { [K in keyof P]: TypeFromJsonSchema<P[K]> | undefined } & AdditionalPropertiesType<T>
123 >
124 > // Array
125 > : T extends { type: 'array'; items: infer Items }
126 > ? Items extends [...infer R]
127 > // If items is an array, we treat it like a tuple
128 > ? { [K in keyof R]: TypeFromJsonSchema<Items[K]> }
129 > : Array<TypeFromJsonSchema<Items>>
130 >
131 > // oneOf / anyof
132 > // These are handled the same way as they both represent a union type.
133 > // However at the validation level, they have different semantics.
134 > : T extends { oneOf: infer I }
135 > ? MapSchemaToType<I>
136 > : T extends { anyOf: infer I }
137 > ? MapSchemaToType<I>
138 >
139 > // Primitive types
140 > : T extends { type: infer Type }
141 > // Basic type
142 > ? Type extends 'string' | 'number' | 'integer' | 'boolean' | 'null'
143 > ? SchemaPrimitiveTypeNameToType<Type>
144 > // Union of primitive types
145 > : Type extends [...infer R]
146 > ? UnionOf<{ [K in keyof R]: SchemaPrimitiveTypeNameToType<R[K]> }>
147 > : never
148 >
149 > // Fallthrough
150 > : never;
151 >
152 > type SchemaPrimitiveTypeNameToType<T> =
153 > T extends 'string' ? string :
154 > T extends 'number' | 'integer' ? number :
155 > T extends 'boolean' ? boolean :
156 > T extends 'null' ? null :
157 > never;
158 >
159 > type UnionOf<T> =
160 > T extends [infer First, ...infer Rest]
161 > ? First | UnionOf<Rest>
162 > : never;
163 >
164 > type IsRequired<K, RequiredList> =
165 > RequiredList extends []
166 > ? false
167 >
168 > : RequiredList extends [K, ...infer _]
169 > ? true
170 >
171 > : RequiredList extends [infer _, ...infer R]
172 > ? IsRequired<K, R>
173 >
174 > : false;
175 >
176 > type AdditionalPropertiesType<Schema> =
177 > Schema extends { additionalProperties: infer AP }
178 > ? AP extends false ? {} : { [key: string]: TypeFromJsonSchema<Schema['additionalProperties']> }
179 > : {};
180 >
181 > type MapSchemaToType<T> = T extends [infer First, ...infer Rest]
182 > ? TypeFromJsonSchema<First> | MapSchemaToType<Rest>
183 > : never;
184 >
185 > interface Equals { schemas: IJSONSchema[]; id?: string }
186 >
187 > export function getCompressedContent(schema: IJSONSchema): string {
188 let hasDups = false;
189
258 return str;
259 }
261 > type IJSONSchemaRef = IJSONSchema | boolean;
262 >
263 function isObject(thing: unknown): thing is object {
264 return typeof thing === 'object' && thing !== null;
265 }
267 > /*
268 > * Traverse a JSON schema and visit each schema node
269 > */
270 function traverseNodes(root: IJSONSchema, visit: (schema: IJSONSchema) => boolean) {
271 if (!root || typeof root !== 'object') {
src/vs/base/common/ternarySearchTree.ts 193 covered LOC · 60 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- ternarySearchTree.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 { shuffle } from './arrays.js';
7 > import { assert } from './assert.js';
8 > import { CharCode } from './charCode.js';
9 > import { compare, compareIgnoreCase, compareSubstring, compareSubstringIgnoreCase } from './strings.js';
10 > import { URI } from './uri.js';
11 >
12 > export interface IKeyIterator<K> {
13 > reset(key: K): this;
14 > next(): this;
15 >
16 > hasNext(): boolean;
17 > cmp(a: string): number;
18 > value(): string;
19 > }
20 >
21 > export class StringIterator implements IKeyIterator<string> {
22
23 private _value: string = '';
24 private _pos: number = 0;
26 > reset(key: string): this {
27 this._value = key;
28 this._pos = 0;
29 return this;
30 }
32 > next(): this {
33 this._pos += 1;
34 return this;
35 }
37 > hasNext(): boolean {
38 return this._pos < this._value.length - 1;
39 }
41 > cmp(a: string): number {
42 const aCode = a.charCodeAt(0);
43 const thisCode = this._value.charCodeAt(this._pos);
44 return aCode - thisCode;
45 }
47 > value(): string {
48 return this._value[this._pos];
49 }
51 >
52 > export class ConfigKeysIterator implements IKeyIterator<string> {
53 >
54 > private _value!: string;
55 > private _from!: number;
56 > private _to!: number;
57 >
58 > constructor(
59 private readonly _caseSensitive: boolean = true
60 ) { }
62 > reset(key: string): this {
63 this._value = key;
64 this._from = 0;
66 return this.next();
67 }
69 > hasNext(): boolean {
70 return this._to < this._value.length;
71 }
73 > next(): this {
74 // this._data = key.split(/[\\/]/).filter(s => !!s);
75 this._from = this._to;
89 return this;
90 }
92 > cmp(a: string): number {
93 return this._caseSensitive
94 ? compareSubstring(a, this._value, 0, a.length, this._from, this._to)
95 : compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);
96 }
98 > value(): string {
99 return this._value.substring(this._from, this._to);
100 }
102 >
103 > export class PathIterator implements IKeyIterator<string> {
104 >
105 > private _value!: string;
106 > private _valueLen!: number;
107 > private _from!: number;
108 > private _to!: number;
109 >
110 > constructor(
111 private readonly _splitOnBackslash: boolean = true,
112 private readonly _caseSensitive: boolean = true
113 ) { }
115 > reset(key: string): this {
116 this._from = 0;
117 this._to = 0;
127 return this.next();
128 }
130 > hasNext(): boolean {
131 return this._to < this._valueLen;
132 }
134 > next(): this {
135 // this._data = key.split(/[\\/]/).filter(s => !!s);
136 this._from = this._to;
150 return this;
151 }
153 > cmp(a: string): number {
154 return this._caseSensitive
155 ? compareSubstring(a, this._value, 0, a.length, this._from, this._to)
156 : compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);
157 }
159 > value(): string {
160 return this._value.substring(this._from, this._to);
161 }
163 >
164 > const enum UriIteratorState {
165 > Scheme = 1, Authority = 2, Path = 3, Query = 4, Fragment = 5
166 > }
167 >
168 > export class UriIterator implements IKeyIterator<URI> {
169 >
170 > private _pathIterator!: PathIterator;
171 > private _value!: URI;
172 > private _states: UriIteratorState[] = [];
173 > private _stateIdx: number = 0;
174 >
175 > constructor(
176 private readonly _ignorePathCasing: (uri: URI) => boolean,
177 private readonly _ignoreQueryAndFragment: (uri: URI) => boolean) { }
179 > reset(key: URI): this {
180 this._value = key;
181 this._states = [];
204 return this;
205 }
207 > next(): this {
208 if (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext()) {
209 this._pathIterator.next();
213 return this;
214 }
216 > hasNext(): boolean {
217 return (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext())
218 || this._stateIdx < this._states.length - 1;
219 }
221 > cmp(a: string): number {
222 if (this._states[this._stateIdx] === UriIteratorState.Scheme) {
223 return compareIgnoreCase(a, this._value.scheme);
233 throw new Error();
234 }
236 > value(): string {
237 if (this._states[this._stateIdx] === UriIteratorState.Scheme) {
238 return this._value.scheme;
248 throw new Error();
249 }
251 >
252 > abstract class Undef {
253 >
254 > static readonly Val: unique symbol = Symbol('undefined_placeholder');
255 >
256 > static wrap<V>(value: V | undefined): V | typeof Undef.Val {
257 return value === undefined ? Undef.Val : value;
258 }
260 > static unwrap<V>(value: V | typeof Undef.Val): V | undefined {
261 return value === Undef.Val ? undefined : value;
262 }
264 >
265 class TernarySearchTreeNode<K, V> {
266 height: number = 1;
271 mid: TernarySearchTreeNode<K, V> | undefined = undefined;
272 right: TernarySearchTreeNode<K, V> | undefined = undefined;
274 > isEmpty(): boolean {
275 return !this.left && !this.mid && !this.right && this.value === undefined;
276 }
278 > rotateLeft() {
279 const tmp = this.right!;
280 this.right = tmp.left;
284 return tmp;
285 }
287 > rotateRight() {
288 const tmp = this.left!;
289 this.left = tmp.right;
293 return tmp;
294 }
296 > updateHeight() {
297 this.height = 1 + Math.max(this.heightLeft, this.heightRight);
298 }
300 > balanceFactor() {
301 return this.heightRight - this.heightLeft;
302 }
304 > get heightLeft() {
305 return this.left?.height ?? 0;
306 }
308 > get heightRight() {
309 return this.right?.height ?? 0;
310 }
312 >
313 > const enum Dir {
314 > Left = -1,
315 > Mid = 0,
316 > Right = 1
317 > }
318 >
319 > export class TernarySearchTree<K, V> {
320 >
321 > static forUris<E>(ignorePathCasing: (key: URI) => boolean = () => false, ignoreQueryAndFragment: (key: URI) => boolean = () => false): TernarySearchTree<URI, E> {
322 return new TernarySearchTree<URI, E>(new UriIterator(ignorePathCasing, ignoreQueryAndFragment));
323 }
325 > static forPaths<E>(ignorePathCasing = false): TernarySearchTree<string, E> {
326 return new TernarySearchTree<string, E>(new PathIterator(undefined, !ignorePathCasing));
327 }
329 > static forStrings<E>(): TernarySearchTree<string, E> {
330 return new TernarySearchTree<string, E>(new StringIterator());
331 }
333 > static forConfigKeys<E>(): TernarySearchTree<string, E> {
334 return new TernarySearchTree<string, E>(new ConfigKeysIterator());
335 }
337 > private _iter: IKeyIterator<K>;
338 > private _root: TernarySearchTreeNode<K, V> | undefined;
339 >
340 > constructor(segments: IKeyIterator<K>) {
341 this._iter = segments;
342 }
344 > clear(): void {
345 this._root = undefined;
346 }
348 > /**
349 > * Fill the tree with the same value of the given keys
350 > */
351 > fill(element: V, keys: readonly K[]): void;
352 > /**
353 > * Fill the tree with given [key,value]-tuples
354 > */
355 > fill(values: readonly [K, V][]): void;
356 > fill(values: readonly [K, V][] | V, keys?: readonly K[]): void {
357 if (keys) {
358 const arr = keys.slice(0);
369 }
370 }
372 > set(key: K, element: V): V | undefined {
373 const iter = this._iter.reset(key);
374 let node: TernarySearchTreeNode<K, V>;
476 return oldElement;
477 }
479 > get(key: K): V | undefined {
480 return Undef.unwrap(this._getNode(key)?.value);
481 }
483 > private _getNode(key: K) {
484 const iter = this._iter.reset(key);
485 let node = this._root;
502 return node;
503 }
505 > has(key: K): boolean {
506 const node = this._getNode(key);
507 return !(node?.value === undefined && node?.mid === undefined);
508 }
510 > delete(key: K): void {
511 return this._delete(key, false);
512 }
514 > deleteSuperstr(key: K): void {
515 return this._delete(key, true);
516 }
518 > private _delete(key: K, superStr: boolean): void {
519 const iter = this._iter.reset(key);
520 const stack: [Dir, TernarySearchTreeNode<K, V>][] = [];
620 this._root = this._balanceByStack(stack) ?? this._root;
621 }
623 > private _min(node: TernarySearchTreeNode<K, V>, stack: [Dir, TernarySearchTreeNode<K, V>][]): TernarySearchTreeNode<K, V> {
624 while (node.left) {
625 stack.push([Dir.Left, node]);
628 return node;
629 }
631 > private _balanceByStack(stack: [Dir, TernarySearchTreeNode<K, V>][]) {
632
633 for (let i = stack.length - 1; i >= 0; i--) {
679 return undefined;
680 }
682 > findSubstr(key: K): V | undefined {
683 const iter = this._iter.reset(key);
684 let node = this._root;
703 return node && Undef.unwrap(node.value) || candidate;
704 }
706 > findSuperstr(key: K): IterableIterator<[K, V]> | undefined {
707 return this._findSuperstrOrElement(key, false);
708 }
710 > private _findSuperstrOrElement(key: K, allowValue: true): IterableIterator<[K, V]> | V | undefined;
711 > private _findSuperstrOrElement(key: K, allowValue: false): IterableIterator<[K, V]> | undefined;
712 > private _findSuperstrOrElement(key: K, allowValue: boolean): IterableIterator<[K, V]> | V | undefined {
713 const iter = this._iter.reset(key);
714 let node = this._root;
740 return undefined;
741 }
743 > hasElementOrSubtree(key: K): boolean {
744 return this._findSuperstrOrElement(key, true) !== undefined;
745 }
747 > forEach(callback: (value: V, index: K) => unknown): void {
748 for (const [key, value] of this) {
749 callback(value, key);
750 }
751 }
753 > *[Symbol.iterator](): IterableIterator<[K, V]> {
754 yield* this._entries(this._root);
755 }
757 > private _entries(node: TernarySearchTreeNode<K, V> | undefined): IterableIterator<[K, V]> {
758 const result: [K, V][] = [];
759 this._dfsEntries(node, result);
760 return result[Symbol.iterator]();
761 }
763 > private _dfsEntries(node: TernarySearchTreeNode<K, V> | undefined, bucket: [K, V][]) {
764 // DFS
765 if (!node) {
779 }
780 }
782 > // for debug/testing
783 > _isBalanced(): boolean {
784 const nodeIsBalanced = (node: TernarySearchTreeNode<unknown, unknown> | undefined): boolean => {
785 if (!node) {
src/vs/base/common/platform.ts 189 covered LOC · 12 ranges

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- undoRedo.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IDisposable } from '../../../base/common/lifecycle.js';
7 > import { URI } from '../../../base/common/uri.js';
8 > import { createDecorator } from '../../instantiation/common/instantiation.js';
9 >
10 > export const IUndoRedoService = createDecorator<IUndoRedoService>('undoRedoService');
11 >
12 > export const enum UndoRedoElementType {
13 > Resource,
14 > Workspace
15 > }
16 >
17 > export interface IResourceUndoRedoElement {
18 > readonly type: UndoRedoElementType.Resource;
19 > /**
20 > * The resource impacted by this element.
21 > */
22 > readonly resource: URI;
23 > /**
24 > * A user presentable label. May be localized.
25 > */
26 > readonly label: string;
27 > /**
28 > * A code describing the operation. Will not be localized.
29 > */
30 > readonly code: string;
31 > /**
32 > * Show a message to the user confirming when trying to undo this element
33 > */
34 > readonly confirmBeforeUndo?: boolean;
35 > undo(): Promise<void> | void;
36 > redo(): Promise<void> | void;
37 > }
38 >
39 > export interface IWorkspaceUndoRedoElement {
40 > readonly type: UndoRedoElementType.Workspace;
41 > /**
42 > * The resources impacted by this element.
43 > */
44 > readonly resources: readonly URI[];
45 > /**
46 > * A user presentable label. May be localized.
47 > */
48 > readonly label: string;
49 > /**
50 > * A code describing the operation. Will not be localized.
51 > */
52 > readonly code: string;
53 > /**
54 > * Show a message to the user confirming when trying to undo this element
55 > */
56 > readonly confirmBeforeUndo?: boolean;
57 > undo(): Promise<void> | void;
58 > redo(): Promise<void> | void;
59 >
60 > /**
61 > * If implemented, indicates that this undo/redo element can be split into multiple per resource elements.
62 > */
63 > split?(): IResourceUndoRedoElement[];
64 >
65 > /**
66 > * If implemented, will be invoked before calling `undo()` or `redo()`.
67 > * This is a good place to prepare everything such that the calls to `undo()` or `redo()` are synchronous.
68 > * If a disposable is returned, it will be invoked to clean things up.
69 > */
70 > prepareUndoRedo?(): Promise<IDisposable> | IDisposable | void;
71 > }
72 >
73 > export type IUndoRedoElement = IResourceUndoRedoElement | IWorkspaceUndoRedoElement;
74 >
75 > export interface IPastFutureElements {
76 > past: IUndoRedoElement[];
77 > future: IUndoRedoElement[];
78 > }
79 >
80 > export interface UriComparisonKeyComputer {
81 > getComparisonKey(uri: URI): string;
82 > }
83 >
84 > export class ResourceEditStackSnapshot {
85 > constructor(
86 public readonly resource: URI,
87 public readonly elements: number[]
88 ) { }
89 > } undoRedo.ts
90 >
91 > export class UndoRedoGroup {
92 > private static _ID = 0;
93 >
94 > public readonly id: number;
95 > private order: number;
96 >
97 > constructor() {
98 > this.id = UndoRedoGroup._ID++;
99 > this.order = 1;
100 > }
101 >
102 > public nextOrder(): number {
103 if (this.id === 0) {
104 return 0;
106 return this.order++;
107 }
108 > undoRedo.ts
109 > public static None = new UndoRedoGroup();
110 > }
111 >
112 > export class UndoRedoSource {
113 > private static _ID = 0;
114 >
115 > public readonly id: number;
116 > private order: number;
117 >
118 > constructor() {
119 > this.id = UndoRedoSource._ID++;
120 > this.order = 1;
121 > }
122 >
123 > public nextOrder(): number {
124 if (this.id === 0) {
125 return 0;
127 return this.order++;
128 }
129 > undoRedo.ts
130 > public static None = new UndoRedoSource();
131 > }
132 >
133 > export interface IUndoRedoService {
134 > readonly _serviceBrand: undefined;
135 >
136 > /**
137 > * Register an URI -> string hasher.
138 > * This is useful for making multiple URIs share the same undo-redo stack.
139 > */
140 > registerUriComparisonKeyComputer(scheme: string, uriComparisonKeyComputer: UriComparisonKeyComputer): IDisposable;
141 >
142 > /**
143 > * Get the hash used internally for a certain URI.
144 > * This uses any registered `UriComparisonKeyComputer`.
145 > */
146 > getUriComparisonKey(resource: URI): string;
147 >
148 > /**
149 > * Add a new element to the `undo` stack.
150 > * This will destroy the `redo` stack.
151 > */
152 > pushElement(element: IUndoRedoElement, group?: UndoRedoGroup, source?: UndoRedoSource): void;
153 >
154 > /**
155 > * Get the last pushed element for a resource.
156 > * If the last pushed element has been undone, returns null.
157 > */
158 > getLastElement(resource: URI): IUndoRedoElement | null;
159 >
160 > /**
161 > * Get all the elements associated with a resource.
162 > * This includes the past and the future.
163 > */
164 > getElements(resource: URI): IPastFutureElements;
165 >
166 > /**
167 > * Validate or invalidate stack elements associated with a resource.
168 > */
169 > setElementsValidFlag(resource: URI, isValid: boolean, filter: (element: IUndoRedoElement) => boolean): void;
170 >
171 > /**
172 > * Remove elements that target `resource`.
173 > */
174 > removeElements(resource: URI): void;
175 >
176 > /**
177 > * Create a snapshot of the current elements on the undo-redo stack for a resource.
178 > */
179 > createSnapshot(resource: URI): ResourceEditStackSnapshot;
180 > /**
181 > * Attempt (as best as possible) to restore a certain snapshot previously created with `createSnapshot` for a resource.
182 > */
183 > restoreSnapshot(snapshot: ResourceEditStackSnapshot): void;
184 >
185 > canUndo(resource: URI | UndoRedoSource): boolean;
186 > undo(resource: URI | UndoRedoSource): Promise<void> | void;
187 >
188 > canRedo(resource: URI | UndoRedoSource): boolean;
189 > redo(resource: URI | UndoRedoSource): Promise<void> | void;
190 > }
src/vs/editor/common/languages/language.ts 168 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- language.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 { IDisposable } from '../../../base/common/lifecycle.js';
8 > import { URI } from '../../../base/common/uri.js';
9 > import { ILanguageIdCodec } from '../languages.js';
10 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
11 >
12 > export const ILanguageService = createDecorator<ILanguageService>('languageService');
13 >
14 > export interface ILanguageExtensionPoint {
15 > id: string;
16 > extensions?: string[];
17 > filenames?: string[];
18 > filenamePatterns?: string[];
19 > firstLine?: string;
20 > aliases?: string[];
21 > mimetypes?: string[];
22 > configuration?: URI;
23 > /**
24 > * @internal
25 > */
26 > icon?: ILanguageIcon;
27 > }
28 >
29 > export interface ILanguageSelection {
30 > readonly languageId: string;
31 > readonly onDidChange: Event<string>;
32 > }
33 >
34 > export interface ILanguageNameIdPair {
35 > readonly languageName: string;
36 > readonly languageId: string;
37 > }
38 >
39 > export interface ILanguageIcon {
40 > readonly light: URI;
41 > readonly dark: URI;
42 > }
43 >
44 > export interface ILanguageService {
45 > readonly _serviceBrand: undefined;
46 >
47 > /**
48 > * A codec which can encode and decode a string `languageId` as a number.
49 > */
50 > readonly languageIdCodec: ILanguageIdCodec;
51 >
52 > /**
53 > * An event emitted when basic language features are requested for the first time.
54 > * This event is emitted when embedded languages are encountered (e.g. JS code block inside Markdown)
55 > * or when a language is associated to a text model.
56 > *
57 > * **Note**: Basic language features refers to language configuration related features.
58 > * **Note**: This event is a superset of `onDidRequestRichLanguageFeatures`
59 > */
60 > readonly onDidRequestBasicLanguageFeatures: Event<string>;
61 >
62 > /**
63 > * An event emitted when rich language features are requested for the first time.
64 > * This event is emitted when a language is associated to a text model.
65 > *
66 > * **Note**: Rich language features refers to tokenizers, language features based on providers, etc.
67 > * **Note**: This event is a subset of `onDidRequestRichLanguageFeatures`
68 > */
69 > readonly onDidRequestRichLanguageFeatures: Event<string>;
70 >
71 > /**
72 > * An event emitted when languages have changed.
73 > */
74 > readonly onDidChange: Event<void>;
75 >
76 > /**
77 > * Register a language.
78 > */
79 > registerLanguage(def: ILanguageExtensionPoint): IDisposable;
80 >
81 > /**
82 > * Check if `languageId` is registered.
83 > */
84 > isRegisteredLanguageId(languageId: string): boolean;
85 >
86 > /**
87 > * Get a list of all registered languages.
88 > */
89 > getRegisteredLanguageIds(): string[];
90 >
91 > /**
92 > * Get a list of all registered languages with a name.
93 > * If a language is explicitly registered without a name, it will not be part of the result.
94 > * The result is sorted using by name case insensitive.
95 > */
96 > getSortedRegisteredLanguageNames(): ILanguageNameIdPair[];
97 >
98 > /**
99 > * Get the preferred language name for a language.
100 > */
101 > getLanguageName(languageId: string): string | null;
102 >
103 > /**
104 > * Get the mimetype for a language.
105 > */
106 > getMimeType(languageId: string): string | null;
107 >
108 > /**
109 > * Get the default icon for the language.
110 > */
111 > getIcon(languageId: string): ILanguageIcon | null;
112 >
113 > /**
114 > * Get all file extensions for a language.
115 > */
116 > getExtensions(languageId: string): ReadonlyArray<string>;
117 >
118 > /**
119 > * Get all file names for a language.
120 > */
121 > getFilenames(languageId: string): ReadonlyArray<string>;
122 >
123 > /**
124 > * Get all language configuration files for a language.
125 > */
126 > getConfigurationFiles(languageId: string): ReadonlyArray<URI>;
127 >
128 > /**
129 > * Look up a language by its name case insensitive.
130 > */
131 > getLanguageIdByLanguageName(languageName: string): string | null;
132 >
133 > /**
134 > * Look up a language by its mime type.
135 > */
136 > getLanguageIdByMimeType(mimeType: string | null | undefined): string | null;
137 >
138 > /**
139 > * Guess the language id for a resource.
140 > */
141 > guessLanguageIdByFilepathOrFirstLine(resource: URI, firstLine?: string): string | null;
142 >
143 > /**
144 > * Will fall back to 'plaintext' if `languageId` is unknown.
145 > */
146 > createById(languageId: string | null | undefined): ILanguageSelection;
147 >
148 > /**
149 > * Will fall back to 'plaintext' if `mimeType` is unknown.
150 > */
151 > createByMimeType(mimeType: string | null | undefined): ILanguageSelection;
152 >
153 > /**
154 > * Will fall back to 'plaintext' if the `languageId` cannot be determined.
155 > */
156 > createByFilepathOrFirstLine(resource: URI | null, firstLine?: string): ILanguageSelection;
157 >
158 > /**
159 > * Request basic language features for a language.
160 > */
161 > requestBasicLanguageFeatures(languageId: string): void;
162 >
163 > /**
164 > * Request rich language features for a language.
165 > */
166 > requestRichLanguageFeatures(languageId: string): void;
167 >
168 > }
src/vs/base/common/glob.ts 167 covered LOC · 24 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- glob.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 './arrays.js';
7 > import { isThenable } from './async.js';
8 > import { CharCode } from './charCode.js';
9 > import { isEqualOrParent } from './extpath.js';
10 > import { LRUCache } from './map.js';
11 > import { basename, extname, posix, sep } from './path.js';
12 > import { isLinux } from './platform.js';
13 > import { endsWithIgnoreCase, equalsIgnoreCase, escapeRegExpCharacters, ltrim } from './strings.js';
14 >
15 > export interface IRelativePattern {
16 >
17 > /**
18 > * A base file path to which this pattern will be matched against relatively.
19 > */
20 > readonly base: string;
21 >
22 > /**
23 > * A file glob pattern like `*.{ts,js}` that will be matched on file paths
24 > * relative to the base path.
25 > *
26 > * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`,
27 > * the file glob pattern will match on `index.js`.
28 > */
29 > readonly pattern: string;
30 > }
31 >
32 > export interface IExpression {
33 > [pattern: string]: boolean | SiblingClause;
34 > }
35 >
36 > export function getEmptyExpression(): IExpression {
37 return Object.create(null);
38 }
39 > glob.ts
40 > interface SiblingClause {
41 > when: string;
42 > }
43 >
44 > export const GLOBSTAR = '**';
45 > export const GLOB_SPLIT = '/';
46 >
47 > const PATH_REGEX = '[/\\\\]'; // any slash or backslash
48 > const NO_PATH_REGEX = '[^/\\\\]'; // any non-slash and non-backslash
49 > const ALL_FORWARD_SLASHES = /\//g;
50 >
51 function starsToRegExp(starCount: number, isLastPattern?: boolean): string {
52 switch (starCount) {
63 }
64 }
65 > glob.ts
66 > export function splitGlobAware(pattern: string, splitChar: string): string[] {
67 if (!pattern) {
68 return [];
109 return segments;
110 }
111 > glob.ts
112 function parseRegExp(pattern: string): string {
113 if (!pattern) {
256 return regEx;
257 }
258 > glob.ts
259 > // regexes to check for trivial glob patterns that just check for String#endsWith
260 > const T1 = /^\*\*\/\*\.[\w\.-]+$/; // **/*.something
261 > const T2 = /^\*\*\/([\w\.-]+)\/?$/; // **/something
262 > const T3 = /^{\*\*\/\*?[\w\.-]+\/?(,\*\*\/\*?[\w\.-]+\/?)*}$/; // {**/*.something,**/*.else} or {**/package.json,**/project.json}
263 > const T3_2 = /^{\*\*\/\*?[\w\.-]+(\/(\*\*)?)?(,\*\*\/\*?[\w\.-]+(\/(\*\*)?)?)*}$/; // Like T3, with optional trailing /**
264 > const T4 = /^\*\*((\/[\w\.-]+)+)\/?$/; // **/something/else
265 > const T5 = /^([\w\.-]+(\/[\w\.-]+)*)\/?$/; // something/else
266 >
267 > export type ParsedPattern = (path: string, basename?: string) => boolean;
268 >
269 > // The `ParsedExpression` returns a `Promise`
270 > // iff `hasSibling` returns a `Promise`.
271 > export type ParsedExpression = (path: string, basename?: string, hasSibling?: (name: string) => boolean | Promise<boolean>) => string | null | Promise<string | null> /* the matching pattern */;
272 >
273 > export interface IGlobOptions {
274 >
275 > /**
276 > * Simplify patterns for use as exclusion filters during
277 > * tree traversal to skip entire subtrees. Cannot be used
278 > * outside of a tree traversal.
279 > */
280 > trimForExclusions?: boolean;
281 >
282 > /**
283 > * Whether glob pattern matching should be case insensitive.
284 > */
285 > ignoreCase?: boolean;
286 > }
287 >
288 > interface IGlobOptionsInternal extends IGlobOptions {
289 > equals: (a: string, b: string) => boolean;
290 > endsWith: (str: string, candidate: string) => boolean;
291 > isEqualOrParent: (base: string, candidate: string) => boolean;
292 > }
293 >
294 > interface ParsedStringPattern {
295 > (path: string, basename?: string): string | null | Promise<string | null> /* the matching pattern */;
296 > basenames?: string[];
297 > patterns?: string[];
298 > allBasenames?: string[];
299 > allPaths?: string[];
300 > }
301 >
302 > interface ParsedExpressionPattern {
303 > (path: string, basename?: string, name?: string, hasSibling?: (name: string) => boolean | Promise<boolean>): string | null | Promise<string | null> /* the matching pattern */;
304 > requiresSiblings?: boolean;
305 > allBasenames?: string[];
306 > allPaths?: string[];
307 > }
308 >
309 > const CACHE = new LRUCache<string, ParsedStringPattern>(10000); // bounded to 10000 elements
310 >
311 > const FALSE = function () {
312 return false;
313 };
314 > glob.ts
315 > const NULL = function (): string | null {
316 return null;
317 };
318 > glob.ts
319 > /**
320 > * Check if a provided parsed pattern or expression
321 > * is empty - hence it won't ever match anything.
322 > *
323 > * See {@link FALSE} and {@link NULL}.
324 > */
325 > export function isEmptyPattern(pattern: ParsedPattern | ParsedExpression): pattern is (typeof FALSE | typeof NULL) {
326 if (pattern === FALSE) {
327 return true;
334 return false;
335 }
336 > glob.ts
337 function parsePattern(arg1: string | IRelativePattern, options: IGlobOptions): ParsedStringPattern {
338 if (!arg1) {
390 return wrapRelativePattern(parsedPattern, arg1, internalOptions);
391 }
392 > glob.ts
393 function wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | IRelativePattern, options: IGlobOptionsInternal): ParsedStringPattern {
394 if (typeof arg2 === 'string') {
421 return wrappedPattern;
422 }
423 > glob.ts
424 function trimForExclusions(pattern: string, options: IGlobOptions): string {
425 return options.trimForExclusions && pattern.endsWith('/**') ? pattern.substring(0, pattern.length - 2) : pattern; // dropping **, tailing / is dropped later
426 }
427 > glob.ts
428 > // common pattern: **/*.txt just need endsWith check
429 function trivia1(base: string, pattern: string, options: IGlobOptionsInternal): ParsedStringPattern {
430 return function (path: string, basename?: string) {
432 };
433 }
434 > glob.ts
435 > // common pattern: **/some.txt just need basename check
436 function trivia2(base: string, pattern: string, options: IGlobOptionsInternal): ParsedStringPattern {
437 const slashBase = `/${base}`;
457 return parsedPattern;
458 }
459 > glob.ts
460 > // repetition of common patterns (see above) {**/*.txt,**/*.png}
461 function trivia3(pattern: string, options: IGlobOptionsInternal): ParsedStringPattern {
462 const parsedPatterns = aggregateBasenameMatches(pattern.slice(1, -1)
496 return parsedPattern;
497 }
498 > glob.ts
499 > // common patterns: **/something/else just need endsWith check, something/else just needs and equals check
500 function trivia4and5(targetPath: string, pattern: string, matchPathEnds: boolean, options: IGlobOptionsInternal): ParsedStringPattern {
501 const usingPosixSep = sep === posix.sep;
522 return parsedPattern;
523 }
524 > glob.ts
525 function toRegExp(pattern: string, options: IGlobOptions): ParsedStringPattern {
526 try {
535 }
536 }
537 > glob.ts
538 > /**
539 > * Simplified glob matching. Supports a subset of glob patterns:
540 > * * `*` to match zero or more characters in a path segment
541 > * * `?` to match on one character in a path segment
542 > * * `**` to match any number of path segments, including none
543 > * * `{}` to group conditions (e.g. *.{ts,js} matches all TypeScript and JavaScript files)
544 > * * `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
545 > * * `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)
546 > */
547 > export function match(pattern: string | IRelativePattern, path: string, options?: IGlobOptions): boolean;
548 > export function match(expression: IExpression, path: string, options?: IGlobOptions): boolean;
549 > export function match(arg1: string | IExpression | IRelativePattern, path: string, options?: IGlobOptions): boolean {
550 if (!arg1 || typeof path !== 'string') {
551 return false;
554 return parse(arg1, options)(path) as boolean;
555 }
556 > glob.ts
557 > /**
558 > * Simplified glob matching. Supports a subset of glob patterns:
559 > * * `*` to match zero or more characters in a path segment
560 > * * `?` to match on one character in a path segment
561 > * * `**` to match any number of path segments, including none
562 > * * `{}` to group conditions (e.g. *.{ts,js} matches all TypeScript and JavaScript files)
563 > * * `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
564 > * * `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)
565 > */
566 > export function parse(pattern: string | IRelativePattern, options?: IGlobOptions): ParsedPattern;
567 > export function parse(expression: IExpression, options?: IGlobOptions): ParsedExpression;
568 > export function parse(arg1: string | IExpression | IRelativePattern, options?: IGlobOptions): ParsedPattern | ParsedExpression;
569 > export function parse(arg1: string | IExpression | IRelativePattern, options: IGlobOptions = {}): ParsedPattern | ParsedExpression {
570 if (!arg1) {
571 return FALSE;
597 return parsedExpression(arg1, options);
598 }
599 > glob.ts
600 > export function isRelativePattern(obj: unknown): obj is IRelativePattern {
601 const rp = obj as IRelativePattern | undefined | null;
602 if (!rp) {
606 return typeof rp.base === 'string' && typeof rp.pattern === 'string';
607 }
608 > glob.ts
609 > export function getBasenameTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] {
610 return (<ParsedStringPattern>patternOrExpression).allBasenames || [];
611 }
612 > glob.ts
613 > export function getPathTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] {
614 return (<ParsedStringPattern>patternOrExpression).allPaths || [];
615 }
616 > glob.ts
617 function parsedExpression(expression: IExpression, options: IGlobOptions): ParsedExpression {
618 const parsedPatterns = aggregateBasenameMatches(Object.getOwnPropertyNames(expression)
745 return resultExpression;
746 }
747 > glob.ts
748 function parseExpressionPattern(pattern: string, value: boolean | SiblingClause, options: IGlobOptions): (ParsedStringPattern | ParsedExpressionPattern) {
749 if (value === false) {
786 return parsedPattern;
787 }
788 > glob.ts
789 function aggregateBasenameMatches(parsedPatterns: Array<ParsedStringPattern | ParsedExpressionPattern>, result?: string): Array<ParsedStringPattern | ParsedExpressionPattern> {
790 const basenamePatterns = parsedPatterns.filter(parsedPattern => !!(<ParsedStringPattern>parsedPattern).basenames);
844 return aggregatedPatterns;
845 }
846 > glob.ts
847 > // NOTE: This is not used for actual matching, only for resetting watcher when patterns change.
848 > // That is why it's ok to avoid case-insensitive comparison here.
849 > export function patternsEquals(patternsA: Array<string | IRelativePattern> | undefined, patternsB: Array<string | IRelativePattern> | undefined): boolean {
850 return equals(patternsA, patternsB, (a, b) => {
851 if (typeof a === 'string' && typeof b === 'string') {
src/vs/platform/environment/common/environment.ts 165 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- environment.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 '../../../base/common/uri.js';
7 > import { NativeParsedArgs } from './argv.js';
8 > import { createDecorator, refineServiceDecorator } from '../../instantiation/common/instantiation.js';
9 >
10 > export const IEnvironmentService = createDecorator<IEnvironmentService>('environmentService');
11 > export const INativeEnvironmentService = refineServiceDecorator<IEnvironmentService, INativeEnvironmentService>(IEnvironmentService);
12 >
13 > export interface IDebugParams {
14 > port: number | null;
15 > break: boolean;
16 > }
17 >
18 > export interface IExtensionHostDebugParams extends IDebugParams {
19 > debugId?: string;
20 > env?: Record<string, string>;
21 > }
22 >
23 > /**
24 > * Type of extension.
25 > *
26 > * **NOTE**: This is defined in `platform/environment` because it can appear as a CLI argument.
27 > */
28 > export type ExtensionKind = 'ui' | 'workspace' | 'web';
29 >
30 > /**
31 > * A basic environment service that can be used in various processes,
32 > * such as main, renderer and shared process. Use subclasses of this
33 > * service for specific environment.
34 > */
35 > export interface IEnvironmentService {
36 >
37 > readonly _serviceBrand: undefined;
38 >
39 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
40 > //
41 > // NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE.
42 > //
43 > // AS SUCH:
44 > // - PUT NON-WEB PROPERTIES INTO NATIVE ENVIRONMENT SERVICE
45 > // - PUT WORKBENCH ONLY PROPERTIES INTO WORKBENCH ENVIRONMENT SERVICE
46 > // - PUT ELECTRON-MAIN ONLY PROPERTIES INTO MAIN ENVIRONMENT SERVICE
47 > //
48 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
49 >
50 > // --- user roaming data
51 > stateResource: URI;
52 > userRoamingDataHome: URI;
53 > keyboardLayoutResource: URI;
54 > argvResource: URI;
55 >
56 > // --- data paths
57 > untitledWorkspacesHome: URI;
58 > workspaceStorageHome: URI;
59 > localHistoryHome: URI;
60 > cacheHome: URI;
61 > appSharedDataHome: URI;
62 >
63 > // --- settings sync
64 > userDataSyncHome: URI;
65 > sync: 'on' | 'off' | undefined;
66 >
67 > // --- continue edit session
68 > continueOn?: string;
69 > editSessionId?: string;
70 >
71 > // --- extension development
72 > debugExtensionHost: IExtensionHostDebugParams;
73 > isExtensionDevelopment: boolean;
74 > disableExtensions: boolean | string[];
75 > skipBuiltinExtensions?: readonly string[];
76 > enableExtensions?: readonly string[];
77 > extensionDevelopmentLocationURI?: URI[];
78 > extensionDevelopmentKind?: ExtensionKind[];
79 > extensionTestsLocationURI?: URI;
80 >
81 > // --- logging
82 > logsHome: URI;
83 > logLevel?: string;
84 > extensionLogLevel?: [string, string][];
85 > verbose: boolean;
86 > isBuilt: boolean;
87 >
88 > // --- telemetry/exp
89 > disableTelemetry: boolean;
90 > disableExperiments: boolean;
91 > serviceMachineIdResource: URI;
92 >
93 > // --- agent sessions workspace
94 > agentSessionsWorkspace: URI;
95 > // --- Policy
96 > policyFile?: URI;
97 >
98 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
99 > //
100 > // NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE.
101 > //
102 > // AS SUCH:
103 > // - PUT NON-WEB PROPERTIES INTO NATIVE ENVIRONMENT SERVICE
104 > // - PUT WORKBENCH ONLY PROPERTIES INTO WORKBENCH ENVIRONMENT SERVICE
105 > // - PUT ELECTRON-MAIN ONLY PROPERTIES INTO MAIN ENVIRONMENT SERVICE
106 > //
107 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
108 > }
109 >
110 > /**
111 > * A subclass of the `IEnvironmentService` to be used only in native
112 > * environments (Windows, Linux, macOS) but not e.g. web.
113 > */
114 > export interface INativeEnvironmentService extends IEnvironmentService {
115 >
116 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
117 > //
118 > // NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE.
119 > //
120 > // AS SUCH:
121 > // - PUT WORKBENCH ONLY PROPERTIES INTO WORKBENCH ENVIRONMENT SERVICE
122 > // - PUT ELECTRON-MAIN ONLY PROPERTIES INTO MAIN ENVIRONMENT SERVICE
123 > //
124 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
125 >
126 > // --- CLI Arguments
127 > args: NativeParsedArgs;
128 >
129 > // --- data paths
130 > /**
131 > * Root path of the JavaScript sources.
132 > *
133 > * Note: This is NOT the installation root
134 > * directory itself but contained in it at
135 > * a level that is platform dependent.
136 > */
137 > appRoot: string;
138 > userHome: URI;
139 > appSettingsHome: URI;
140 > tmpDir: URI;
141 > userDataPath: string;
142 >
143 > // --- extensions
144 > extensionsPath: string;
145 > extensionsDownloadLocation: URI;
146 > builtinExtensionsPath: string;
147 >
148 > // --- use in-memory Secret Storage
149 > useInMemorySecretStorage?: boolean;
150 >
151 > crossOriginIsolated?: boolean;
152 > exportPolicyData?: string;
153 > exportDefaultKeybindings?: string;
154 >
155 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
156 > //
157 > // NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE.
158 > //
159 > // AS SUCH:
160 > // - PUT NON-WEB PROPERTIES INTO NATIVE ENVIRONMENT SERVICE
161 > // - PUT WORKBENCH ONLY PROPERTIES INTO WORKBENCH ENVIRONMENT SERVICE
162 > // - PUT ELECTRON-MAIN ONLY PROPERTIES INTO MAIN ENVIRONMENT SERVICE
163 > //
164 > // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
165 > }
src/vs/platform/theme/common/colors/listColors.ts 165 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- listColors.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 > // Import the effects we need
9 > import { Color } from '../../../../base/common/color.js';
10 > import { registerColor, darken, lighten, transparent, ifDefinedThenElse } from '../colorUtils.js';
11 >
12 > // Import the colors we need
13 > import { foreground, contrastBorder, activeContrastBorder, focusBorder, iconForeground } from './baseColors.js';
14 > import { editorWidgetBackground, editorFindMatchHighlightBorder, editorFindMatchHighlight, widgetShadow, editorWidgetForeground } from './editorColors.js';
15 >
16 >
17 > export const listFocusBackground = registerColor('list.focusBackground',
18 > null,
19 > nls.localize('listFocusBackground', "List/Tree background color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not."));
20 >
21 > export const listFocusForeground = registerColor('list.focusForeground',
22 > null,
23 > nls.localize('listFocusForeground', "List/Tree foreground color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not."));
24 >
25 > export const listFocusOutline = registerColor('list.focusOutline',
26 > { dark: focusBorder, light: focusBorder, hcDark: activeContrastBorder, hcLight: activeContrastBorder },
27 > nls.localize('listFocusOutline', "List/Tree outline color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not."));
28 >
29 > export const listFocusAndSelectionOutline = registerColor('list.focusAndSelectionOutline',
30 > null,
31 > nls.localize('listFocusAndSelectionOutline', "List/Tree outline color for the focused item when the list/tree is active and selected. An active list/tree has keyboard focus, an inactive does not."));
32 >
33 > export const listActiveSelectionBackground = registerColor('list.activeSelectionBackground',
34 > { dark: '#04395E', light: '#0060C0', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) },
35 > nls.localize('listActiveSelectionBackground', "List/Tree background color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not."));
36 >
37 > export const listActiveSelectionForeground = registerColor('list.activeSelectionForeground',
38 > { dark: Color.white, light: Color.white, hcDark: null, hcLight: null },
39 > nls.localize('listActiveSelectionForeground', "List/Tree foreground color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not."));
40 >
41 > export const listActiveSelectionIconForeground = registerColor('list.activeSelectionIconForeground',
42 > null,
43 > nls.localize('listActiveSelectionIconForeground', "List/Tree icon foreground color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not."));
44 >
45 > export const listInactiveSelectionBackground = registerColor('list.inactiveSelectionBackground',
46 > { dark: '#37373D', light: '#E4E6F1', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) },
47 > nls.localize('listInactiveSelectionBackground', "List/Tree background color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not."));
48 >
49 > export const listInactiveSelectionForeground = registerColor('list.inactiveSelectionForeground',
50 > null,
51 > nls.localize('listInactiveSelectionForeground', "List/Tree foreground color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not."));
52 >
53 > export const listInactiveSelectionIconForeground = registerColor('list.inactiveSelectionIconForeground',
54 > null,
55 > nls.localize('listInactiveSelectionIconForeground', "List/Tree icon foreground color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not."));
56 >
57 > export const listInactiveFocusBackground = registerColor('list.inactiveFocusBackground',
58 > null,
59 > nls.localize('listInactiveFocusBackground', "List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not."));
60 >
61 > export const listInactiveFocusOutline = registerColor('list.inactiveFocusOutline',
62 > null,
63 > nls.localize('listInactiveFocusOutline', "List/Tree outline color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not."));
64 >
65 > export const listHoverBackground = registerColor('list.hoverBackground',
66 > { dark: '#2A2D2E', light: '#F0F0F0', hcDark: Color.white.transparent(0.1), hcLight: Color.fromHex('#0F4A85').transparent(0.1) },
67 > nls.localize('listHoverBackground', "List/Tree background when hovering over items using the mouse."));
68 >
69 > export const listHoverForeground = registerColor('list.hoverForeground',
70 > null,
71 > nls.localize('listHoverForeground', "List/Tree foreground when hovering over items using the mouse."));
72 >
73 > export const listDropOverBackground = registerColor('list.dropBackground',
74 > { dark: '#062F4A', light: '#D6EBFF', hcDark: null, hcLight: null },
75 > nls.localize('listDropBackground', "List/Tree drag and drop background when moving items over other items when using the mouse."));
76 >
77 > export const listDropBetweenBackground = registerColor('list.dropBetweenBackground',
78 > { dark: iconForeground, light: iconForeground, hcDark: null, hcLight: null },
79 > nls.localize('listDropBetweenBackground', "List/Tree drag and drop border color when moving items between items when using the mouse."));
80 >
81 > export const listHighlightForeground = registerColor('list.highlightForeground',
82 > { dark: '#2AAAFF', light: '#0066BF', hcDark: focusBorder, hcLight: focusBorder },
83 > nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.'));
84 >
85 > export const listFocusHighlightForeground = registerColor('list.focusHighlightForeground',
86 > { dark: listHighlightForeground, light: ifDefinedThenElse(listActiveSelectionBackground, listHighlightForeground, '#BBE7FF'), hcDark: listHighlightForeground, hcLight: listHighlightForeground },
87 > nls.localize('listFocusHighlightForeground', 'List/Tree foreground color of the match highlights on actively focused items when searching inside the list/tree.'));
88 >
89 > export const listInvalidItemForeground = registerColor('list.invalidItemForeground',
90 > { dark: '#B89500', light: '#B89500', hcDark: '#B89500', hcLight: '#B5200D' },
91 > nls.localize('invalidItemForeground', 'List/Tree foreground color for invalid items, for example an unresolved root in explorer.'));
92 >
93 > export const listErrorForeground = registerColor('list.errorForeground',
94 > { dark: '#F88070', light: '#B01011', hcDark: null, hcLight: null }, nls.localize('listErrorForeground', 'Foreground color of list items containing errors.'));
95 >
96 > export const listWarningForeground = registerColor('list.warningForeground',
97 > { dark: '#CCA700', light: '#855F00', hcDark: null, hcLight: null }, nls.localize('listWarningForeground', 'Foreground color of list items containing warnings.'));
98 >
99 > export const listFilterWidgetBackground = registerColor('listFilterWidget.background',
100 > { light: darken(editorWidgetBackground, 0), dark: lighten(editorWidgetBackground, 0), hcDark: editorWidgetBackground, hcLight: editorWidgetBackground },
101 > nls.localize('listFilterWidgetBackground', 'Background color of the type filter widget in lists and trees.'));
102 >
103 > export const listFilterWidgetOutline = registerColor('listFilterWidget.outline',
104 > { dark: Color.transparent, light: Color.transparent, hcDark: '#f38518', hcLight: '#007ACC' },
105 > nls.localize('listFilterWidgetOutline', 'Outline color of the type filter widget in lists and trees.'));
106 >
107 > export const listFilterWidgetNoMatchesOutline = registerColor('listFilterWidget.noMatchesOutline',
108 > { dark: '#BE1100', light: '#BE1100', hcDark: contrastBorder, hcLight: contrastBorder },
109 > nls.localize('listFilterWidgetNoMatchesOutline', 'Outline color of the type filter widget in lists and trees, when there are no matches.'));
110 >
111 > export const listFilterWidgetShadow = registerColor('listFilterWidget.shadow',
112 > widgetShadow,
113 > nls.localize('listFilterWidgetShadow', 'Shadow color of the type filter widget in lists and trees.'));
114 >
115 > export const listFilterMatchHighlight = registerColor('list.filterMatchBackground',
116 > { dark: editorFindMatchHighlight, light: editorFindMatchHighlight, hcDark: null, hcLight: null },
117 > nls.localize('listFilterMatchHighlight', 'Background color of the filtered match.'));
118 >
119 > export const listFilterMatchHighlightBorder = registerColor('list.filterMatchBorder',
120 > { dark: editorFindMatchHighlightBorder, light: editorFindMatchHighlightBorder, hcDark: contrastBorder, hcLight: activeContrastBorder },
121 > nls.localize('listFilterMatchHighlightBorder', 'Border color of the filtered match.'));
122 >
123 > export const listDeemphasizedForeground = registerColor('list.deemphasizedForeground',
124 > { dark: '#8C8C8C', light: '#8E8E90', hcDark: '#A7A8A9', hcLight: '#666666' },
125 > nls.localize('listDeemphasizedForeground', "List/Tree foreground color for items that are deemphasized."));
126 >
127 >
128 > // ------ tree
129 >
130 > export const treeIndentGuidesStroke = registerColor('tree.indentGuidesStroke',
131 > { dark: '#585858', light: '#a9a9a9', hcDark: '#a9a9a9', hcLight: '#a5a5a5' },
132 > nls.localize('treeIndentGuidesStroke', "Tree stroke color for the indentation guides."));
133 >
134 > export const treeInactiveIndentGuidesStroke = registerColor('tree.inactiveIndentGuidesStroke',
135 > transparent(treeIndentGuidesStroke, 0.4),
136 > nls.localize('treeInactiveIndentGuidesStroke', "Tree stroke color for the indentation guides that are not active."));
137 >
138 >
139 > // ------ table
140 >
141 > export const tableColumnsBorder = registerColor('tree.tableColumnsBorder',
142 > { dark: '#CCCCCC20', light: '#61616120', hcDark: null, hcLight: null },
143 > nls.localize('tableColumnsBorder', "Table border color between columns."));
144 >
145 > export const tableOddRowsBackgroundColor = registerColor('tree.tableOddRowsBackground',
146 > { dark: transparent(foreground, 0.04), light: transparent(foreground, 0.04), hcDark: null, hcLight: null },
147 > nls.localize('tableOddRowsBackgroundColor', "Background color for odd table rows."));
148 >
149 > // ------ action list
150 >
151 > export const editorActionListBackground = registerColor('editorActionList.background',
152 > editorWidgetBackground,
153 > nls.localize('editorActionListBackground', "Action List background color."));
154 >
155 > export const editorActionListForeground = registerColor('editorActionList.foreground',
156 > editorWidgetForeground,
157 > nls.localize('editorActionListForeground', "Action List foreground color."));
158 >
159 > export const editorActionListFocusForeground = registerColor('editorActionList.focusForeground',
160 > listActiveSelectionForeground,
161 > nls.localize('editorActionListFocusForeground', "Action List foreground color for the focused item."));
162 >
163 > export const editorActionListFocusBackground = registerColor('editorActionList.focusBackground',
164 > listActiveSelectionBackground,
165 > nls.localize('editorActionListFocusBackground', "Action List background color for the focused item."));
src/vs/editor/common/model/textModelTokens.ts 161 covered LOC · 44 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelTokens.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 { IdleDeadline, runWhenGlobalIdle } from '../../../base/common/async.js';
7 > import { BugIndicatingError, onUnexpectedError } from '../../../base/common/errors.js';
8 > import { setTimeout0 } from '../../../base/common/platform.js';
9 > import { StopWatch } from '../../../base/common/stopwatch.js';
10 > import { countEOL } from '../core/misc/eolCounter.js';
11 > import { LineRange } from '../core/ranges/lineRange.js';
12 > import { OffsetRange } from '../core/ranges/offsetRange.js';
13 > import { Position } from '../core/position.js';
14 > import { StandardTokenType } from '../encodedTokenAttributes.js';
15 > import { EncodedTokenizationResult, IBackgroundTokenizationStore, IBackgroundTokenizer, ILanguageIdCodec, IState, ITokenizationSupport } from '../languages.js';
16 > import { nullTokenizeEncoded } from '../languages/nullTokenize.js';
17 > import { ITextModel } from '../model.js';
18 > import { FixedArray } from './fixedArray.js';
19 > import { IModelContentChange } from './mirrorTextModel.js';
20 > import { ContiguousMultilineTokensBuilder } from '../tokens/contiguousMultilineTokensBuilder.js';
21 > import { LineTokens } from '../tokens/lineTokens.js';
22 >
23 > const enum Constants {
24 > CHEAP_TOKENIZATION_LENGTH_LIMIT = 2048
25 > }
26 >
27 > export class TokenizerWithStateStore<TState extends IState = IState> {
28 > private readonly initialState;
29 >
30 > public readonly store: TrackingTokenizationStateStore<TState>;
31 >
32 > constructor(
33 lineCount: number,
34 public readonly tokenizationSupport: ITokenizationSupport
37 this.store = new TrackingTokenizationStateStore<TState>(lineCount);
38 }
40 > public getStartState(lineNumber: number): TState | null {
41 return this.store.getStartState(lineNumber, this.initialState);
42 }
44 > public getFirstInvalidLine(): { lineNumber: number; startState: TState } | null {
45 return this.store.getFirstInvalidLine(this.initialState);
46 }
48 >
49 > export class TokenizerWithStateStoreAndTextModel<TState extends IState = IState> extends TokenizerWithStateStore<TState> {
50 > constructor(
51 lineCount: number,
52 tokenizationSupport: ITokenizationSupport,
56 super(lineCount, tokenizationSupport);
57 }
59 > public updateTokensUntilLine(builder: ContiguousMultilineTokensBuilder, lineNumber: number): void {
60 const languageId = this._textModel.getLanguageId();
61
73 }
74 }
76 > /** assumes state is up to date */
77 > public getTokenTypeIfInsertingCharacter(position: Position, character: string): StandardTokenType {
78 // TODO@hediet: use tokenizeLineWithEdit
79 const lineStartState = this.getStartState(position.lineNumber);
101 return lineTokens.getStandardTokenType(tokenIndex);
102 }
104 > /** assumes state is up to date */
105 > public tokenizeLinesAt(lineNumber: number, lines: string[]): LineTokens[] | null {
106 const lineStartState: IState | null = this.getStartState(lineNumber);
107 if (!lineStartState) {
121 return result;
122 }
124 > public hasAccurateTokensForLine(lineNumber: number): boolean {
125 const firstInvalidLineNumber = this.store.getFirstInvalidEndStateLineNumberOrMax();
126 return (lineNumber < firstInvalidLineNumber);
127 }
129 > public isCheapToTokenize(lineNumber: number): boolean {
130 const firstInvalidLineNumber = this.store.getFirstInvalidEndStateLineNumberOrMax();
131 if (lineNumber < firstInvalidLineNumber) {
139 return false;
140 }
142 > /**
143 > * The result is not cached.
144 > */
145 > public tokenizeHeuristically(builder: ContiguousMultilineTokensBuilder, startLineNumber: number, endLineNumber: number): { heuristicTokens: boolean } {
146 if (endLineNumber <= this.store.getFirstInvalidEndStateLineNumberOrMax()) {
147 // nothing to do
167 return { heuristicTokens: true };
168 }
170 > private guessStartState(lineNumber: number): IState {
171 let { likelyRelevantLines, initialState } = findLikelyRelevantLines(this._textModel, lineNumber, this);
172
183 return state;
184 }
186 >
187 > export function findLikelyRelevantLines(model: ITextModel, lineNumber: number, store?: TokenizerWithStateStore): { likelyRelevantLines: string[]; initialState?: IState } {
188 let nonWhitespaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber);
189 const likelyRelevantLines: string[] = [];
208 return { likelyRelevantLines, initialState: initialState ?? undefined };
209 }
211 > /**
212 > * **Invariant:**
213 > * If the text model is retokenized from line 1 to {@link getFirstInvalidEndStateLineNumber}() - 1,
214 > * then the recomputed end state for line l will be equal to {@link getEndState}(l).
215 > */
216 > export class TrackingTokenizationStateStore<TState extends IState> {
217 > private readonly _tokenizationStateStore = new TokenizationStateStore<TState>();
218 > private readonly _invalidEndStatesLineNumbers = new RangePriorityQueueImpl();
219 >
220 > constructor(private lineCount: number) {
221 this._invalidEndStatesLineNumbers.addRange(new OffsetRange(1, lineCount + 1));
222 }
224 > public getEndState(lineNumber: number): TState | null {
225 return this._tokenizationStateStore.getEndState(lineNumber);
226 }
228 > /**
229 > * @returns if the end state has changed.
230 > */
231 > public setEndState(lineNumber: number, state: TState): boolean {
232 if (!state) {
233 throw new BugIndicatingError('Cannot set null/undefined state');
243 return r;
244 }
246 > public acceptChange(range: LineRange, newLineCount: number): void {
247 this.lineCount += newLineCount - range.length;
248 this._tokenizationStateStore.acceptChange(range, newLineCount);
249 this._invalidEndStatesLineNumbers.addRangeAndResize(new OffsetRange(range.startLineNumber, range.endLineNumberExclusive), newLineCount);
250 }
252 > public acceptChanges(changes: IModelContentChange[]) {
253 for (const c of changes) {
254 const [eolCount] = countEOL(c.text);
256 }
257 }
259 > public invalidateEndStateRange(range: LineRange): void {
260 this._invalidEndStatesLineNumbers.addRange(new OffsetRange(range.startLineNumber, range.endLineNumberExclusive));
261 }
263 > public getFirstInvalidEndStateLineNumber(): number | null { return this._invalidEndStatesLineNumbers.min; }
264 >
265 > public getFirstInvalidEndStateLineNumberOrMax(): number {
266 return this.getFirstInvalidEndStateLineNumber() || Number.MAX_SAFE_INTEGER;
267 }
269 > public allStatesValid(): boolean { return this._invalidEndStatesLineNumbers.min === null; }
270 >
271 > public getStartState(lineNumber: number, initialState: TState): TState | null {
272 if (lineNumber === 1) { return initialState; }
273 return this.getEndState(lineNumber - 1);
274 }
276 > public getFirstInvalidLine(initialState: TState): { lineNumber: number; startState: TState } | null {
277 const lineNumber = this.getFirstInvalidEndStateLineNumber();
278 if (lineNumber === null) {
286 return { lineNumber, startState };
287 }
289 >
290 > export class TokenizationStateStore<TState extends IState> {
291 private readonly _lineEndStates = new FixedArray<TState | null>(null);
293 > public getEndState(lineNumber: number): TState | null {
294 return this._lineEndStates.get(lineNumber);
295 }
297 > public setEndState(lineNumber: number, state: TState): boolean {
298 const oldState = this._lineEndStates.get(lineNumber);
299 if (oldState && oldState.equals(state)) {
304 return true;
305 }
307 > public acceptChange(range: LineRange, newLineCount: number): void {
308 let length = range.length;
309 if (newLineCount > 0 && length > 0) {
316 this._lineEndStates.replace(range.startLineNumber, length, newLineCount);
317 }
319 > public acceptChanges(changes: IModelContentChange[]) {
320 for (const c of changes) {
321 const [eolCount] = countEOL(c.text);
323 }
324 }
326 >
327 > interface RangePriorityQueue {
328 > get min(): number | null;
329 > removeMin(): number | null;
330 >
331 > addRange(range: OffsetRange): void;
332 >
333 > addRangeAndResize(range: OffsetRange, newLength: number): void;
334 > }
335 >
336 > export class RangePriorityQueueImpl implements RangePriorityQueue {
337 private readonly _ranges: OffsetRange[] = [];
339 > public getRanges(): OffsetRange[] {
340 return this._ranges;
341 }
343 > public get min(): number | null {
344 if (this._ranges.length === 0) {
345 return null;
347 return this._ranges[0].start;
348 }
350 > public removeMin(): number | null {
351 if (this._ranges.length === 0) {
352 return null;
360 return range.start;
361 }
363 > public delete(value: number): void {
364 const idx = this._ranges.findIndex(r => r.contains(value));
365 if (idx !== -1) {
380 }
381 }
383 > public addRange(range: OffsetRange): void {
384 OffsetRange.addRange(range, this._ranges);
385 }
387 > public addRangeAndResize(range: OffsetRange, newLength: number): void {
388 let idxFirstMightBeIntersecting = 0;
389 while (!(idxFirstMightBeIntersecting >= this._ranges.length || range.start <= this._ranges[idxFirstMightBeIntersecting].endExclusive)) {
417 }
418 }
420 > toString() {
421 return this._ranges.map(r => r.toString()).join(' + ');
422 }
424 >
425 >
426 function safeTokenize(languageIdCodec: ILanguageIdCodec, languageId: string, tokenizationSupport: ITokenizationSupport | null, text: string, hasEOL: boolean, state: IState): EncodedTokenizationResult {
427 let r: EncodedTokenizationResult | null = null;
442 return r;
443 }
445 > export class DefaultBackgroundTokenizer implements IBackgroundTokenizer {
446 > private _isDisposed = false;
447 >
448 > constructor(
449 private readonly _tokenizerWithStateStore: TokenizerWithStateStoreAndTextModel,
450 private readonly _backgroundTokenStore: IBackgroundTokenizationStore,
461
462 private _isScheduled = false;
463 > private _beginBackgroundTokenization(): void { textModelTokens.ts
464 if (this._isScheduled || !this._tokenizerWithStateStore._textModel.isAttachedToEditor() || !this._hasLinesToTokenize()) {
465 return;
473 });
474 }
476 > /**
477 > * Tokenize until the deadline occurs, but try to yield every 1-2ms.
478 > */
479 > private _backgroundTokenizeWithDeadline(deadline: IdleDeadline): void {
480 // Read the time remaining from the `deadline` immediately because it is unclear
481 // if the `deadline` object will be valid after execution leaves this function.
501 execute();
502 }
504 > /**
505 > * Tokenize for at least 1ms.
506 > */
507 > private _backgroundTokenizeForAtLeast1ms(): void {
508 const lineCount = this._tokenizerWithStateStore._textModel.getLineCount();
509 const builder = new ContiguousMultilineTokensBuilder();
528 this.checkFinished();
529 }
531 > private _hasLinesToTokenize(): boolean {
532 if (!this._tokenizerWithStateStore) {
533 return false;
535 return !this._tokenizerWithStateStore.store.allStatesValid();
536 }
538 > private _tokenizeOneInvalidLine(builder: ContiguousMultilineTokensBuilder): number {
539 const firstInvalidLine = this._tokenizerWithStateStore?.getFirstInvalidLine();
540 if (!firstInvalidLine) {
544 return firstInvalidLine.lineNumber;
545 }
547 > public checkFinished(): void {
548 if (this._isDisposed) {
549 return;
553 }
554 }
556 > public requestTokens(startLineNumber: number, endLineNumberExclusive: number): void {
557 this._tokenizerWithStateStore.store.invalidateEndStateRange(new LineRange(startLineNumber, endLineNumberExclusive));
558 }
src/vs/editor/common/languages/languageConfigurationRegistry.ts 160 covered LOC · 28 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageConfigurationRegistry.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 '../../../base/common/event.js';
7 > import { Disposable, IDisposable, markAsSingleton, toDisposable } from '../../../base/common/lifecycle.js';
8 > import * as strings from '../../../base/common/strings.js';
9 > import { ITextModel } from '../model.js';
10 > import { DEFAULT_WORD_REGEXP, ensureValidWordDefinition } from '../core/wordHelper.js';
11 > import { EnterAction, FoldingRules, IAutoClosingPair, IndentationRule, LanguageConfiguration, AutoClosingPairs, CharacterPair, ExplicitLanguageConfiguration } from './languageConfiguration.js';
12 > import { CharacterPairSupport } from './supports/characterPair.js';
13 > import { BracketElectricCharacterSupport } from './supports/electricCharacter.js';
14 > import { IndentRulesSupport } from './supports/indentRules.js';
15 > import { OnEnterSupport } from './supports/onEnter.js';
16 > import { RichEditBrackets } from './supports/richEditBrackets.js';
17 > import { EditorAutoIndentStrategy } from '../config/editorOptions.js';
18 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
19 > import { IConfigurationService } from '../../../platform/configuration/common/configuration.js';
20 > import { ILanguageService } from './language.js';
21 > import { InstantiationType, registerSingleton } from '../../../platform/instantiation/common/extensions.js';
22 > import { PLAINTEXT_LANGUAGE_ID } from './modesRegistry.js';
23 > import { LanguageBracketsConfiguration } from './supports/languageBracketsConfiguration.js';
24 >
25 > /**
26 > * Interface used to support insertion of mode specific comments.
27 > */
28 > export interface ICommentsConfiguration {
29 > lineCommentToken?: string;
30 > lineCommentNoIndent?: boolean;
31 > blockCommentStartToken?: string;
32 > blockCommentEndToken?: string;
33 > }
34 >
35 > export interface ILanguageConfigurationService {
36 > readonly _serviceBrand: undefined;
37 >
38 > readonly onDidChange: Event<LanguageConfigurationServiceChangeEvent>;
39 >
40 > /**
41 > * @param priority Use a higher number for higher priority
42 > */
43 > register(languageId: string, configuration: LanguageConfiguration, priority?: number): IDisposable;
44 >
45 > getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration;
46 >
47 > }
48 >
49 > export class LanguageConfigurationServiceChangeEvent {
50 > constructor(public readonly languageId: string | undefined) { }
51 >
52 > public affects(languageId: string): boolean {
53 return !this.languageId ? true : this.languageId === languageId;
54 }
56 >
57 > export const ILanguageConfigurationService = createDecorator<ILanguageConfigurationService>('languageConfigurationService');
58 >
59 > export class LanguageConfigurationService extends Disposable implements ILanguageConfigurationService {
60 > _serviceBrand: undefined;
61 >
62 > private readonly _registry = this._register(new LanguageConfigurationRegistry());
63 >
64 > private readonly onDidChangeEmitter = this._register(new Emitter<LanguageConfigurationServiceChangeEvent>());
65 > public readonly onDidChange = this.onDidChangeEmitter.event;
66 >
67 > private readonly configurations = new Map<string, ResolvedLanguageConfiguration>();
68 >
69 > constructor(
70 @IConfigurationService private readonly configurationService: IConfigurationService,
71 @ILanguageService private readonly languageService: ILanguageService
103 }));
104 }
106 > public register(languageId: string, configuration: LanguageConfiguration, priority?: number): IDisposable {
107 return this._registry.register(languageId, configuration, priority);
108 }
110 > public getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration {
111 let result = this.configurations.get(languageId);
112 if (!result) {
140 return config;
141 }
143 > const customizedLanguageConfigKeys = {
144 > brackets: 'editor.language.brackets',
145 > colorizedBracketPairs: 'editor.language.colorizedBracketPairs'
146 > };
147 >
148 function getCustomizedLanguageConfig(languageId: string, configurationService: IConfigurationService): LanguageConfiguration {
149 const brackets = configurationService.getValue(customizedLanguageConfigKeys.brackets, {
160 };
161 }
163 function validateBracketPairs(data: unknown): CharacterPair[] | undefined {
164 if (!Array.isArray(data)) {
172 }).filter((p): p is CharacterPair => !!p);
173 }
175 > export function getIndentationAtPosition(model: ITextModel, lineNumber: number, column: number): string {
176 const lineText = model.getLineContent(lineNumber);
177 let indentation = strings.getLeadingWhitespace(lineText);
181 return indentation;
182 }
184 > class ComposedLanguageConfiguration {
185 > private readonly _entries: LanguageConfigurationContribution[];
186 > private _order: number;
187 > private _resolved: ResolvedLanguageConfiguration | null = null;
188 >
189 > constructor(public readonly languageId: string) {
190 this._entries = [];
191 this._order = 0;
192 this._resolved = null;
193 }
195 > public register(
196 configuration: LanguageConfiguration,
197 priority: number
214 }));
215 }
217 > public getResolvedConfiguration(): ResolvedLanguageConfiguration | null {
218 if (!this._resolved) {
219 const config = this._resolve();
227 return this._resolved;
228 }
230 > private _resolve(): LanguageConfiguration | null {
231 if (this._entries.length === 0) {
232 return null;
235 return combineLanguageConfigurations(this._entries.map(e => e.configuration));
236 }
238 >
239 function combineLanguageConfigurations(configs: LanguageConfiguration[]): LanguageConfiguration {
240 let result: ExplicitLanguageConfiguration = {
269 return result;
270 }
272 > class LanguageConfigurationContribution {
273 > constructor(
274 public readonly configuration: LanguageConfiguration,
275 public readonly priority: number,
276 public readonly order: number
277 ) { }
279 > public static cmp(a: LanguageConfigurationContribution, b: LanguageConfigurationContribution) {
280 if (a.priority === b.priority) {
281 // higher order last
285 return a.priority - b.priority;
286 }
288 >
289 > export class LanguageConfigurationChangeEvent {
290 > constructor(public readonly languageId: string) { }
291 > }
292 >
293 > export class LanguageConfigurationRegistry extends Disposable {
294 > private readonly _entries = new Map<string, ComposedLanguageConfiguration>();
295 >
296 > private readonly _onDidChange = this._register(new Emitter<LanguageConfigurationChangeEvent>());
297 > public readonly onDidChange: Event<LanguageConfigurationChangeEvent> = this._onDidChange.event;
298 >
299 > constructor() {
300 super();
301 this._register(this.register(PLAINTEXT_LANGUAGE_ID, {
320 }, 0));
321 }
323 > /**
324 > * @param priority Use a higher number for higher priority
325 > */
326 > public register(languageId: string, configuration: LanguageConfiguration, priority: number = 0): IDisposable {
327 let entries = this._entries.get(languageId);
328 if (!entries) {
339 }));
340 }
342 > public getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration | null {
343 const entries = this._entries.get(languageId);
344 return entries?.getResolvedConfiguration() || null;
345 }
347 >
348 > /**
349 > * Immutable.
350 > */
351 > export class ResolvedLanguageConfiguration {
352 > private _brackets: RichEditBrackets | null;
353 > private _electricCharacter: BracketElectricCharacterSupport | null;
354 > private readonly _onEnterSupport: OnEnterSupport | null;
355 >
356 > public readonly comments: ICommentsConfiguration | null;
357 > public readonly characterPair: CharacterPairSupport;
358 > public readonly wordDefinition: RegExp;
359 > public readonly indentRulesSupport: IndentRulesSupport | null;
360 > public readonly indentationRules: IndentationRule | undefined;
361 > public readonly foldingRules: FoldingRules;
362 > public readonly bracketsNew: LanguageBracketsConfiguration;
363 >
364 > constructor(
365 public readonly languageId: string,
366 public readonly underlyingConfig: LanguageConfiguration
393 );
394 }
396 > public getWordDefinition(): RegExp {
397 return ensureValidWordDefinition(this.wordDefinition);
398 }
400 > public get brackets(): RichEditBrackets | null {
401 if (!this._brackets && this.underlyingConfig.brackets) {
402 this._brackets = new RichEditBrackets(
407 return this._brackets;
408 }
410 > public get electricCharacter(): BracketElectricCharacterSupport | null {
411 if (!this._electricCharacter) {
412 this._electricCharacter = new BracketElectricCharacterSupport(
416 return this._electricCharacter;
417 }
419 > public onEnter(
420 autoIndent: EditorAutoIndentStrategy,
421 previousLineText: string,
433 );
434 }
436 > public getAutoClosingPairs(): AutoClosingPairs {
437 return new AutoClosingPairs(this.characterPair.getAutoClosingPairs());
438 }
440 > public getAutoCloseBeforeSet(forQuotes: boolean): string {
441 return this.characterPair.getAutoCloseBeforeSet(forQuotes);
442 }
444 > public getSurroundingPairs(): IAutoClosingPair[] {
445 return this.characterPair.getSurroundingPairs();
446 }
448 > private static _handleComments(
449 conf: LanguageConfiguration
450 ): ICommentsConfiguration | null {
473 return comments;
474 }
476 >
477 > registerSingleton(ILanguageConfigurationService, LanguageConfigurationService, InstantiationType.Delayed);
src/vs/editor/common/model/editStack.ts 160 covered LOC · 46 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editStack.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 > import { onUnexpectedError } from '../../../base/common/errors.js';
8 > import { Selection } from '../core/selection.js';
9 > import { EndOfLineSequence, ICursorStateComputer, IValidEditOperation, ITextModel } from '../model.js';
10 > import { TextModel } from './textModel.js';
11 > import { IUndoRedoService, IResourceUndoRedoElement, UndoRedoElementType, IWorkspaceUndoRedoElement, UndoRedoGroup } from '../../../platform/undoRedo/common/undoRedo.js';
12 > import { URI } from '../../../base/common/uri.js';
13 > import { TextChange, compressConsecutiveTextChanges } from '../core/textChange.js';
14 > import * as buffer from '../../../base/common/buffer.js';
15 > import { IDisposable } from '../../../base/common/lifecycle.js';
16 > import { basename } from '../../../base/common/resources.js';
17 > import { ISingleEditOperation } from '../core/editOperation.js';
18 > import { EditSources, TextModelEditSource } from '../textModelEditSource.js';
19 >
20 function uriGetComparisonKey(resource: URI): string {
21 return resource.toString();
22 }
24 > export class SingleModelEditStackData {
25 >
26 > public static create(model: ITextModel, beforeCursorState: Selection[] | null): SingleModelEditStackData {
27 > const alternativeVersionId = model.getAlternativeVersionId();
28 > const eol = getModelEOL(model);
29 > return new SingleModelEditStackData(
30 > alternativeVersionId,
31 > alternativeVersionId,
32 > eol,
33 > eol,
34 > beforeCursorState,
35 > beforeCursorState,
36 > []
37 > );
38 > }
39 >
40 > constructor(
41 public readonly beforeVersionId: number,
42 public afterVersionId: number,
47 public changes: TextChange[]
48 ) { }
50 > public append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {
51 if (textChanges.length > 0) {
52 this.changes = compressConsecutiveTextChanges(this.changes, textChanges);
56 this.afterCursorState = afterCursorState;
57 }
59 > private static _writeSelectionsSize(selections: Selection[] | null): number {
60 return 4 + 4 * 4 * (selections ? selections.length : 0);
61 }
63 > private static _writeSelections(b: Uint8Array, selections: Selection[] | null, offset: number): number {
64 buffer.writeUInt32BE(b, (selections ? selections.length : 0), offset); offset += 4;
65 if (selections) {
73 return offset;
74 }
76 > private static _readSelections(b: Uint8Array, offset: number, dest: Selection[]): number {
77 const count = buffer.readUInt32BE(b, offset); offset += 4;
78 for (let i = 0; i < count; i++) {
85 return offset;
86 }
88 > public serialize(): ArrayBuffer {
89 let necessarySize = (
90 + 4 // beforeVersionId
114 return b.buffer;
115 }
116 > editStack.ts
117 > public static deserialize(source: ArrayBuffer): SingleModelEditStackData {
118 const b = new Uint8Array(source);
119 let offset = 0;
141 );
142 }
143 > } editStack.ts
144 >
145 > export interface IUndoRedoDelegate {
146 > prepareUndoRedo(element: MultiModelEditStackElement): Promise<IDisposable> | IDisposable | void;
147 > }
148 >
149 > export class SingleModelEditStackElement implements IResourceUndoRedoElement {
150 >
151 > public model: ITextModel | URI;
152 > private _data: SingleModelEditStackData | ArrayBuffer;
153 >
154 > public get type(): UndoRedoElementType.Resource {
155 > return UndoRedoElementType.Resource;
156 > }
157 >
158 > public get resource(): URI {
159 if (URI.isUri(this.model)) {
160 return this.model;
162 return this.model.uri;
163 }
164 > editStack.ts
165 > constructor(
166 public readonly label: string,
167 public readonly code: string,
172 this._data = SingleModelEditStackData.create(model, beforeCursorState);
173 }
174 > editStack.ts
175 > public toString(): string {
176 const data = (this._data instanceof SingleModelEditStackData ? this._data : SingleModelEditStackData.deserialize(this._data));
177 return data.changes.map(change => change.toString()).join(', ');
178 }
179 > editStack.ts
180 > public matchesResource(resource: URI): boolean {
181 const uri = (URI.isUri(this.model) ? this.model : this.model.uri);
182 return (uri.toString() === resource.toString());
183 }
184 > editStack.ts
185 > public setModel(model: ITextModel | URI): void {
186 this.model = model;
187 }
188 > editStack.ts
189 > public canAppend(model: ITextModel): boolean {
190 return (this.model === model && this._data instanceof SingleModelEditStackData);
191 }
192 > editStack.ts
193 > public append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {
194 if (this._data instanceof SingleModelEditStackData) {
195 this._data.append(model, textChanges, afterEOL, afterVersionId, afterCursorState);
196 }
197 }
198 > editStack.ts
199 > public close(): void {
200 if (this._data instanceof SingleModelEditStackData) {
201 this._data = this._data.serialize();
202 }
203 }
204 > editStack.ts
205 > public open(): void {
206 if (!(this._data instanceof SingleModelEditStackData)) {
207 this._data = SingleModelEditStackData.deserialize(this._data);
208 }
209 }
210 > editStack.ts
211 > public undo(): void {
212 if (URI.isUri(this.model)) {
213 // don't have a model
220 this.model._applyUndo(data.changes, data.beforeEOL, data.beforeVersionId, data.beforeCursorState);
221 }
222 > editStack.ts
223 > public redo(): void {
224 if (URI.isUri(this.model)) {
225 // don't have a model
232 this.model._applyRedo(data.changes, data.afterEOL, data.afterVersionId, data.afterCursorState);
233 }
234 > editStack.ts
235 > public heapSize(): number {
236 if (this._data instanceof SingleModelEditStackData) {
237 this._data = this._data.serialize();
239 return this._data.byteLength + 168/*heap overhead*/;
240 }
241 > } editStack.ts
242 >
243 > export class MultiModelEditStackElement implements IWorkspaceUndoRedoElement {
244 >
245 > public readonly type = UndoRedoElementType.Workspace;
246 > private _isOpen: boolean;
247 >
248 > private readonly _editStackElementsArr: SingleModelEditStackElement[];
249 > private readonly _editStackElementsMap: Map<string, SingleModelEditStackElement>;
250 >
251 > private _delegate: IUndoRedoDelegate | null;
252 >
253 > public get resources(): readonly URI[] {
254 > return this._editStackElementsArr.map(editStackElement => editStackElement.resource);
255 > }
256 >
257 > constructor(
258 public readonly label: string,
259 public readonly code: string,
269 this._delegate = null;
270 }
271 > editStack.ts
272 > public setDelegate(delegate: IUndoRedoDelegate): void {
273 this._delegate = delegate;
274 }
275 > editStack.ts
276 > public prepareUndoRedo(): Promise<IDisposable> | IDisposable | void {
277 if (this._delegate) {
278 return this._delegate.prepareUndoRedo(this);
279 }
280 }
281 > editStack.ts
282 > public getMissingModels(): URI[] {
283 const result: URI[] = [];
284 for (const editStackElement of this._editStackElementsArr) {
289 return result;
290 }
291 > editStack.ts
292 > public matchesResource(resource: URI): boolean {
293 const key = uriGetComparisonKey(resource);
294 return (this._editStackElementsMap.has(key));
295 }
296 > editStack.ts
297 > public setModel(model: ITextModel | URI): void {
298 const key = uriGetComparisonKey(URI.isUri(model) ? model : model.uri);
299 if (this._editStackElementsMap.has(key)) {
301 }
302 }
303 > editStack.ts
304 > public canAppend(model: ITextModel): boolean {
305 if (!this._isOpen) {
306 return false;
313 return false;
314 }
315 > editStack.ts
316 > public append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {
317 const key = uriGetComparisonKey(model.uri);
318 const editStackElement = this._editStackElementsMap.get(key)!;
319 editStackElement.append(model, textChanges, afterEOL, afterVersionId, afterCursorState);
320 }
321 > editStack.ts
322 > public close(): void {
323 this._isOpen = false;
324 }
325 > editStack.ts
326 > public open(): void {
327 // cannot reopen
328 }
329 > editStack.ts
330 > public undo(): void {
331 this._isOpen = false;
332
335 }
336 }
337 > editStack.ts
338 > public redo(): void {
339 for (const editStackElement of this._editStackElementsArr) {
340 editStackElement.redo();
341 }
342 }
343 > editStack.ts
344 > public heapSize(resource: URI): number {
345 const key = uriGetComparisonKey(resource);
346 if (this._editStackElementsMap.has(key)) {
350 return 0;
351 }
352 > editStack.ts
353 > public split(): IResourceUndoRedoElement[] {
354 return this._editStackElementsArr;
355 }
356 > editStack.ts
357 > public toString(): string {
358 const result: string[] = [];
359 for (const editStackElement of this._editStackElementsArr) {
362 return `{${result.join(', ')}}`;
363 }
364 > } editStack.ts
365 >
366 > export type EditStackElement = SingleModelEditStackElement | MultiModelEditStackElement;
367 >
368 function getModelEOL(model: ITextModel): EndOfLineSequence {
369 const eol = model.getEOL();
374 }
375 }
376 > editStack.ts
377 > export function isEditStackElement(element: IResourceUndoRedoElement | IWorkspaceUndoRedoElement | null): element is EditStackElement {
378 if (!element) {
379 return false;
381 return ((element instanceof SingleModelEditStackElement) || (element instanceof MultiModelEditStackElement));
382 }
383 > editStack.ts
384 > export class EditStack {
385 >
386 > private readonly _model: TextModel;
387 > private readonly _undoRedoService: IUndoRedoService;
388 >
389 > constructor(model: TextModel, undoRedoService: IUndoRedoService) {
390 this._model = model;
391 this._undoRedoService = undoRedoService;
392 }
393 > editStack.ts
394 > public pushStackElement(): void {
395 const lastElement = this._undoRedoService.getLastElement(this._model.uri);
396 if (isEditStackElement(lastElement)) {
398 }
399 }
400 > editStack.ts
401 > public popStackElement(): void {
402 const lastElement = this._undoRedoService.getLastElement(this._model.uri);
403 if (isEditStackElement(lastElement)) {
405 }
406 }
407 > editStack.ts
408 > public clear(): void {
409 this._undoRedoService.removeElements(this._model.uri);
410 }
411 > editStack.ts
412 > private _getOrCreateEditStackElement(beforeCursorState: Selection[] | null, group: UndoRedoGroup | undefined): EditStackElement {
413 const lastElement = this._undoRedoService.getLastElement(this._model.uri);
414 if (isEditStackElement(lastElement) && lastElement.canAppend(this._model)) {
419 return newElement;
420 }
421 > editStack.ts
422 > public pushEOL(eol: EndOfLineSequence): void {
423 const editStackElement = this._getOrCreateEditStackElement(null, undefined);
424 this._model.setEOL(eol);
425 editStackElement.append(this._model, [], getModelEOL(this._model), this._model.getAlternativeVersionId(), null);
426 }
427 > editStack.ts
428 > public pushEditOperation(beforeCursorState: Selection[] | null, editOperations: ISingleEditOperation[], cursorStateComputer: ICursorStateComputer | null, group?: UndoRedoGroup, reason: TextModelEditSource = EditSources.unknown({ name: 'pushEditOperation' })): Selection[] | null {
429 const editStackElement = this._getOrCreateEditStackElement(beforeCursorState, group);
430 const inverseEditOperations = this._model.applyEdits(editOperations, true, reason);
440 return afterCursorState;
441 }
442 > editStack.ts
443 > private static _computeCursorState(cursorStateComputer: ICursorStateComputer | null, inverseEditOperations: IValidEditOperation[]): Selection[] | null {
444 try {
445 return cursorStateComputer ? cursorStateComputer(inverseEditOperations) : null;
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/model/tokens/treeSitter/treeSitterTokenizationImpl.ts 158 covered LOC · 39 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- treeSitterTokenizationImpl.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 '../../../../../base/common/event.js';
7 > import { Disposable } from '../../../../../base/common/lifecycle.js';
8 > import { setTimeout0 } from '../../../../../base/common/platform.js';
9 > import { StopWatch } from '../../../../../base/common/stopwatch.js';
10 > import { LanguageId } from '../../../encodedTokenAttributes.js';
11 > import { ILanguageIdCodec, QueryCapture } from '../../../languages.js';
12 > import { IModelContentChangedEvent, IModelTokensChangedEvent } from '../../../textModelEvents.js';
13 > import { findLikelyRelevantLines } from '../../textModelTokens.js';
14 > import { TokenStore, TokenUpdate, TokenQuality } from './tokenStore.js';
15 > import { TreeSitterTree, RangeChange, RangeWithOffsets } from './treeSitterTree.js';
16 > import type * as TreeSitter from '@vscode/tree-sitter-wasm';
17 > import { autorun, autorunHandleChanges, IObservable, recordChanges, runOnChange } from '../../../../../base/common/observable.js';
18 > import { LineRange } from '../../../core/ranges/lineRange.js';
19 > import { LineTokens } from '../../../tokens/lineTokens.js';
20 > import { Position } from '../../../core/position.js';
21 > import { Range } from '../../../core/range.js';
22 > import { isDefined } from '../../../../../base/common/types.js';
23 > import { ITreeSitterThemeService } from '../../../services/treeSitter/treeSitterThemeService.js';
24 > import { BugIndicatingError } from '../../../../../base/common/errors.js';
25 >
26 > export class TreeSitterTokenizationImpl extends Disposable {
27 > private readonly _tokenStore: TokenStore;
28 > private _accurateVersion: number;
29 > private _guessVersion: number;
30 >
31 > private readonly _onDidChangeTokens: Emitter<{ changes: IModelTokensChangedEvent }> = this._register(new Emitter());
32 > public readonly onDidChangeTokens: Event<{ changes: IModelTokensChangedEvent }> = this._onDidChangeTokens.event;
33 > private readonly _onDidCompleteBackgroundTokenization: Emitter<void> = this._register(new Emitter());
34 > public readonly onDidChangeBackgroundTokenization: Event<void> = this._onDidCompleteBackgroundTokenization.event;
35 >
36 > private _encodedLanguageId: LanguageId;
37 >
38 > private get _textModel() {
39 > return this._tree.textModel;
40 > }
41 >
42 > constructor(
43 private readonly _tree: TreeSitterTree,
44 private readonly _highlightingQueries: TreeSitter.Query,
97 }));
98 }
100 > public handleContentChanged(e: IModelContentChangedEvent): void {
101 this._guessVersion = e.versionId;
102 for (const change of e.changes) {
124 }
125 }
127 > public getLineTokens(lineNumber: number) {
128 const content = this._textModel.getLineContent(lineNumber);
129 const rawTokens = this.getTokens(lineNumber);
130 return new LineTokens(rawTokens, content, this._languageIdCodec);
131 }
133 > private _createEmptyTokens() {
134 const emptyToken = this._emptyToken();
135 const modelEndOffset = this._textModel.getValueLength();
138 return emptyTokens;
139 }
141 > private _emptyToken() {
142 return this._treeSitterThemeService.findMetadata([], this._encodedLanguageId, false, undefined);
143 }
145 > private _emptyTokensForOffsetAndLength(offset: number, length: number, emptyToken: number): TokenUpdate {
146 return { token: emptyToken, length: offset + length, startOffsetInclusive: 0 };
147 }
149 > public hasAccurateTokensForLine(lineNumber: number): boolean {
150 return this.hasTokens(new Range(lineNumber, 1, lineNumber, this._textModel.getLineMaxColumn(lineNumber)));
151 }
153 > public tokenizeLinesAt(lineNumber: number, lines: string[]): LineTokens[] | null {
154 const rawLineTokens = this._guessTokensForLinesContent(lineNumber, lines);
155 const lineTokens: LineTokens[] = [];
162 return lineTokens;
163 }
165 > private _rangeHasTokens(range: Range, minimumTokenQuality: TokenQuality): boolean {
166 return this._tokenStore.rangeHasTokens(this._textModel.getOffsetAt(range.getStartPosition()), this._textModel.getOffsetAt(range.getEndPosition()), minimumTokenQuality);
167 }
169 > public hasTokens(accurateForRange?: Range): boolean {
170 if (!accurateForRange || (this._guessVersion === this._accurateVersion)) {
171 return true;
174 return !this._tokenStore.rangeNeedsRefresh(this._textModel.getOffsetAt(accurateForRange.getStartPosition()), this._textModel.getOffsetAt(accurateForRange.getEndPosition()));
175 }
177 > public getTokens(line: number): Uint32Array {
178 const lineStartOffset = this._textModel.getOffsetAt({ lineNumber: line, column: 1 });
179 const lineEndOffset = this._textModel.getOffsetAt({ lineNumber: line, column: this._textModel.getLineLength(line) + 1 });
186 return result;
187 }
189 > getTokensInRange(range: Range, rangeStartOffset: number, rangeEndOffset: number, captures?: QueryCapture[]): TokenUpdate[] | undefined {
190 const tokens = captures ? this._tokenizeCapturesWithMetadata(captures, rangeStartOffset, rangeEndOffset) : this._tokenize(range, rangeStartOffset, rangeEndOffset);
191 if (tokens?.endOffsetsAndMetadata) {
194 return undefined;
195 }
197 > private _updateTokensInStore(version: number, updates: { oldRangeLength?: number; newTokens: TokenUpdate[] }[], tokenQuality: TokenQuality): void {
198 this._accurateVersion = version;
199 for (const update of updates) {
210 }
211 }
213 > private _markForRefresh(range: Range): void {
214 this._tokenStore.markForRefresh(this._textModel.getOffsetAt(range.getStartPosition()), this._textModel.getOffsetAt(range.getEndPosition()));
215 }
217 > private _getNeedsRefresh(): { range: Range; startOffset: number; endOffset: number }[] {
218 const needsRefreshOffsetRanges = this._tokenStore.getNeedsRefresh();
219 if (!needsRefreshOffsetRanges) {
226 }));
227 }
229 >
230 > private _parseAndTokenizeViewPort(lineRanges: readonly LineRange[]) {
231 const viewportRanges = lineRanges.map(r => r.toInclusiveRange()).filter(isDefined);
232 for (const range of viewportRanges) {
251 }
252 }
254 > private _guessTokensForLinesContent(lineNumber: number, lines: string[]): Uint32Array[] | undefined {
255 if (lines.length === 0) {
256 return undefined;
293 return tokensByLine;
294 }
296 > private _forceParseAndTokenizeContent(range: Range, startOffsetOfRangeInDocument: number, endOffsetOfRangeInDocument: number, content: string, asUpdate: true): TokenUpdate[] | undefined;
297 > private _forceParseAndTokenizeContent(range: Range, startOffsetOfRangeInDocument: number, endOffsetOfRangeInDocument: number, content: string, asUpdate: false): EndOffsetToken[] | undefined;
298 > private _forceParseAndTokenizeContent(range: Range, startOffsetOfRangeInDocument: number, endOffsetOfRangeInDocument: number, content: string, asUpdate: boolean): EndOffsetToken[] | TokenUpdate[] | undefined {
299 const likelyRelevantLines = findLikelyRelevantLines(this._textModel, range.startLineNumber).likelyRelevantLines;
300 const likelyRelevantPrefix = likelyRelevantLines.join(this._textModel.getEOL());
320 }
321 }
323 >
324 > private _firstTreeUpdate(versionId: number) {
325 return this._setViewPortTokens(versionId);
326 }
328 > private _setViewPortTokens(versionId: number) {
329 const rangeChanges = this._visibleLineRanges.get().map<RangeChange | undefined>(lineRange => {
330 const range = lineRange.toInclusiveRange();
341 return this._handleTreeUpdate(rangeChanges, versionId);
342 }
344 > /**
345 > * Do not await in this method, it will cause a race
346 > */
347 > private _handleTreeUpdate(ranges: RangeChange[], versionId: number) {
348 const rangeChanges: RangeWithOffsets[] = [];
349 const chunkSize = 1000;
407 });
408 }
410 > private async _updateTreeForRanges(rangeChanges: RangeWithOffsets[], versionId: number, captures: QueryCapture[][]) {
411 let tokenUpdate: { newTokens: TokenUpdate[] } | undefined;
412
436 this._onDidCompleteBackgroundTokenization.fire();
437 }
439 > private _refreshNeedsRefresh(versionId: number) {
440 const rangesToRefresh = this._getNeedsRefresh();
441 if (rangesToRefresh.length === 0) {
455 this._handleTreeUpdate(rangeChanges, versionId);
456 }
458 > private _rangeTokensAsUpdates(rangeOffset: number, endOffsetToken: EndOffsetToken[], startingOffsetInArray?: number) {
459 const updates: TokenUpdate[] = [];
460 let lastEnd = 0;
474 return updates;
475 }
477 > private _updateTheme() {
478 const modelRange = this._textModel.getFullModelRange();
479 this._markForRefresh(modelRange);
480 this._parseAndTokenizeViewPort(this._visibleLineRanges.get());
481 }
483 > // Was used for inspect editor tokens command
484 > captureAtPosition(lineNumber: number, column: number): QueryCapture[] {
485 const captures = this.captureAtRangeWithInjections(new Range(lineNumber, column, lineNumber, column + 1));
486 return captures;
487 }
489 > // Was used for the colorization tests
490 > captureAtRangeTree(range: Range): QueryCapture[] {
491 const captures = this.captureAtRangeWithInjections(range);
492 return captures;
493 }
495 > private captureAtRange(range: Range): QueryCapture[] {
496 const tree = this._tree.tree.get();
497 if (!tree) {
519 ));
520 }
522 > private captureAtRangeWithInjections(range: Range): QueryCapture[] {
523 const captures: QueryCapture[] = this.captureAtRange(range);
524 for (let i = 0; i < captures.length; i++) {
544 return captures;
545 }
547 > /**
548 > * Gets the tokens for a given line.
549 > * Each token takes 2 elements in the array. The first element is the offset of the end of the token *in the line, not in the document*, and the second element is the metadata.
550 > *
551 > * @param lineNumber
552 > * @returns
553 > */
554 > public tokenizeEncoded(lineNumber: number) {
555 const tokens = this._tokenizeEncoded(lineNumber);
556 if (!tokens) {
562 }
563 }
565 > public tokenizeEncodedInstrumented(lineNumber: number): { result: Uint32Array; captureTime: number; metadataTime: number } | undefined {
566 const tokens = this._tokenizeEncoded(lineNumber);
567 if (!tokens) {
570 return { result: this._endOffsetTokensToUint32Array(tokens.result), captureTime: tokens.captureTime, metadataTime: tokens.metadataTime };
571 }
573 > private _getCaptures(range: Range): QueryCapture[] {
574 const captures = this.captureAtRangeWithInjections(range);
575 return captures;
576 }
578 > private _tokenize(range: Range, rangeStartOffset: number, rangeEndOffset: number): { endOffsetsAndMetadata: { endOffset: number; metadata: number }[]; versionId: number; captureTime: number; metadataTime: number } | undefined {
579 const captures = this._getCaptures(range);
580 const result = this._tokenizeCapturesWithMetadata(captures, rangeStartOffset, rangeEndOffset);
584 return { ...result, versionId: this._tree.treeLastParsedVersion.get() };
585 }
587 > private _createTokensFromCaptures(captures: QueryCapture[], rangeStartOffset: number, rangeEndOffset: number): { endOffsets: EndOffsetAndScopes[]; captureTime: number } | undefined {
588 const tree = this._tree.tree.get();
589 const stopwatch = StopWatch.create();
734 return { endOffsets: endOffsetsAndScopes as { endOffset: number; scopes: string[]; encodedLanguageId: LanguageId }[], captureTime };
735 }
737 > private _getInjectionCaptures(parentCapture: QueryCapture, range: Range): QueryCapture[] {
738 /*
739 const injection = textModelTreeSitter.getInjection(parentCapture.node.startIndex, this._treeSitterModel.languageId);
749 return [];
750 }
752 > private _tokenizeCapturesWithMetadata(captures: QueryCapture[], rangeStartOffset: number, rangeEndOffset: number): { endOffsetsAndMetadata: EndOffsetToken[]; captureTime: number; metadataTime: number } | undefined {
753 const stopwatch = StopWatch.create();
754 const emptyTokens = this._createTokensFromCaptures(captures, rangeStartOffset, rangeEndOffset);
765 return { endOffsetsAndMetadata: endOffsetsAndScopes as { endOffset: number; scopes: string[]; metadata: number }[], captureTime: emptyTokens.captureTime, metadataTime };
766 }
768 > private _tokenizeEncoded(lineNumber: number): { result: EndOffsetToken[]; captureTime: number; metadataTime: number; versionId: number } | undefined {
769 const lineOffset = this._textModel.getOffsetAt({ lineNumber: lineNumber, column: 1 });
770 const maxLine = this._textModel.getLineCount();
778 return { result: result.endOffsetsAndMetadata, captureTime: result.captureTime, metadataTime: result.metadataTime, versionId: result.versionId };
779 }
781 > private _endOffsetTokensToUint32Array(endOffsetsAndMetadata: EndOffsetToken[]): Uint32Array {
782
783 const uint32Array = new Uint32Array(endOffsetsAndMetadata.length * 2);
788 return uint32Array;
789 }
791 >
792 >
793 > interface EndOffsetToken {
794 > endOffset: number;
795 > metadata: number;
796 > }
797 >
798 > interface EndOffsetAndScopes {
799 > endOffset: number;
800 > scopes: string[];
801 > bracket?: number[];
802 > encodedLanguageId: LanguageId;
803 > }
804 >
805 > interface EndOffsetWithMeta extends EndOffsetAndScopes {
806 > metadata?: number;
807 > }
808 > export const TREESITTER_BASE_SCOPES: Record<string, string> = {
809 > 'css': 'source.css',
810 > 'typescript': 'source.ts',
811 > 'ini': 'source.ini',
812 > 'regex': 'source.regex',
813 > };
814 >
815 > const BRACKETS = /[\{\}\[\]\<\>\(\)]/g;
src/vs/editor/common/services/modelService.ts 152 covered LOC · 30 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- modelService.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 '../../../base/common/event.js';
7 > import { StringSHA1 } from '../../../base/common/hash.js';
8 > import { Disposable, DisposableStore, IDisposable } from '../../../base/common/lifecycle.js';
9 > import { Schemas } from '../../../base/common/network.js';
10 > import { equals } from '../../../base/common/objects.js';
11 > import * as platform from '../../../base/common/platform.js';
12 > import { URI } from '../../../base/common/uri.js';
13 > import { IConfigurationChangeEvent, IConfigurationService } from '../../../platform/configuration/common/configuration.js';
14 > import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
15 > import { IUndoRedoService, ResourceEditStackSnapshot } from '../../../platform/undoRedo/common/undoRedo.js';
16 > import { clampedInt } from '../config/editorOptions.js';
17 > import { EditOperation, ISingleEditOperation } from '../core/editOperation.js';
18 > import { EDITOR_MODEL_DEFAULTS } from '../core/misc/textModelDefaults.js';
19 > import { Range } from '../core/range.js';
20 > import { ILanguageSelection } from '../languages/language.js';
21 > import { PLAINTEXT_LANGUAGE_ID } from '../languages/modesRegistry.js';
22 > import { DefaultEndOfLine, EndOfLinePreference, EndOfLineSequence, ITextBuffer, ITextBufferFactory, ITextModel, ITextModelCreationOptions } from '../model.js';
23 > import { isEditStackElement } from '../model/editStack.js';
24 > import { TextModel, createTextBuffer } from '../model/textModel.js';
25 > import { EditSources, TextModelEditSource } from '../textModelEditSource.js';
26 > import { IModelLanguageChangedEvent } from '../textModelEvents.js';
27 > import { IModelService } from './model.js';
28 > import { ITextResourcePropertiesService } from './textResourceConfiguration.js';
29 >
30 function MODEL_ID(resource: URI): string {
31 return resource.toString();
32 }
34 > class ModelData implements IDisposable {
35 >
36 > private readonly _modelEventListeners = new DisposableStore();
37 >
38 > constructor(
39 public readonly model: TextModel,
40 onWillDispose: (model: ITextModel) => void,
45 this._modelEventListeners.add(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e)));
46 }
48 > public dispose(): void {
49 this._modelEventListeners.dispose();
50 }
52 >
53 > interface IRawEditorConfig {
54 > tabSize?: unknown;
55 > indentSize?: unknown;
56 > insertSpaces?: unknown;
57 > detectIndentation?: unknown;
58 > trimAutoWhitespace?: unknown;
59 > creationOptions?: unknown;
60 > largeFileOptimizations?: unknown;
61 > bracketPairColorization?: unknown;
62 > }
63 >
64 > interface IRawConfig {
65 > eol?: unknown;
66 > editor?: IRawEditorConfig;
67 > }
68 >
69 > const DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? DefaultEndOfLine.LF : DefaultEndOfLine.CRLF;
70 >
71 > class DisposedModelInfo {
72 > constructor(
73 public readonly uri: URI,
74 public readonly initialUndoRedoSnapshot: ResourceEditStackSnapshot | null,
80 public readonly alternativeVersionId: number,
81 ) { }
83 >
84 > export class ModelService extends Disposable implements IModelService {
85 >
86 > public static MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK = 20 * 1024 * 1024;
87 >
88 > public _serviceBrand: undefined;
89 >
90 > private readonly _onModelAdded: Emitter<ITextModel> = this._register(new Emitter<ITextModel>());
91 > public readonly onModelAdded: Event<ITextModel> = this._onModelAdded.event;
92 >
93 > private readonly _onModelRemoved: Emitter<ITextModel> = this._register(new Emitter<ITextModel>());
94 > public readonly onModelRemoved: Event<ITextModel> = this._onModelRemoved.event;
95 >
96 > private readonly _onModelModeChanged = this._register(new Emitter<{ model: ITextModel; oldLanguageId: string }>());
97 > public readonly onModelLanguageChanged = this._onModelModeChanged.event;
98 >
99 > private _modelCreationOptionsByLanguageAndResource: { [languageAndResource: string]: ITextModelCreationOptions };
100 >
101 > /**
102 > * All the models known in the system.
103 > */
104 > private readonly _models: { [modelId: string]: ModelData };
105 > private readonly _disposedModels: Map<string, DisposedModelInfo>;
106 > private _disposedModelsHeapSize: number;
107 >
108 > constructor(
109 @IConfigurationService private readonly _configurationService: IConfigurationService,
110 @ITextResourcePropertiesService private readonly _resourcePropertiesService: ITextResourcePropertiesService,
121 this._updateModelOptions(undefined);
122 }
124 > private static _readModelOptions(config: IRawConfig, isForSimpleWidget: boolean): ITextModelCreationOptions {
125 let tabSize = EDITOR_MODEL_DEFAULTS.tabSize;
126 if (config.editor && typeof config.editor.tabSize !== 'undefined') {
181 };
182 }
184 > private _getEOL(resource: URI | undefined, language: string): string {
185 if (resource) {
186 return this._resourcePropertiesService.getEOL(resource, language);
192 return platform.OS === platform.OperatingSystem.Linux || platform.OS === platform.OperatingSystem.Macintosh ? '\n' : '\r\n';
193 }
195 > private _shouldRestoreUndoStack(): boolean {
196 const result = this._configurationService.getValue('files.restoreUndoStack');
197 if (typeof result === 'boolean') {
200 return true;
201 }
203 > public getCreationOptions(languageIdOrSelection: string | ILanguageSelection, resource: URI | undefined, isForSimpleWidget: boolean): ITextModelCreationOptions {
204 const language = (typeof languageIdOrSelection === 'string' ? languageIdOrSelection : languageIdOrSelection.languageId);
205 let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource];
212 return creationOptions;
213 }
215 > private _updateModelOptions(e: IConfigurationChangeEvent | undefined): void {
216 const oldOptionsByLanguageAndResource = this._modelCreationOptionsByLanguageAndResource;
217 this._modelCreationOptionsByLanguageAndResource = Object.create(null);
234 }
235 }
237 > private static _setModelOptionsForModel(model: ITextModel, newOptions: ITextModelCreationOptions, currentOptions: ITextModelCreationOptions): void {
238 if (currentOptions && currentOptions.defaultEOL !== newOptions.defaultEOL && model.getLineCount() === 1) {
239 model.setEOL(newOptions.defaultEOL === DefaultEndOfLine.LF ? EndOfLineSequence.LF : EndOfLineSequence.CRLF);
268 }
269 }
271 > // --- begin IModelService
272 >
273 > private _insertDisposedModel(disposedModelData: DisposedModelInfo): void {
274 this._disposedModels.set(MODEL_ID(disposedModelData.uri), disposedModelData);
275 this._disposedModelsHeapSize += disposedModelData.heapSize;
276 }
278 > private _removeDisposedModel(resource: URI): DisposedModelInfo | undefined {
279 const disposedModelData = this._disposedModels.get(MODEL_ID(resource));
280 if (disposedModelData) {
284 return disposedModelData;
285 }
287 > private _ensureDisposedModelsHeapSize(maxModelsHeapSize: number): void {
288 if (this._disposedModelsHeapSize > maxModelsHeapSize) {
289 // we must remove some old undo stack elements to free up some memory
304 }
305 }
307 > private _createModelData(value: string | ITextBufferFactory, languageIdOrSelection: string | ILanguageSelection, resource: URI | undefined, isForSimpleWidget: boolean): ModelData {
308 // create & save the model
309 const options = this.getCreationOptions(languageIdOrSelection, resource, isForSimpleWidget);
362 return modelData;
363 }
365 > public updateModel(model: ITextModel, value: string | ITextBufferFactory, reason: TextModelEditSource = EditSources.unknown({ name: 'updateModel' })): void {
366 const options = this.getCreationOptions(model.getLanguageId(), model.uri, model.isForSimpleWidget);
367 const { textBuffer, disposable } = createTextBuffer(value, options.defaultEOL);
386 disposable.dispose();
387 }
389 > private static _commonPrefix(a: ITextModel, aLen: number, aDelta: number, b: ITextBuffer, bLen: number, bDelta: number): number {
390 const maxResult = Math.min(aLen, bLen);
391
396 return result;
397 }
399 > private static _commonSuffix(a: ITextModel, aLen: number, aDelta: number, b: ITextBuffer, bLen: number, bDelta: number): number {
400 const maxResult = Math.min(aLen, bLen);
401
406 return result;
407 }
409 > /**
410 > * Compute edits to bring `model` to the state of `textSource`.
411 > */
412 > public static _computeEdits(model: ITextModel, textBuffer: ITextBuffer): ISingleEditOperation[] {
413 const modelLineCount = model.getLineCount();
414 const textBufferLineCount = textBuffer.getLineCount();
437 return [EditOperation.replaceMove(oldRange, textBuffer.getValueInRange(newRange, EndOfLinePreference.TextDefined))];
438 }
440 > public createModel(value: string | ITextBufferFactory, languageSelection: ILanguageSelection | null, resource?: URI, isForSimpleWidget: boolean = false): ITextModel {
441 let modelData: ModelData;
442
451 return modelData.model;
452 }
454 > public destroyModel(resource: URI): void {
455 // We need to support that not all models get disposed through this service (i.e. model.dispose() should work!)
456 const modelData = this._models[MODEL_ID(resource)];
460 modelData.model.dispose();
461 }
463 > public getModels(): ITextModel[] {
464 const ret: ITextModel[] = [];
465
472 return ret;
473 }
475 > public getModel(resource: URI): ITextModel | null {
476 const modelId = MODEL_ID(resource);
477 const modelData = this._models[modelId];
481 return modelData.model;
482 }
484 > // --- end IModelService
485 >
486 > protected _schemaShouldMaintainUndoRedoElements(resource: URI) {
487 return (
488 resource.scheme === Schemas.file
493 );
494 }
496 > private _onWillDispose(model: ITextModel): void {
497 const modelId = MODEL_ID(model.uri);
498 const modelData = this._models[modelId];
551 this._onModelRemoved.fire(model);
552 }
554 > private _onDidChangeLanguage(model: ITextModel, e: IModelLanguageChangedEvent): void {
555 const oldLanguageId = e.oldLanguage;
556 const newLanguageId = model.getLanguageId();
560 this._onModelModeChanged.fire({ model, oldLanguageId: oldLanguageId });
561 }
563 > protected _getSHA1Computer(): ITextModelSHA1Computer {
564 return new DefaultModelSHA1Computer();
565 }
566 > } modelService.ts
567 >
568 > export interface ITextModelSHA1Computer {
569 > canComputeSHA1(model: ITextModel): boolean;
570 > computeSHA1(model: ITextModel): string;
571 > }
572 >
573 > export class DefaultModelSHA1Computer implements ITextModelSHA1Computer {
574 >
575 > public static MAX_MODEL_SIZE = 10 * 1024 * 1024; // takes 200ms to compute a sha1 on a 10MB model on a new machine
576 >
577 > canComputeSHA1(model: ITextModel): boolean {
578 return (model.getValueLength() <= DefaultModelSHA1Computer.MAX_MODEL_SIZE);
579 }
581 > computeSHA1(model: ITextModel): string {
582 // compute the sha1
583 const shaComputer = new StringSHA1();
src/vs/editor/common/core/ranges/lineRange.ts 148 covered LOC · 40 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,
94 endLineNumberExclusive: number,
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(
144 Math.min(this.startLineNumber, other.startLineNumber),
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;
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/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/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts 137 covered LOC · 42 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- pieceTreeTextBuffer.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 '../../../../base/common/event.js';
7 > import * as strings from '../../../../base/common/strings.js';
8 > import { Position } from '../../core/position.js';
9 > import { Range } from '../../core/range.js';
10 > import { ApplyEditsResult, EndOfLinePreference, FindMatch, IInternalModelContentChange, ISingleEditOperationIdentifier, ITextBuffer, ITextSnapshot, ValidAnnotatedEditOperation, IValidEditOperation, SearchData } from '../../model.js';
11 > import { PieceTreeBase, StringBuffer } from './pieceTreeBase.js';
12 > import { countEOL, StringEOL } from '../../core/misc/eolCounter.js';
13 > import { TextChange } from '../../core/textChange.js';
14 > import { Disposable } from '../../../../base/common/lifecycle.js';
15 >
16 > export interface IValidatedEditOperation {
17 > sortIndex: number;
18 > identifier: ISingleEditOperationIdentifier | null;
19 > range: Range;
20 > rangeOffset: number;
21 > rangeLength: number;
22 > text: string;
23 > eolCount: number;
24 > firstLineLength: number;
25 > lastLineLength: number;
26 > forceMoveMarkers: boolean;
27 > isAutoWhitespaceEdit: boolean;
28 > }
29 >
30 > interface IReverseSingleEditOperation extends IValidEditOperation {
31 > sortIndex: number;
32 > }
33 >
34 > export class PieceTreeTextBuffer extends Disposable implements ITextBuffer {
35 > private _pieceTree: PieceTreeBase;
36 > private readonly _BOM: string;
37 > private _mightContainRTL: boolean;
38 > private _mightContainUnusualLineTerminators: boolean;
39 > private _mightContainNonBasicASCII: boolean;
40 >
41 > private readonly _onDidChangeContent: Emitter<void> = this._register(new Emitter<void>());
42 > public get onDidChangeContent(): Event<void> { return this._onDidChangeContent.event; }
43 >
44 > constructor(chunks: StringBuffer[], BOM: string, eol: '\r\n' | '\n', containsRTL: boolean, containsUnusualLineTerminators: boolean, isBasicASCII: boolean, eolNormalized: boolean) {
45 > super(); pieceTreeTextBuffer.ts
46 > this._BOM = BOM;
47 > this._mightContainNonBasicASCII = !isBasicASCII;
48 > this._mightContainRTL = containsRTL;
49 > this._mightContainUnusualLineTerminators = containsUnusualLineTerminators;
50 > this._pieceTree = new PieceTreeBase(chunks, eol, eolNormalized);
51 > }
53 > // #region TextBuffer
54 > public equals(other: ITextBuffer): boolean {
55 if (!(other instanceof PieceTreeTextBuffer)) {
56 return false;
64 return this._pieceTree.equal(other._pieceTree);
65 }
66 > public mightContainRTL(): boolean { pieceTreeTextBuffer.ts
67 return this._mightContainRTL;
68 }
69 > public mightContainUnusualLineTerminators(): boolean { pieceTreeTextBuffer.ts
70 return this._mightContainUnusualLineTerminators;
71 }
72 > public resetMightContainUnusualLineTerminators(): void { pieceTreeTextBuffer.ts
73 this._mightContainUnusualLineTerminators = false;
74 }
75 > public mightContainNonBasicASCII(): boolean { pieceTreeTextBuffer.ts
76 return this._mightContainNonBasicASCII;
77 }
78 > public getBOM(): string { pieceTreeTextBuffer.ts
79 return this._BOM;
80 }
81 > public getEOL(): '\r\n' | '\n' { pieceTreeTextBuffer.ts
82 return this._pieceTree.getEOL();
83 }
85 > public createSnapshot(preserveBOM: boolean): ITextSnapshot {
86 return this._pieceTree.createSnapshot(preserveBOM ? this._BOM : '');
87 }
89 > public getOffsetAt(lineNumber: number, column: number): number {
90 return this._pieceTree.getOffsetAt(lineNumber, column);
91 }
93 > public getPositionAt(offset: number): Position {
94 return this._pieceTree.getPositionAt(offset);
95 }
97 > public getRangeAt(start: number, length: number): Range {
98 const end = start + length;
99 const startPosition = this.getPositionAt(start);
101 return new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
102 }
104 > public getValueInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): string {
105 if (range.isEmpty()) {
106 return '';
110 return this._pieceTree.getValueInRange(range, lineEnding);
111 }
113 > public getValueLengthInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): number {
114 if (range.isEmpty()) {
115 return 0;
136 return endOffset - startOffset + eolOffsetCompensation;
137 }
139 > public getCharacterCountInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): number {
140 if (this._mightContainNonBasicASCII) {
141 // we must count by iterating
167 return this.getValueLengthInRange(range, eol);
168 }
170 > public getNearestChunk(offset: number): string {
171 return this._pieceTree.getNearestChunk(offset);
172 }
174 > public getLength(): number {
175 return this._pieceTree.getLength();
176 }
178 > public getLineCount(): number {
179 return this._pieceTree.getLineCount();
180 }
182 > public getLinesContent(): string[] {
183 return this._pieceTree.getLinesContent();
184 }
186 > public getLineContent(lineNumber: number): string {
187 return this._pieceTree.getLineContent(lineNumber);
188 }
190 > public getLineCharCode(lineNumber: number, index: number): number {
191 return this._pieceTree.getLineCharCode(lineNumber, index);
192 }
194 > public getCharCode(offset: number): number {
195 return this._pieceTree.getCharCode(offset);
196 }
198 > public getLineLength(lineNumber: number): number {
199 return this._pieceTree.getLineLength(lineNumber);
200 }
202 > public getLineMinColumn(lineNumber: number): number {
203 return 1;
204 }
206 > public getLineMaxColumn(lineNumber: number): number {
207 return this.getLineLength(lineNumber) + 1;
208 }
210 > public getLineFirstNonWhitespaceColumn(lineNumber: number): number {
211 const result = strings.firstNonWhitespaceIndex(this.getLineContent(lineNumber));
212 if (result === -1) {
215 return result + 1;
216 }
218 > public getLineLastNonWhitespaceColumn(lineNumber: number): number {
219 const result = strings.lastNonWhitespaceIndex(this.getLineContent(lineNumber));
220 if (result === -1) {
223 return result + 2;
224 }
226 > private _getEndOfLine(eol: EndOfLinePreference): string {
227 switch (eol) {
228 case EndOfLinePreference.LF:
236 }
237 }
239 > public setEOL(newEOL: '\r\n' | '\n'): void {
240 this._pieceTree.setEOL(newEOL);
241 }
243 > public applyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult {
244 let mightContainRTL = this._mightContainRTL;
245 let mightContainUnusualLineTerminators = this._mightContainUnusualLineTerminators;
413 );
414 }
416 > /**
417 > * Transform operations such that they represent the same logic edit,
418 > * but that they also do not cause OOM crashes.
419 > */
420 > private _reduceOperations(operations: IValidatedEditOperation[]): IValidatedEditOperation[] {
421 if (operations.length < 1000) {
422 // We know from empirical testing that a thousand edits work fine regardless of their shape.
431 return [this._toSingleEditOperation(operations)];
432 }
434 > _toSingleEditOperation(operations: IValidatedEditOperation[]): IValidatedEditOperation {
435 let forceMoveMarkers = false;
436 const firstEditRange = operations[0].range;
476 };
477 }
479 > private _doApplyEdits(operations: IValidatedEditOperation[]): IInternalModelContentChange[] {
480 operations.sort(PieceTreeTextBuffer._sortOpsDescending);
481
517 return contentChanges;
518 }
520 > findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {
521 return this._pieceTree.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
522 }
524 > // #endregion
525 >
526 > // #region helper
527 > // testing purpose.
528 > public getPieceTree(): PieceTreeBase {
529 > return this._pieceTree; pieceTreeTextBuffer.ts
530 > }
532 > public static _getInverseEditRange(range: Range, text: string) {
533 const startLineNumber = range.startLineNumber;
534 const startColumn = range.startColumn;
554 return resultRange;
555 }
557 > /**
558 > * Assumes `operations` are validated and sorted ascending
559 > */
560 > public static _getInverseEditRanges(operations: IValidatedEditOperation[]): Range[] {
561 const result: Range[] = [];
562
610 return result;
611 }
613 > private static _sortOpsAscending(a: IValidatedEditOperation, b: IValidatedEditOperation): number {
614 const r = Range.compareRangesUsingEnds(a.range, b.range);
615 if (r === 0) {
618 return r;
619 }
621 > private static _sortOpsDescending(a: IValidatedEditOperation, b: IValidatedEditOperation): number {
622 const r = Range.compareRangesUsingEnds(a.range, b.range);
623 if (r === 0) {
src/vs/editor/common/languages/supports/tokenization.ts 134 covered LOC · 28 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tokenization.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 { IFontTokenOptions } from '../../../../platform/theme/common/themeService.js';
8 > import { LanguageId, FontStyle, ColorId, StandardTokenType, MetadataConsts } from '../../encodedTokenAttributes.js';
9 >
10 > export interface ITokenThemeRule {
11 > token: string;
12 > foreground?: string;
13 > background?: string;
14 > fontStyle?: string;
15 > }
16 >
17 > export class ParsedTokenThemeRule {
18 > _parsedThemeRuleBrand: void = undefined;
19 >
20 > readonly token: string;
21 > readonly index: number;
22 >
23 > /**
24 > * -1 if not set. An or mask of `FontStyle` otherwise.
25 > */
26 > readonly fontStyle: FontStyle;
27 > readonly foreground: string | null;
28 > readonly background: string | null;
29 >
30 > constructor(
31 token: string,
32 index: number,
41 this.background = background;
42 }
44 >
45 > /**
46 > * Parse a raw theme into rules.
47 > */
48 > export function parseTokenTheme(source: ITokenThemeRule[]): ParsedTokenThemeRule[] {
49 if (!source || !Array.isArray(source)) {
50 return [];
100 return result;
101 }
103 > /**
104 > * Resolve rules (i.e. inheritance).
105 > */
106 function resolveParsedTokenThemeRules(parsedThemeRules: ParsedTokenThemeRule[], customTokenColors: string[]): TokenTheme {
107
151 return new TokenTheme(colorMap, root);
152 }
154 > const colorRegExp = /^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/;
155 >
156 > export class ColorMap {
157 >
158 > private _lastColorId: number;
159 > private readonly _id2color: Color[];
160 > private readonly _color2id: Map<string, ColorId>;
161 >
162 > constructor() {
163 this._lastColorId = 0;
164 this._id2color = [];
165 this._color2id = new Map<string, ColorId>();
166 }
168 > public getId(color: string | null): ColorId {
169 if (color === null) {
170 return 0;
184 return value;
185 }
187 > public getColorMap(): Color[] {
188 return this._id2color.slice(0);
189 }
191 > }
192 >
193 > export class TokenTheme {
194 >
195 > public static createFromRawTokenTheme(source: ITokenThemeRule[], customTokenColors: string[]): TokenTheme {
196 return this.createFromParsedTokenTheme(parseTokenTheme(source), customTokenColors);
197 }
199 > public static createFromParsedTokenTheme(source: ParsedTokenThemeRule[], customTokenColors: string[]): TokenTheme {
200 return resolveParsedTokenThemeRules(source, customTokenColors);
201 }
203 > private readonly _colorMap: ColorMap;
204 > private readonly _root: ThemeTrieElement;
205 > private readonly _cache: Map<string, number>;
206 >
207 > constructor(colorMap: ColorMap, root: ThemeTrieElement) {
208 this._colorMap = colorMap;
209 this._root = root;
210 this._cache = new Map<string, number>();
211 }
213 > public getColorMap(): Color[] {
214 return this._colorMap.getColorMap();
215 }
217 > /**
218 > * used for testing purposes
219 > */
220 > public getThemeTrieElement(): ExternalThemeTrieElement {
221 return this._root.toExternalThemeTrieElement();
222 }
224 > public _match(token: string): ThemeTrieElementRule {
225 return this._root.match(token);
226 }
228 > public match(languageId: LanguageId, token: string): number {
229 // The cache contains the metadata without the language bits set.
230 let result = this._cache.get(token);
244 ) >>> 0;
245 }
246 > } tokenization.ts
247 >
248 > const STANDARD_TOKEN_TYPE_REGEXP = /\b(comment|string|regex|regexp)\b/;
249 > export function toStandardTokenType(tokenType: string): StandardTokenType {
250 const m = tokenType.match(STANDARD_TOKEN_TYPE_REGEXP);
251 if (!m) {
264 throw new Error('Unexpected match for standard token type!');
265 }
267 > export function strcmp(a: string, b: string): number {
268 if (a < b) {
269 return -1;
274 return 0;
275 }
277 > export class ThemeTrieElementRule {
278 > _themeTrieElementRuleBrand: void = undefined;
279 >
280 > private _fontStyle: FontStyle;
281 > private _foreground: ColorId;
282 > private _background: ColorId;
283 > public metadata: number;
284 >
285 > constructor(fontStyle: FontStyle, foreground: ColorId, background: ColorId) {
286 this._fontStyle = fontStyle;
287 this._foreground = foreground;
293 ) >>> 0;
294 }
296 > public clone(): ThemeTrieElementRule {
297 return new ThemeTrieElementRule(this._fontStyle, this._foreground, this._background);
298 }
300 > public acceptOverwrite(fontStyle: FontStyle, foreground: ColorId, background: ColorId): void {
301 if (fontStyle !== FontStyle.NotSet) {
302 this._fontStyle = fontStyle;
314 ) >>> 0;
315 }
316 > } tokenization.ts
317 >
318 > export class ExternalThemeTrieElement {
319 >
320 > public readonly mainRule: ThemeTrieElementRule;
321 > public readonly children: Map<string, ExternalThemeTrieElement>;
322 >
323 > constructor(
324 mainRule: ThemeTrieElementRule,
325 children: Map<string, ExternalThemeTrieElement> | { [key: string]: ExternalThemeTrieElement } = new Map<string, ExternalThemeTrieElement>()
335 }
336 }
337 > } tokenization.ts
338 >
339 > export class ThemeTrieElement {
340 > _themeTrieElementBrand: void = undefined;
341 >
342 > private readonly _mainRule: ThemeTrieElementRule;
343 > private readonly _children: Map<string, ThemeTrieElement>;
344 >
345 > constructor(mainRule: ThemeTrieElementRule) {
346 this._mainRule = mainRule;
347 this._children = new Map<string, ThemeTrieElement>();
348 }
350 > /**
351 > * used for testing purposes
352 > */
353 > public toExternalThemeTrieElement(): ExternalThemeTrieElement {
354 const children = new Map<string, ExternalThemeTrieElement>();
355 this._children.forEach((element, index) => {
358 return new ExternalThemeTrieElement(this._mainRule, children);
359 }
361 > public match(token: string): ThemeTrieElementRule {
362 if (token === '') {
363 return this._mainRule;
382 return this._mainRule;
383 }
385 > public insert(token: string, fontStyle: FontStyle, foreground: ColorId, background: ColorId): void {
386 if (token === '') {
387 // Merge into the main rule
409 child.insert(tail, fontStyle, foreground, background);
410 }
411 > } tokenization.ts
412 >
413 > export function generateTokensCSSForColorMap(colorMap: readonly Color[]): string {
414 const rules: string[] = [];
415 for (let i = 1, len = colorMap.length; i < len; i++) {
424 return rules.join('\n');
425 }
427 > export function generateTokensCSSForFontMap(fontMap: readonly IFontTokenOptions[]): string {
428 const rules: string[] = [];
429 const fonts = new Set<string>();
450 return rules.join('\n');
451 }
453 > export function classNameForFontTokenDecorations(fontFamily: string, fontSize: number): string {
454 const safeFontFamily = sanitizeFontFamilyForClassName(fontFamily);
455 return cleanClassName(`font-decoration-${safeFontFamily}-${fontSize}`);
456 }
458 function sanitizeFontFamilyForClassName(fontFamily: string): string {
459 const normalized = fontFamily.toLowerCase().trim();
463 return cleanClassName(normalized);
464 }
466 function cleanClassName(className: string): string {
467 return className.replace(/[^a-z0-9_-]/gi, '-');
src/vs/editor/common/core/ranges/offsetRange.ts 132 covered LOC · 40 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);
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) {
64 throw new BugIndicatingError(`Invalid range: ${this.toString()}`);
65 }
66 }
68 > get isEmpty(): boolean {
69 return this.start === this.endExclusive;
70 }
72 > public delta(offset: number): OffsetRange {
73 return new OffsetRange(this.start + offset, this.endExclusive + offset);
74 }
76 > public deltaStart(offset: number): OffsetRange {
77 return new OffsetRange(this.start + offset, this.endExclusive);
78 }
80 > public deltaEnd(offset: number): OffsetRange {
81 return new OffsetRange(this.start, this.endExclusive + offset);
82 }
84 > public get length(): number {
85 return this.endExclusive - this.start;
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));
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);
120 const end = Math.min(this.endExclusive, other.endExclusive);
124 return undefined;
125 }
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);
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/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts 132 covered LOC · 35 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- pieceTreeTextBufferBuilder.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 { IDisposable } from '../../../../base/common/lifecycle.js';
8 > import * as strings from '../../../../base/common/strings.js';
9 > import { DefaultEndOfLine, ITextBuffer, ITextBufferBuilder, ITextBufferFactory } from '../../model.js';
10 > import { StringBuffer, createLineStarts, createLineStartsFast } from './pieceTreeBase.js';
11 > import { PieceTreeTextBuffer } from './pieceTreeTextBuffer.js';
12 >
13 > class PieceTreeTextBufferFactory implements ITextBufferFactory {
14 >
15 > constructor(
16 > private readonly _chunks: StringBuffer[], pieceTreeTextBufferBuilder.ts
17 > private readonly _bom: string,
18 > private readonly _cr: number,
19 > private readonly _lf: number,
20 > private readonly _crlf: number,
21 > private readonly _containsRTL: boolean,
22 > private readonly _containsUnusualLineTerminators: boolean,
23 > private readonly _isBasicASCII: boolean,
24 > private readonly _normalizeEOL: boolean
25 > ) { }
27 > private _getEOL(defaultEOL: DefaultEndOfLine): '\r\n' | '\n' {
28 > const totalEOLCount = this._cr + this._lf + this._crlf; pieceTreeTextBufferBuilder.ts
29 > const totalCRCount = this._cr + this._crlf;
30 > if (totalEOLCount === 0) {
31 > // This is an empty file or a file with precisely one line pieceTreeTextBufferBuilder.ts
32 > return (defaultEOL === DefaultEndOfLine.LF ? '\n' : '\r\n');
33 > }
34 if (totalCRCount > totalEOLCount / 2) {
35 // More than half of the file contains \r\n ending lines
38 // At least one line more ends in \n
39 return '\n';
42 > public create(defaultEOL: DefaultEndOfLine): { textBuffer: ITextBuffer; disposable: IDisposable } {
43 > const eol = this._getEOL(defaultEOL); pieceTreeTextBufferBuilder.ts
44 > const chunks = this._chunks;
45 >
46 > if (this._normalizeEOL &&
47 > ((eol === '\r\n' && (this._cr > 0 || this._lf > 0)) pieceTreeTextBufferBuilder.ts
48 > || (eol === '\n' && (this._cr > 0 || this._crlf > 0))) pieceTreeTextBufferBuilder.ts
50 // Normalize pieces
51 for (let i = 0, len = chunks.length; i < len; i++) {
55 }
56 }
58 > const textBuffer = new PieceTreeTextBuffer(chunks, this._bom, eol, this._containsRTL, this._containsUnusualLineTerminators, this._isBasicASCII, this._normalizeEOL);
59 > return { textBuffer: textBuffer, disposable: textBuffer };
60 > }
62 > public getFirstLineText(lengthLimit: number): string {
63 return this._chunks[0].buffer.substr(0, lengthLimit).split(/\r\n|\r|\n/)[0];
64 }
66 >
67 > export class PieceTreeTextBufferBuilder implements ITextBufferBuilder {
68 > private readonly chunks: StringBuffer[];
69 > private BOM: string;
70 >
71 > private _hasPreviousChar: boolean;
72 > private _previousChar: number;
73 > private readonly _tmpLineStarts: number[];
74 >
75 > private cr: number;
76 > private lf: number;
77 > private crlf: number;
78 > private containsRTL: boolean;
79 > private containsUnusualLineTerminators: boolean;
80 > private isBasicASCII: boolean;
81 >
82 > constructor() {
83 > this.chunks = []; pieceTreeTextBufferBuilder.ts
84 > this.BOM = '';
85 >
86 > this._hasPreviousChar = false;
87 > this._previousChar = 0;
88 > this._tmpLineStarts = [];
89 >
90 > this.cr = 0;
91 > this.lf = 0;
92 > this.crlf = 0;
93 > this.containsRTL = false;
94 > this.containsUnusualLineTerminators = false;
95 > this.isBasicASCII = true;
96 > }
98 > public acceptChunk(chunk: string): void {
99 > if (chunk.length === 0) { pieceTreeTextBufferBuilder.ts
101 > }
102
103 if (this.chunks.length === 0) {
109
110 const lastChar = chunk.charCodeAt(chunk.length - 1);
111 > if (lastChar === CharCode.CarriageReturn || (lastChar >= 0xD800 && lastChar <= 0xDBFF)) { pieceTreeTextBufferBuilder.ts
112 // last character is \r or a high surrogate => keep it back
113 this._acceptChunk1(chunk.substr(0, chunk.length - 1), false);
119 this._previousChar = lastChar;
120 }
123 > private _acceptChunk1(chunk: string, allowEmptyStrings: boolean): void {
124 > if (!allowEmptyStrings && chunk.length === 0) { pieceTreeTextBufferBuilder.ts
125 // Nothing to do
126 return;
127 }
129 > if (this._hasPreviousChar) {
130 this._acceptChunk2(String.fromCharCode(this._previousChar) + chunk);
132 > this._acceptChunk2(chunk);
133 > }
134 > }
136 > private _acceptChunk2(chunk: string): void {
137 > const lineStarts = createLineStarts(this._tmpLineStarts, chunk); pieceTreeTextBufferBuilder.ts
138 >
139 > this.chunks.push(new StringBuffer(chunk, lineStarts.lineStarts));
140 > this.cr += lineStarts.cr;
141 > this.lf += lineStarts.lf;
142 > this.crlf += lineStarts.crlf;
143 >
144 > if (!lineStarts.isBasicASCII) {
145 // this chunk contains non basic ASCII characters
146 this.isBasicASCII = false;
152 }
153 }
156 > public finish(normalizeEOL: boolean = true): PieceTreeTextBufferFactory {
157 > this._finish(); pieceTreeTextBufferBuilder.ts
158 > return new PieceTreeTextBufferFactory(
159 > this.chunks,
160 > this.BOM,
161 > this.cr,
162 > this.lf,
163 > this.crlf,
164 > this.containsRTL,
165 > this.containsUnusualLineTerminators,
166 > this.isBasicASCII,
167 > normalizeEOL
168 > );
169 > }
171 > private _finish(): void {
172 > if (this.chunks.length === 0) { pieceTreeTextBufferBuilder.ts
173 > this._acceptChunk1('', true); pieceTreeTextBufferBuilder.ts
174 > }
176 > if (this._hasPreviousChar) {
177 this._hasPreviousChar = false;
178 // recreate last chunk
src/vs/editor/common/model/tokens/treeSitter/tokenStore.ts 130 covered LOC · 32 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tokenStore.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { IDisposable } from '../../../../../base/common/lifecycle.js';
7 > import { ITextModel } from '../../../model.js';
8 >
9 > // Exported for tests
10 > export class ListNode implements IDisposable {
11 > parent?: ListNode;
12 > private readonly _children: Node[] = [];
13 > get children(): ReadonlyArray<Node> { return this._children; }
14 >
15 > private _length: number = 0;
16 > get length(): number { return this._length; }
17 >
18 > constructor(public readonly height: number) { }
19 >
20 > static create(node1: Node, node2: Node) {
21 const list = new ListNode(node1.height + 1);
22 list.appendChild(node1);
24 return list;
25 }
27 > canAppendChild(): boolean {
28 return this._children.length < 3;
29 }
31 > appendChild(node: Node) {
32 if (!this.canAppendChild()) {
33 throw new Error('Cannot insert more than 3 children in a ListNode');
41 }
42 }
44 > private _updateParentLength(delta: number) {
45 let updateParent = this.parent;
46 while (updateParent) {
49 }
50 }
52 > unappendChild(): Node {
53 const child = this._children.pop()!;
54 this._length -= child.length;
56 return child;
57 }
59 > prependChild(node: Node) {
60 if (this._children.length >= 3) {
61 throw new Error('Cannot prepend more than 3 children in a ListNode');
69 }
70 }
72 > unprependChild(): Node {
73 const child = this._children.shift()!;
74 this._length -= child.length;
76 return child;
77 }
79 > lastChild(): Node {
80 return this._children[this._children.length - 1];
81 }
83 > dispose() {
84 this._children.splice(0, this._children.length);
85 }
86 > } tokenStore.ts
87 >
88 > export enum TokenQuality {
89 > None = 0,
90 > ViewportGuess = 1,
91 > EditGuess = 2,
92 > Accurate = 3
93 > }
94 >
95 > type Node = ListNode | LeafNode;
96 >
97 > // Exported for tests
98 > export interface LeafNode {
99 > readonly length: number;
100 > token: number;
101 > tokenQuality: TokenQuality;
102 > height: 0;
103 > }
104 >
105 > export interface TokenUpdate {
106 > readonly startOffsetInclusive: number;
107 > readonly length: number;
108 > readonly token: number;
109 > }
110 >
111 function isLeaf(node: Node): node is LeafNode {
112 return (node as LeafNode).token !== undefined;
113 }
115 > // Heavily inspired by https://github.com/microsoft/vscode/blob/4eb2658d592cb6114a7a393655574176cc790c5b/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/concat23Trees.ts#L108-L109
116 function append(node: Node, nodeToAppend: Node): Node {
117 let curNode = node;
154 }
155 }
157 function prepend(list: Node, nodeToAppend: Node): Node {
158 let curNode = list;
188 }
189 }
191 function concat(node1: Node, node2: Node): Node {
192 if (node1.height === node2.height) {
200 }
201 }
203 > export class TokenStore implements IDisposable {
204 > private _root: Node;
205 > get root(): Node {
206 > return this._root;
207 > }
208 >
209 > constructor(private readonly _textModel: ITextModel) {
210 this._root = this.createEmptyRoot();
211 }
213 > private createEmptyRoot(): Node {
214 return {
215 length: this._textModel.getValueLength(),
219 };
220 }
222 > /**
223 > *
224 > * @param update all the tokens for the document in sequence
225 > */
226 > buildStore(tokens: TokenUpdate[], tokenQuality: TokenQuality): void {
227 this._root = this.createFromUpdates(tokens, tokenQuality);
228 }
230 > private createFromUpdates(tokens: TokenUpdate[], tokenQuality: TokenQuality): Node {
231 if (tokens.length === 0) {
232 return this.createEmptyRoot();
243 return newRoot;
244 }
246 > /**
247 > *
248 > * @param tokens tokens are in sequence in the document.
249 > */
250 > update(length: number, tokens: TokenUpdate[], tokenQuality: TokenQuality) {
251 if (tokens.length === 0) {
252 return;
254 this.replace(length, tokens[0].startOffsetInclusive, tokens, tokenQuality);
255 }
257 > delete(length: number, startOffset: number) {
258 this.replace(length, startOffset, [], TokenQuality.EditGuess);
259 }
261 > /**
262 > *
263 > * @param tokens tokens are in sequence in the document.
264 > */
265 > private replace(length: number, updateOffsetStart: number, tokens: TokenUpdate[], tokenQuality: TokenQuality) {
266 const firstUnchangedOffsetAfterUpdate = updateOffsetStart + length;
267 // Find the last unchanged node preceding the update
326 this._root = newRoot ?? this.createEmptyRoot();
327 }
329 > /**
330 > *
331 > * @param startOffsetInclusive
332 > * @param endOffsetExclusive
333 > * @param visitor Return true from visitor to exit early
334 > * @returns
335 > */
336 > private traverseInOrderInRange(startOffsetInclusive: number, endOffsetExclusive: number, visitor: (node: Node, offset: number) => boolean): void {
337 const stack: { node: Node; offset: number }[] = [{ node: this._root, offset: 0 }];
338
360 }
361 }
363 > getTokenAt(offset: number): TokenUpdate | undefined {
364 let result: TokenUpdate | undefined;
365 this.traverseInOrderInRange(offset, this._root.length, (node, offset) => {
372 return result;
373 }
375 > getTokensInRange(startOffsetInclusive: number, endOffsetExclusive: number): TokenUpdate[] {
376 const result: { token: number; startOffsetInclusive: number; length: number }[] = [];
377 this.traverseInOrderInRange(startOffsetInclusive, endOffsetExclusive, (node, offset) => {
394 return result;
395 }
397 > markForRefresh(startOffsetInclusive: number, endOffsetExclusive: number): void {
398 this.traverseInOrderInRange(startOffsetInclusive, endOffsetExclusive, (node) => {
399 if (isLeaf(node)) {
403 });
404 }
406 > rangeHasTokens(startOffsetInclusive: number, endOffsetExclusive: number, minimumTokenQuality: TokenQuality): boolean {
407 let hasAny = true;
408 this.traverseInOrderInRange(startOffsetInclusive, endOffsetExclusive, (node) => {
414 return hasAny;
415 }
417 > rangeNeedsRefresh(startOffsetInclusive: number, endOffsetExclusive: number): boolean {
418 let needsRefresh = false;
419 this.traverseInOrderInRange(startOffsetInclusive, endOffsetExclusive, (node) => {
425 return needsRefresh;
426 }
428 > getNeedsRefresh(): { startOffset: number; endOffset: number }[] {
429 const result: { startOffset: number; endOffset: number }[] = [];
430
441 return result;
442 }
444 > public deepCopy(): TokenStore {
445 const newStore = new TokenStore(this._textModel);
446 newStore._root = this._copyNodeIterative(this._root);
447 return newStore;
448 }
450 > private _copyNodeIterative(root: Node): Node {
451 const newRoot = isLeaf(root)
452 ? { length: root.length, token: root.token, tokenQuality: root.tokenQuality, height: root.height }
471 return newRoot;
472 }
474 > /**
475 > * Returns a string representation of the token tree using an iterative approach
476 > */
477 > printTree(root: Node = this._root): string {
478 const result: string[] = [];
479 const stack: Array<[Node, number]> = [[root, 0]];
496 return result.join('');
497 }
499 > dispose(): void {
500 const stack: Array<[Node, boolean]> = [[this._root, false]];
501 while (stack.length > 0) {
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/editor/common/model/tokens/tokenizationTextModelPart.ts 124 covered LOC · 29 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tokenizationTextModelPart.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 { BugIndicatingError } from '../../../../base/common/errors.js';
8 > import { Emitter, Event } from '../../../../base/common/event.js';
9 > import { countEOL } from '../../core/misc/eolCounter.js';
10 > import { IPosition, Position } from '../../core/position.js';
11 > import { Range } from '../../core/range.js';
12 > import { IWordAtPosition, getWordAtText } from '../../core/wordHelper.js';
13 > import { StandardTokenType } from '../../encodedTokenAttributes.js';
14 > import { ILanguageService } from '../../languages/language.js';
15 > import { ILanguageConfigurationService, LanguageConfigurationServiceChangeEvent, ResolvedLanguageConfiguration } from '../../languages/languageConfigurationRegistry.js';
16 > import { BracketPairsTextModelPart } from '../bracketPairsTextModelPart/bracketPairsImpl.js';
17 > import { TextModel } from '../textModel.js';
18 > import { TextModelPart } from '../textModelPart.js';
19 > import { AbstractSyntaxTokenBackend, AttachedViews } from './abstractSyntaxTokenBackend.js';
20 > import { TreeSitterSyntaxTokenBackend } from './treeSitter/treeSitterSyntaxTokenBackend.js';
21 > import { IModelContentChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelTokensChangedEvent, IModelFontTokensChangedEvent } from '../../textModelEvents.js';
22 > import { ITokenizationTextModelPart } from '../../tokenizationTextModelPart.js';
23 > import { LineTokens } from '../../tokens/lineTokens.js';
24 > import { SparseMultilineTokens } from '../../tokens/sparseMultilineTokens.js';
25 > import { SparseTokensStore } from '../../tokens/sparseTokensStore.js';
26 > import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
27 > import { TokenizerSyntaxTokenBackend } from './tokenizerSyntaxTokenBackend.js';
28 > import { ITreeSitterLibraryService } from '../../services/treeSitter/treeSitterLibraryService.js';
29 > import { derived, IObservable, ISettableObservable, observableValue } from '../../../../base/common/observable.js';
30 >
31 > export class TokenizationTextModelPart extends TextModelPart implements ITokenizationTextModelPart {
32 > private readonly _semanticTokens: SparseTokensStore;
33 >
34 > private readonly _onDidChangeLanguage: Emitter<IModelLanguageChangedEvent>;
35 > public readonly onDidChangeLanguage: Event<IModelLanguageChangedEvent>;
36 >
37 > private readonly _onDidChangeLanguageConfiguration: Emitter<IModelLanguageConfigurationChangedEvent>;
38 > public readonly onDidChangeLanguageConfiguration: Event<IModelLanguageConfigurationChangedEvent>;
39 >
40 > private readonly _onDidChangeTokens: Emitter<IModelTokensChangedEvent>;
41 > public readonly onDidChangeTokens: Event<IModelTokensChangedEvent>;
42 >
43 > private readonly _onDidChangeFontTokens: Emitter<IModelFontTokensChangedEvent> = this._register(new Emitter<IModelFontTokensChangedEvent>());
44 > public readonly onDidChangeFontTokens: Event<IModelFontTokensChangedEvent> = this._onDidChangeFontTokens.event;
45 >
46 > public readonly tokens: IObservable<AbstractSyntaxTokenBackend>;
47 > private readonly _useTreeSitter: IObservable<boolean>;
48 > private readonly _languageIdObs: ISettableObservable<string>;
49 >
50 > constructor(
51 private readonly _textModel: TextModel,
52 private readonly _bracketPairsTextModelPart: BracketPairsTextModelPart,
116 this.onDidChangeFontTokens = this._onDidChangeFontTokens.event;
117 }
119 > _hasListeners(): boolean {
120 // Note: _onDidChangeFontTokens is intentionally excluded because it's an internal event
121 // that TokenizationFontDecorationProvider subscribes to during TextModel construction
124 || this._onDidChangeTokens.hasListeners());
125 }
127 > public handleLanguageConfigurationServiceChange(e: LanguageConfigurationServiceChangeEvent): void {
128 if (e.affects(this._languageId)) {
129 this._onDidChangeLanguageConfiguration.fire({});
130 }
131 }
133 > public handleDidChangeContent(e: IModelContentChangedEvent): void {
134 if (e.isFlush) {
135 this._semanticTokens.flush();
150 this.tokens.get().handleDidChangeContent(e);
151 }
153 > public handleDidChangeAttached(): void {
154 this.tokens.get().handleDidChangeAttached();
155 }
157 > /**
158 > * Includes grammar and semantic tokens.
159 > */
160 > public getLineTokens(lineNumber: number): LineTokens {
161 this.validateLineNumber(lineNumber);
162 const syntacticTokens = this.tokens.get().getLineTokens(lineNumber);
163 return this._semanticTokens.addSparseTokens(lineNumber, syntacticTokens);
164 }
166 > private _emitModelTokensChangedEvent(e: IModelTokensChangedEvent): void {
167 if (!this._textModel._isDisposing()) {
168 this._bracketPairsTextModelPart.handleDidChangeTokens(e);
170 }
171 }
173 > // #region Grammar Tokens
174 >
175 > private validateLineNumber(lineNumber: number): void {
176 if (lineNumber < 1 || lineNumber > this._textModel.getLineCount()) {
177 throw new BugIndicatingError('Illegal value for lineNumber');
178 }
179 }
181 > public get hasTokens(): boolean {
182 return this.tokens.get().hasTokens;
183 }
185 > public resetTokenization() {
186 this.tokens.get().todo_resetTokenization();
187 }
189 > public get backgroundTokenizationState() {
190 return this.tokens.get().backgroundTokenizationState;
191 }
193 > public forceTokenization(lineNumber: number): void {
194 this.validateLineNumber(lineNumber);
195 this.tokens.get().forceTokenization(lineNumber);
196 }
198 > public hasAccurateTokensForLine(lineNumber: number): boolean {
199 this.validateLineNumber(lineNumber);
200 return this.tokens.get().hasAccurateTokensForLine(lineNumber);
201 }
203 > public isCheapToTokenize(lineNumber: number): boolean {
204 this.validateLineNumber(lineNumber);
205 return this.tokens.get().isCheapToTokenize(lineNumber);
206 }
208 > public tokenizeIfCheap(lineNumber: number): void {
209 this.validateLineNumber(lineNumber);
210 this.tokens.get().tokenizeIfCheap(lineNumber);
211 }
213 > public getTokenTypeIfInsertingCharacter(lineNumber: number, column: number, character: string): StandardTokenType {
214 return this.tokens.get().getTokenTypeIfInsertingCharacter(lineNumber, column, character);
215 }
217 > public tokenizeLinesAt(lineNumber: number, lines: string[]): LineTokens[] | null {
218 return this.tokens.get().tokenizeLinesAt(lineNumber, lines);
219 }
221 > // #endregion
222 >
223 > // #region Semantic Tokens
224 >
225 > public setSemanticTokens(tokens: SparseMultilineTokens[] | null, isComplete: boolean): void {
226 this._semanticTokens.set(tokens, isComplete, this._textModel);
227
231 });
232 }
234 > public hasCompleteSemanticTokens(): boolean {
235 return this._semanticTokens.isComplete();
236 }
238 > public hasSomeSemanticTokens(): boolean {
239 return !this._semanticTokens.isEmpty();
240 }
242 > public setPartialSemanticTokens(range: Range, tokens: SparseMultilineTokens[]): void {
243 if (this.hasCompleteSemanticTokens()) {
244 return;
258 });
259 }
261 > // #endregion
262 >
263 > // #region Utility Methods
264 >
265 > public getWordAtPosition(_position: IPosition): IWordAtPosition | null {
266 this.assertNotDisposed();
267
313 return null;
314 }
316 > private getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration {
317 return this._languageConfigurationService.getLanguageConfiguration(languageId);
318 }
320 > private static _findLanguageBoundaries(lineTokens: LineTokens, tokenIndex: number): [number, number] {
321 const languageId = lineTokens.getLanguageId(tokenIndex);
322
339 return [startOffset, endOffset];
340 }
342 > public getWordUntilPosition(position: IPosition): IWordAtPosition {
343 const wordAtPosition = this.getWordAtPosition(position);
344 if (!wordAtPosition) {
351 };
352 }
354 > // #endregion
355 >
356 > // #region Language Id handling
357 >
358 > public getLanguageId(): string {
359 return this._languageId;
360 }
362 > public getLanguageIdAtPosition(lineNumber: number, column: number): string {
363 const position = this._textModel.validatePosition(new Position(lineNumber, column));
364 const lineTokens = this.getLineTokens(position.lineNumber);
365 return lineTokens.getLanguageId(lineTokens.findTokenIndexAtOffset(position.column - 1));
366 }
368 > public setLanguageId(languageId: string, source: string = 'api'): void {
369 if (this._languageId === languageId) {
370 // There's nothing to do
src/vs/platform/instantiation/common/instantiation.ts 124 covered LOC · 11 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- abstractSyntaxTokenBackend.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 { RunOnceScheduler } from '../../../../base/common/async.js';
8 > import { Emitter, Event } from '../../../../base/common/event.js';
9 > import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
10 > import { LineRange } from '../../core/ranges/lineRange.js';
11 > import { StandardTokenType } from '../../encodedTokenAttributes.js';
12 > import { ILanguageIdCodec } from '../../languages.js';
13 > import { IAttachedView } from '../../model.js';
14 > import { TextModel } from '../textModel.js';
15 > import { IModelContentChangedEvent, IModelTokensChangedEvent, IModelFontTokensChangedEvent } from '../../textModelEvents.js';
16 > import { BackgroundTokenizationState } from '../../tokenizationTextModelPart.js';
17 > import { LineTokens } from '../../tokens/lineTokens.js';
18 > import { derivedOpts, IObservable, ISettableObservable, observableSignal, observableValueOpts } from '../../../../base/common/observable.js';
19 > import { equalsIfDefinedC, thisEqualsC, arrayEqualsC } from '../../../../base/common/equals.js';
20 >
21 > /**
22 > * @internal
23 > */
24 > export class AttachedViews implements IDisposable {
25 > private readonly _onDidChangeVisibleRanges = new Emitter<{ view: IAttachedView; state: AttachedViewState | undefined }>();
26 > public readonly onDidChangeVisibleRanges = this._onDidChangeVisibleRanges.event;
27 >
28 > private readonly _views = new Set<AttachedViewImpl>();
29 > private readonly _viewsChanged = observableSignal(this);
30 >
31 > public readonly visibleLineRanges: IObservable<readonly LineRange[]>;
32 >
33 > constructor() {
34 this.visibleLineRanges = derivedOpts({
35 owner: this,
43 });
44 }
46 > public attachView(): IAttachedView {
47 const view = new AttachedViewImpl((state) => {
48 this._onDidChangeVisibleRanges.fire({ view, state });
52 return view;
53 }
55 > public detachView(view: IAttachedView): void {
56 this._views.delete(view as AttachedViewImpl);
57 this._onDidChangeVisibleRanges.fire({ view, state: undefined });
58 this._viewsChanged.trigger(undefined);
59 }
61 > public dispose(): void {
62 this._onDidChangeVisibleRanges.dispose();
63 }
65 >
66 > /**
67 > * @internal
68 > */
69 > export class AttachedViewState {
70 > constructor(
71 readonly visibleLineRanges: readonly LineRange[],
72 readonly stabilized: boolean,
73 ) { }
75 > public equals(other: AttachedViewState): boolean {
76 if (this === other) {
77 return true;
85 return true;
86 }
88 >
89 > class AttachedViewImpl implements IAttachedView {
90 > private readonly _state: ISettableObservable<AttachedViewState | undefined>;
91 > public get state(): IObservable<AttachedViewState | undefined> { return this._state; }
92 >
93 > constructor(
94 private readonly handleStateChange: (state: AttachedViewState) => void
95 ) {
96 this._state = observableValueOpts<AttachedViewState | undefined>({ owner: this, equalsFn: equalsIfDefinedC((a, b) => a.equals(b)) }, undefined);
97 }
99 > setVisibleLines(visibleLines: { startLineNumber: number; endLineNumber: number }[], stabilized: boolean): void {
100 const visibleLineRanges = visibleLines.map((line) => new LineRange(line.startLineNumber, line.endLineNumber + 1));
101 const state = new AttachedViewState(visibleLineRanges, stabilized);
103 this.handleStateChange(state);
104 }
106 >
107 >
108 > export class AttachedViewHandler extends Disposable {
109 > private readonly runner = this._register(new RunOnceScheduler(() => this.update(), 50));
110 >
111 > private _computedLineRanges: readonly LineRange[] = [];
112 > private _lineRanges: readonly LineRange[] = [];
113 > public get lineRanges(): readonly LineRange[] { return this._lineRanges; }
114 >
115 > constructor(private readonly _refreshTokens: () => void) {
116 super();
117 }
119 > private update(): void {
120 if (equals(this._computedLineRanges, this._lineRanges, (a, b) => a.equals(b))) {
121 return;
124 this._refreshTokens();
125 }
127 > public handleStateChange(state: AttachedViewState): void {
128 this._lineRanges = state.visibleLineRanges;
129 if (state.stabilized) {
134 }
135 }
137 >
138 > export abstract class AbstractSyntaxTokenBackend extends Disposable {
139 > protected abstract _backgroundTokenizationState: BackgroundTokenizationState;
140 > public get backgroundTokenizationState(): BackgroundTokenizationState {
141 > return this._backgroundTokenizationState;
142 > }
143 >
144 > protected abstract readonly _onDidChangeBackgroundTokenizationState: Emitter<void>;
145 > /** @internal, should not be exposed by the text model! */
146 > public abstract readonly onDidChangeBackgroundTokenizationState: Event<void>;
147 >
148 > protected readonly _onDidChangeTokens = this._register(new Emitter<IModelTokensChangedEvent>());
149 > /** @internal, should not be exposed by the text model! */
150 > public readonly onDidChangeTokens: Event<IModelTokensChangedEvent> = this._onDidChangeTokens.event;
151 >
152 > protected readonly _onDidChangeFontTokens: Emitter<IModelFontTokensChangedEvent> = this._register(new Emitter<IModelFontTokensChangedEvent>());
153 > /** @internal, should not be exposed by the text model! */
154 > public readonly onDidChangeFontTokens: Event<IModelFontTokensChangedEvent> = this._onDidChangeFontTokens.event;
155 >
156 > constructor(
157 protected readonly _languageIdCodec: ILanguageIdCodec,
158 protected readonly _textModel: TextModel,
160 super();
161 }
163 > public abstract todo_resetTokenization(fireTokenChangeEvent?: boolean): void;
164 >
165 > public abstract handleDidChangeAttached(): void;
166 >
167 > public abstract handleDidChangeContent(e: IModelContentChangedEvent): void;
168 >
169 > public abstract forceTokenization(lineNumber: number): void;
170 >
171 > public abstract hasAccurateTokensForLine(lineNumber: number): boolean;
172 >
173 > public abstract isCheapToTokenize(lineNumber: number): boolean;
174 >
175 > public tokenizeIfCheap(lineNumber: number): void {
176 if (this.isCheapToTokenize(lineNumber)) {
177 this.forceTokenization(lineNumber);
178 }
179 }
181 > public abstract getLineTokens(lineNumber: number): LineTokens;
182 >
183 > public abstract getTokenTypeIfInsertingCharacter(lineNumber: number, column: number, character: string): StandardTokenType;
184 >
185 > public abstract tokenizeLinesAt(lineNumber: number, lines: string[]): LineTokens[] | null;
186 >
187 > public abstract get hasTokens(): boolean;
188 > }
src/vs/platform/telemetry/common/telemetry.ts 115 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- telemetry.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 { createDecorator } from '../../instantiation/common/instantiation.js';
7 > import { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from './gdprTypings.js';
8 >
9 > export const ITelemetryService = createDecorator<ITelemetryService>('telemetryService');
10 >
11 > export interface ITelemetryData {
12 > from?: string;
13 > target?: string;
14 > [key: string]: string | unknown | undefined;
15 > }
16 >
17 > export interface ITelemetryService {
18 >
19 > readonly _serviceBrand: undefined;
20 >
21 > readonly telemetryLevel: TelemetryLevel;
22 >
23 > readonly sessionId: string;
24 > readonly machineId: string;
25 > readonly sqmId: string;
26 > readonly devDeviceId: string;
27 > readonly firstSessionDate: string;
28 > readonly msftInternal?: boolean;
29 >
30 > /**
31 > * Whether error telemetry will get sent. If false, `publicLogError` will no-op.
32 > */
33 > readonly sendErrorTelemetry: boolean;
34 >
35 > /**
36 > * @deprecated Use publicLog2 and the typescript GDPR annotation where possible
37 > */
38 > publicLog(eventName: string, data?: ITelemetryData): void;
39 >
40 > /**
41 > * Sends a telemetry event that has been privacy approved.
42 > * Do not call this unless you have been given approval.
43 > */
44 > publicLog2<E extends ClassifiedEvent<OmitMetadata<T>> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck<T, E>): void;
45 >
46 > /**
47 > * @deprecated Use publicLogError2 and the typescript GDPR annotation where possible
48 > */
49 > publicLogError(errorEventName: string, data?: ITelemetryData): void;
50 >
51 > publicLogError2<E extends ClassifiedEvent<OmitMetadata<T>> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck<T, E>): void;
52 >
53 > setExperimentProperty(name: string, value: string): void;
54 >
55 > /**
56 > * Sets a common property that will be attached to all telemetry events.
57 > * Common properties are added after PII cleaning and cannot be overridden by event data.
58 > */
59 > setCommonProperty(name: string, value: string | boolean): void;
60 > }
61 >
62 > export function telemetryLevelEnabled(service: ITelemetryService, level: TelemetryLevel): boolean {
63 return service.telemetryLevel >= level;
64 }
66 > /**
67 > * Replaces `/` and `\` with `|` in model identifiers to prevent the
68 > * telemetry pipeline from redacting them as file paths.
69 > */
70 > export function escapeModelIdForTelemetry(modelId: string | undefined): string | undefined {
71 return modelId?.replace(/[\/\\]/g, '|');
72 }
74 > export interface ITelemetryEndpoint {
75 > id: string;
76 > aiKey: string;
77 > sendErrorTelemetry: boolean;
78 > }
79 >
80 > export const ICustomEndpointTelemetryService = createDecorator<ICustomEndpointTelemetryService>('customEndpointTelemetryService');
81 >
82 > export interface ICustomEndpointTelemetryService {
83 > readonly _serviceBrand: undefined;
84 >
85 > publicLog(endpoint: ITelemetryEndpoint, eventName: string, data?: ITelemetryData): void;
86 > publicLogError(endpoint: ITelemetryEndpoint, errorEventName: string, data?: ITelemetryData): void;
87 > }
88 >
89 > // Keys
90 > export const currentSessionDateStorageKey = 'telemetry.currentSessionDate';
91 > export const firstSessionDateStorageKey = 'telemetry.firstSessionDate';
92 > export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';
93 > export const machineIdKey = 'telemetry.machineId';
94 > export const sqmIdKey = 'telemetry.sqmId';
95 > export const devDeviceIdKey = 'telemetry.devDeviceId';
96 >
97 > // Configuration Keys
98 > export const TELEMETRY_SECTION_ID = 'telemetry';
99 > export const TELEMETRY_SETTING_ID = 'telemetry.telemetryLevel';
100 > export const TELEMETRY_CRASH_REPORTER_SETTING_ID = 'telemetry.enableCrashReporter';
101 > export const TELEMETRY_OLD_SETTING_ID = 'telemetry.enableTelemetry';
102 >
103 > export const enum TelemetryLevel {
104 > NONE = 0,
105 > CRASH = 1,
106 > ERROR = 2,
107 > USAGE = 3
108 > }
109 >
110 > export const enum TelemetryConfiguration {
111 > OFF = 'off',
112 > CRASH = 'crash',
113 > ERROR = 'error',
114 > ON = 'all'
115 > }
116 >
117 > export interface ICommonProperties {
118 > [name: string]: string | boolean | undefined;
119 > }
src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/tokenizer.ts 114 covered LOC · 18 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tokenizer.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 { NotSupportedError } from '../../../../../base/common/errors.js';
7 > import { StandardTokenType, TokenMetadata } from '../../../encodedTokenAttributes.js';
8 > import { IViewLineTokens } from '../../../tokens/lineTokens.js';
9 > import { BracketAstNode, TextAstNode } from './ast.js';
10 > import { BracketTokens, LanguageAgnosticBracketTokens } from './brackets.js';
11 > import { Length, lengthAdd, lengthDiff, lengthGetColumnCountIfZeroLineCount, lengthToObj, lengthZero, toLength } from './length.js';
12 > import { SmallImmutableSet } from './smallImmutableSet.js';
13 >
14 > export interface Tokenizer {
15 > readonly offset: Length;
16 > readonly length: Length;
17 >
18 > read(): Token | null;
19 > peek(): Token | null;
20 > skip(length: Length): void;
21 >
22 > getText(): string;
23 > }
24 >
25 > export const enum TokenKind {
26 > Text = 0,
27 > OpeningBracket = 1,
28 > ClosingBracket = 2,
29 > }
30 >
31 > export type OpeningBracketId = number;
32 >
33 > export class Token {
34 > constructor(
35 readonly length: Length,
36 readonly kind: TokenKind,
49 readonly astNode: BracketAstNode | TextAstNode | undefined,
50 ) { }
51 > } tokenizer.ts
52 >
53 > export interface ITokenizerSource {
54 > getValue(): string;
55 > getLineCount(): number;
56 > getLineLength(lineNumber: number): number;
57 >
58 > tokenization: {
59 > getLineTokens(lineNumber: number): IViewLineTokens;
60 > };
61 > }
62 >
63 > export class TextBufferTokenizer implements Tokenizer {
64 > private readonly textBufferLineCount: number;
65 > private readonly textBufferLastLineLength: number;
66 >
67 > private readonly reader;
68 >
69 > constructor(
70 private readonly textModel: ITokenizerSource,
71 private readonly bracketTokens: LanguageAgnosticBracketTokens
78 this.textBufferLastLineLength = textModel.getLineLength(this.textBufferLineCount);
79 }
81 > private _offset: Length;
82 >
83 > get offset() {
84 return this._offset;
85 }
87 > get length() {
88 return toLength(this.textBufferLineCount - 1, this.textBufferLastLineLength);
89 }
91 > getText() {
92 return this.textModel.getValue();
93 }
95 > skip(length: Length): void {
96 this.didPeek = false;
97 this._offset = lengthAdd(this._offset, length);
99 this.reader.setPosition(obj.lineCount, obj.columnCount);
100 }
101 > tokenizer.ts
102 > private didPeek;
103 > private peeked: Token | null;
104 >
105 > read(): Token | null {
106 let token: Token | null;
107 if (this.peeked) {
116 return token;
117 }
118 > tokenizer.ts
119 > peek(): Token | null {
120 if (!this.didPeek) {
121 this.peeked = this.reader.read();
124 return this.peeked;
125 }
126 > } tokenizer.ts
127 >
128 > /**
129 > * Does not support peek.
130 > */
131 > class NonPeekableTextBufferTokenizer {
132 > private readonly textBufferLineCount: number;
133 > private readonly textBufferLastLineLength: number;
134 >
135 > constructor(private readonly textModel: ITokenizerSource, private readonly bracketTokens: LanguageAgnosticBracketTokens) {
136 this.textBufferLineCount = textModel.getLineCount();
137 this.textBufferLastLineLength = textModel.getLineLength(this.textBufferLineCount);
138 }
139 > tokenizer.ts
140 > private lineIdx = 0;
141 > private line: string | null = null;
142 > private lineCharOffset = 0;
143 > private lineTokens: IViewLineTokens | null = null;
144 > private lineTokenOffset = 0;
145 >
146 > public setPosition(lineIdx: number, column: number): void {
147 // We must not jump into a token!
148 if (lineIdx === this.lineIdx) {
158 this.peekedToken = null;
159 }
160 > tokenizer.ts
161 > /** Must be a zero line token. The end of the document cannot be peeked. */
162 > private peekedToken: Token | null = null;
163 >
164 > public read(): Token | null {
165 if (this.peekedToken) {
166 const token = this.peekedToken;
278 return new Token(length, TokenKind.Text, -1, SmallImmutableSet.getEmpty(), new TextAstNode(length));
279 }
280 > } tokenizer.ts
281 >
282 > export class FastTokenizer implements Tokenizer {
283 > private _offset: Length = lengthZero;
284 > private readonly tokens: readonly Token[];
285 > private idx = 0;
286 >
287 > constructor(private readonly text: string, brackets: BracketTokens) {
288 const regExpStr = brackets.getRegExpStr();
289 const regexp = regExpStr ? new RegExp(regExpStr + '|\n', 'gi') : null;
372 this.tokens = tokens;
373 }
374 > tokenizer.ts
375 > get offset(): Length {
376 return this._offset;
377 }
378 > tokenizer.ts
379 > readonly length: Length;
380 >
381 > read(): Token | null {
382 return this.tokens[this.idx++] || null;
383 }
384 > tokenizer.ts
385 > peek(): Token | null {
386 return this.tokens[this.idx] || null;
387 }
388 > tokenizer.ts
389 > skip(length: Length): void {
390 throw new NotSupportedError();
391 }
392 > tokenizer.ts
393 > getText(): string {
394 return this.text;
395 }
396 > } tokenizer.ts
src/vs/base/common/observableInternal/observables/derivedImpl.ts 112 covered LOC · 23 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- annotations.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 { binarySearch2 } from '../../../../base/common/arrays.js';
7 > import { StringEdit } from '../../core/edits/stringEdit.js';
8 > import { OffsetRange } from '../../core/ranges/offsetRange.js';
9 >
10 > export interface IAnnotation<T> {
11 > range: OffsetRange;
12 > annotation: T;
13 > }
14 >
15 > export interface IAnnotatedString<T> {
16 > /**
17 > * Set annotations for a specific line.
18 > * Annotations should be sorted and non-overlapping.
19 > */
20 > setAnnotations(annotations: AnnotationsUpdate<T>): void;
21 > /**
22 > * Return annotations intersecting with the given offset range.
23 > */
24 > getAnnotationsIntersecting(range: OffsetRange): IAnnotation<T>[];
25 > /**
26 > * Get all the annotations. Method is used for testing.
27 > */
28 > getAllAnnotations(): IAnnotation<T>[];
29 > /**
30 > * Apply a string edit to the annotated string.
31 > * @returns The annotations that were deleted (became empty) as a result of the edit.
32 > */
33 > applyEdit(edit: StringEdit): IAnnotation<T>[];
34 > /**
35 > * Clone the annotated string.
36 > */
37 > clone(): IAnnotatedString<T>;
38 > }
39 >
40 > export class AnnotatedString<T> implements IAnnotatedString<T> {
41 >
42 > /**
43 > * Annotations are non intersecting and contiguous in the array.
44 > */
45 > private _annotations: IAnnotation<T>[] = [];
46 >
47 > constructor(annotations: IAnnotation<T>[] = []) {
48 this._annotations = annotations;
49 }
51 > /**
52 > * Set annotations for a specific range.
53 > * Annotations should be sorted and non-overlapping.
54 > * If the annotation value is undefined, the annotation is removed.
55 > */
56 > public setAnnotations(annotations: AnnotationsUpdate<T>): void {
57 for (const annotation of annotations.annotations) {
58 const startIndex = this._getStartIndexOfIntersectingAnnotation(annotation.range.start);
65 }
66 }
68 > /**
69 > * Returns all annotations that intersect with the given offset range.
70 > */
71 > public getAnnotationsIntersecting(range: OffsetRange): IAnnotation<T>[] {
72 const startIndex = this._getStartIndexOfIntersectingAnnotation(range.start);
73 const endIndexExclusive = this._getEndIndexOfIntersectingAnnotation(range.endExclusive);
74 return this._annotations.slice(startIndex, endIndexExclusive);
75 }
77 > private _getStartIndexOfIntersectingAnnotation(offset: number): number {
78 // Find index to the left of the offset
79 const startIndexWhereToReplace = binarySearch2(this._annotations.length, (index) => {
98 return startIndex;
99 }
101 > private _getEndIndexOfIntersectingAnnotation(offset: number): number {
102 // Find index to the right of the offset
103 const endIndexWhereToReplace = binarySearch2(this._annotations.length, (index) => {
122 return endIndexExclusive;
123 }
125 > /**
126 > * Returns a copy of all annotations.
127 > */
128 > public getAllAnnotations(): IAnnotation<T>[] {
129 return this._annotations.slice();
130 }
132 > /**
133 > * Applies a string edit to the annotated string, updating annotation ranges accordingly.
134 > * @param edit The string edit to apply.
135 > * @returns The annotations that were deleted (became empty) as a result of the edit.
136 > */
137 > public applyEdit(edit: StringEdit): IAnnotation<T>[] {
138 const annotations = this._annotations.slice();
139
226 return deletedAnnotations;
227 }
229 > /**
230 > * Creates a shallow clone of this annotated string.
231 > */
232 > public clone(): IAnnotatedString<T> {
233 return new AnnotatedString<T>(this._annotations.slice());
234 }
235 > } annotations.ts
236 >
237 > export interface IAnnotationUpdate<T> {
238 > range: OffsetRange;
239 > annotation: T | undefined;
240 > }
241 >
242 > type DefinedValue = object | string | number | boolean;
243 >
244 > export type ISerializedAnnotation<TSerializedProperty extends DefinedValue> = {
245 > range: { start: number; endExclusive: number };
246 > annotation: TSerializedProperty | undefined;
247 > };
248 >
249 > export class AnnotationsUpdate<T> {
250 >
251 > public static create<T>(annotations: IAnnotationUpdate<T>[]): AnnotationsUpdate<T> {
252 return new AnnotationsUpdate(annotations);
253 }
255 > private _annotations: IAnnotationUpdate<T>[];
256 >
257 > private constructor(annotations: IAnnotationUpdate<T>[]) {
258 this._annotations = annotations;
259 }
261 > get annotations(): IAnnotationUpdate<T>[] {
262 return this._annotations;
263 }
265 > public rebase(edit: StringEdit): void {
266 const annotatedString = new AnnotatedString<T | undefined>(this._annotations);
267 annotatedString.applyEdit(edit);
268 this._annotations = annotatedString.getAllAnnotations();
269 }
271 > public serialize<TSerializedProperty extends DefinedValue>(serializingFunc: (annotation: T) => TSerializedProperty): ISerializedAnnotation<TSerializedProperty>[] {
272 return this._annotations.map(annotation => {
273 const range = { start: annotation.range.start, endExclusive: annotation.range.endExclusive };
278 });
279 }
281 > static deserialize<T, TSerializedProperty extends DefinedValue>(serializedAnnotations: ISerializedAnnotation<TSerializedProperty>[], deserializingFunc: (annotation: TSerializedProperty) => T): AnnotationsUpdate<T> {
282 const annotations: IAnnotationUpdate<T>[] = serializedAnnotations.map(serializedAnnotation => {
283 const range = new OffsetRange(serializedAnnotation.range.start, serializedAnnotation.range.endExclusive);
289 return new AnnotationsUpdate(annotations);
290 }
291 > } annotations.ts
src/vs/platform/instantiation/common/instantiationService.ts 109 covered LOC · 21 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- instantiationService.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 { GlobalIdleValue } from '../../../base/common/async.js';
7 > import { Event } from '../../../base/common/event.js';
8 > import { illegalState } from '../../../base/common/errors.js';
9 > import { DisposableStore, dispose, IDisposable, isDisposable, toDisposable } from '../../../base/common/lifecycle.js';
10 > import { SyncDescriptor, SyncDescriptor0 } from './descriptors.js';
11 > import { Graph } from './graph.js';
12 > import { GetLeadingNonServiceArgs, IInstantiationService, ServiceIdentifier, ServicesAccessor, _util } from './instantiation.js';
13 > import { ServiceCollection } from './serviceCollection.js';
14 > import { LinkedList } from '../../../base/common/linkedList.js';
15 >
16 > // TRACING
17 > const _enableAllTracing = false
18 > // || "TRUE" // DO NOT CHECK IN!
19 > ;
20 >
21 > class CyclicDependencyError extends Error {
22 > constructor(graph: Graph<any>) {
23 super('cyclic dependency between services');
24 this.message = graph.findCycleSlow() ?? `UNABLE to detect cycle, dumping graph: \n${graph.toString()}`;
25 }
27 >
28 > export class InstantiationService implements IInstantiationService {
29 >
30 > declare readonly _serviceBrand: undefined;
31 >
32 > readonly _globalGraph?: Graph<string>;
33 > private _globalGraphImplicitDependency?: string;
34 >
35 > private _isDisposed = false;
36 > private readonly _servicesToMaybeDispose = new Set<any>();
37 > private readonly _children = new Set<InstantiationService>();
38 >
39 > constructor(
40 private readonly _services: ServiceCollection = new ServiceCollection(),
41 private readonly _strict: boolean = false,
47 this._globalGraph = _enableTracing ? _parent?._globalGraph ?? new Graph(e => e) : undefined;
48 }
50 > dispose(): void {
51 if (!this._isDisposed) {
52 this._isDisposed = true;
64 }
65 }
67 > private _throwIfDisposed(): void {
68 if (this._isDisposed) {
69 throw new Error('InstantiationService has been disposed');
70 }
71 }
73 > createChild(services: ServiceCollection, store?: DisposableStore): IInstantiationService {
74 this._throwIfDisposed();
75
86 return result;
87 }
89 > invokeFunction<R, TS extends any[] = []>(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R {
90 this._throwIfDisposed();
91
113 }
114 }
116 > createInstance<T>(descriptor: SyncDescriptor0<T>): T;
117 > createInstance<Ctor extends new (...args: any[]) => unknown, R extends InstanceType<Ctor>>(ctor: Ctor, ...args: GetLeadingNonServiceArgs<ConstructorParameters<Ctor>>): R;
118 > createInstance(ctorOrDescriptor: any | SyncDescriptor<any>, ...rest: unknown[]): unknown {
119 this._throwIfDisposed();
120
131 return result;
132 }
134 > private _createInstance<T>(ctor: any, args: unknown[] = [], _trace: Trace): T {
135
136 // arguments defined by service decorators
162 return Reflect.construct<any, T>(ctor, args.concat(serviceArgs));
163 }
165 > private _setCreatedServiceInstance<T>(id: ServiceIdentifier<T>, instance: T): void {
166 if (this._services.get(id) instanceof SyncDescriptor) {
167 this._services.set(id, instance);
172 }
173 }
175 > private _getServiceInstanceOrDescriptor<T>(id: ServiceIdentifier<T>): T | SyncDescriptor<T> {
176 const instanceOrDesc = this._services.get(id);
177 if (!instanceOrDesc && this._parent) {
181 }
182 }
184 > protected _getOrCreateServiceInstance<T>(id: ServiceIdentifier<T>, _trace: Trace): T {
185 if (this._globalGraph && this._globalGraphImplicitDependency) {
186 this._globalGraph.insertEdge(this._globalGraphImplicitDependency, String(id));
194 }
195 }
197 > private readonly _activeInstantiations = new Set<ServiceIdentifier<any>>();
198 >
199 >
200 > private _safeCreateAndCacheServiceInstance<T>(id: ServiceIdentifier<T>, desc: SyncDescriptor<T>, _trace: Trace): T {
201 if (this._activeInstantiations.has(id)) {
202 throw new Error(`illegal state - RECURSIVELY instantiating service '${id}'`);
209 }
210 }
212 > private _createAndCacheServiceInstance<T>(id: ServiceIdentifier<T>, desc: SyncDescriptor<T>, _trace: Trace): T {
213
214 type Triple = { id: ServiceIdentifier<any>; desc: SyncDescriptor<any>; _trace: Trace };
279 return <T>this._getServiceInstanceOrDescriptor(id);
280 }
282 > private _createServiceInstanceWithOwner<T>(id: ServiceIdentifier<T>, ctor: any, args: unknown[] = [], supportsDelayedInstantiation: boolean, _trace: Trace): T {
283 if (this._services.get(id) instanceof SyncDescriptor) {
284 return this._createServiceInstance(id, ctor, args, supportsDelayedInstantiation, _trace, this._servicesToMaybeDispose);
289 }
290 }
292 > private _createServiceInstance<T>(id: ServiceIdentifier<T>, ctor: any, args: unknown[] = [], supportsDelayedInstantiation: boolean, _trace: Trace, disposeBucket: Set<any>): T {
293 if (!supportsDelayedInstantiation) {
294 // eager instantiation
384 }
385 }
387 > private _throwIfStrict(msg: string, printWarning: boolean): void {
388 if (printWarning) {
389 console.warn(msg);
393 }
394 }
396 >
397 > //#region -- tracing ---
398 >
399 > const enum TraceType {
400 > None = 0,
401 > Creation = 1,
402 > Invocation = 2,
403 > Branch = 3,
404 > }
405 >
406 > export class Trace {
407 >
408 > static all = new Set<string>();
409 >
410 > private static readonly _None = new class extends Trace {
411 > constructor() { super(TraceType.None, null); }
412 > override stop() { }
413 > override branch() { return this; }
414 > };
415 >
416 > static traceInvocation(_enableTracing: boolean, ctor: any): Trace {
417 return !_enableTracing ? Trace._None : new Trace(TraceType.Invocation, ctor.name || new Error().stack!.split('\n').slice(3, 4).join('\n'));
418 }
420 > static traceCreation(_enableTracing: boolean, ctor: any): Trace {
421 return !_enableTracing ? Trace._None : new Trace(TraceType.Creation, ctor.name);
422 }
424 > private static _totals: number = 0;
425 > private readonly _start: number = Date.now();
426 > private readonly _dep: [ServiceIdentifier<any>, boolean, Trace?][] = [];
427 >
428 > private constructor(
429 > readonly type: TraceType,
430 > readonly name: string | null
431 > ) { }
432 >
433 > branch(id: ServiceIdentifier<any>, first: boolean): Trace {
434 const child = new Trace(TraceType.Branch, id.toString());
435 this._dep.push([id, first, child]);
436 return child;
437 }
439 > stop() {
440 const dur = Date.now() - this._start;
441 Trace._totals += dur;
src/vs/base/common/equals.ts 108 covered LOC · 14 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelEditSource.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 { prefixedUuid } from '../../base/common/uuid.js';
8 > import { LineEdit } from './core/edits/lineEdit.js';
9 > import { BaseStringEdit } from './core/edits/stringEdit.js';
10 > import { StringText } from './core/text/abstractText.js';
11 > import { TextLength } from './core/text/textLength.js';
12 > import { ProviderId, VersionedExtensionId } from './languages.js';
13 >
14 > const privateSymbol = Symbol('TextModelEditSource');
15 >
16 > export class TextModelEditSource {
17 > constructor(
18 public readonly metadata: ITextModelEditSourceMetadata,
19 _privateCtorGuard: typeof privateSymbol,
20 ) { }
22 > public toString(): string {
23 return `${this.metadata.source}`;
24 }
26 > public getType(): string {
27 const metadata = this.metadata;
28 switch (metadata.source) {
37 }
38 }
40 > /**
41 > * Converts the metadata to a key string.
42 > * Only includes properties/values that have `level` many `$` prefixes or less.
43 > */
44 > public toKey(level: number, filter: { [TKey in ITextModelEditSourceMetadataKeys]?: boolean } = {}): string {
45 const metadata = this.metadata;
46 const keys = Object.entries(metadata).filter(([key, value]) => {
55 return keys.join('-');
56 }
58 > public get props(): Record<ITextModelEditSourceMetadataKeys, string | undefined> {
59 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
60 return this.metadata as any;
61 }
63 >
64 > type TextModelEditSourceT<T> = TextModelEditSource & {
65 > metadataT: T;
66 > };
67 >
68 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
69 function createEditSource<T extends Record<string, any>>(metadata: T): TextModelEditSourceT<T> {
70 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
71 return new TextModelEditSource(metadata as any, privateSymbol) as any;
72 }
74 > export function isAiEdit(source: TextModelEditSource): boolean {
75 switch (source.metadata.source) {
76 case 'inlineCompletionAccept':
82 return false;
83 }
85 > export function isUserEdit(source: TextModelEditSource): boolean {
86 switch (source.metadata.source) {
87 case 'cursor':
90 return false;
91 }
93 > export const EditSources = {
94 > unknown(data: { name?: string | null }) {
95 return createEditSource({
96 source: 'unknown',
98 } as const);
99 },
101 > rename: (oldName: string | undefined, newName: string) => createEditSource({ source: 'rename', $$$oldName: oldName, $$$newName: newName } as const),
102 >
103 > chatApplyEdits(data: {
104 modelId: string | undefined;
105 sessionId: string | undefined;
122 } as const);
123 },
125 > chatUndoEdits: () => createEditSource({ source: 'Chat.undoEdits' } as const),
126 > chatReset: () => createEditSource({ source: 'Chat.reset' } as const),
127 >
128 > inlineCompletionAccept(data: { nes: boolean; requestUuid: string; languageId: string; providerId?: ProviderId; correlationId: string | undefined }) {
129 return createEditSource({
130 source: 'inlineCompletionAccept',
136 } as const);
137 },
139 > inlineCompletionPartialAccept(data: { nes: boolean; requestUuid: string; languageId: string; providerId?: ProviderId; correlationId: string | undefined; type: 'word' | 'line' }) {
140 return createEditSource({
141 source: 'inlineCompletionPartialAccept',
148 } as const);
149 },
151 > inlineChatApplyEdit(data: { modelId: string | undefined; requestId: string | undefined; sessionId: string | undefined; languageId: string; extensionId: VersionedExtensionId | undefined }) {
152 return createEditSource({
153 source: 'inlineChat.applyEdits',
160 } as const);
161 },
163 > reloadFromDisk: () => createEditSource({ source: 'reloadFromDisk' } as const),
164 >
165 > cursor(data: { kind: 'compositionType' | 'compositionEnd' | 'type' | 'paste' | 'cut' | 'executeCommands' | 'executeCommand'; detailedSource?: string | null }) {
166 return createEditSource({
167 source: 'cursor',
170 } as const);
171 },
173 > setValue: () => createEditSource({ source: 'setValue' } as const),
174 > eolChange: () => createEditSource({ source: 'eolChange' } as const),
175 > applyEdits: () => createEditSource({ source: 'applyEdits' } as const),
176 > snippet: () => createEditSource({ source: 'snippet' } as const),
177 > suggest: (data: { providerId: ProviderId | undefined }) => createEditSource({ source: 'suggest', ...toProperties(data.providerId) } as const),
178 >
179 > codeAction: (data: { kind: string | undefined; providerId: ProviderId | undefined }) => createEditSource({ source: 'codeAction', $kind: data.kind, ...toProperties(data.providerId) } as const)
180 > };
181 >
182 function toProperties(version: ProviderId | undefined) {
183 if (!version) {
190 };
191 }
193 > type Values<T> = T[keyof T];
194 > export type ITextModelEditSourceMetadata = Values<{ [TKey in keyof typeof EditSources]: ReturnType<typeof EditSources[TKey]>['metadataT'] }>;
195 > type ITextModelEditSourceMetadataKeys = Values<{ [TKey in keyof typeof EditSources]: keyof ReturnType<typeof EditSources[TKey]>['metadataT'] }>;
196 >
197 >
198 function avoidPathRedaction(str: string | undefined): string | undefined {
199 if (str === undefined) {
203 return str.replaceAll('/', '|');
204 }
206 >
207 > export class EditDeltaInfo {
208 > public static fromText(text: string): EditDeltaInfo {
209 > const linesAdded = TextLength.ofText(text).lineCount;
210 > const charsAdded = text.length;
211 > return new EditDeltaInfo(linesAdded, 0, charsAdded, 0);
212 > }
213 >
214 > /** @internal */
215 > public static fromEdit(edit: BaseStringEdit, originalString: StringText): EditDeltaInfo {
216 const lineEdit = LineEdit.fromStringEdit(edit, originalString);
217 const linesAdded = sumBy(lineEdit.replacements, r => r.newLines.length);
221 return new EditDeltaInfo(linesAdded, linesRemoved, charsAdded, charsRemoved);
222 }
224 > public static tryCreate(
225 linesAdded: number | undefined,
226 linesRemoved: number | undefined,
233 return new EditDeltaInfo(linesAdded, linesRemoved, charsAdded, charsRemoved);
234 }
236 > constructor(
237 public readonly linesAdded: number,
238 public readonly linesRemoved: number,
240 public readonly charsRemoved: number
241 ) { }
243 >
244 >
245 > /**
246 > * This is an opaque serializable type that represents a unique identity for an edit.
247 > */
248 > export interface EditSuggestionId {
249 > readonly _brand: 'EditIdentity';
250 > }
251 >
252 > export namespace EditSuggestionId {
253 > /**
254 > * Use AiEditTelemetryServiceImpl to create a new id!
255 > */
256 > export function newId(genPrefixedUuid?: (ns: string) => string): EditSuggestionId {
257 const id = genPrefixedUuid ? genPrefixedUuid('sgt') : prefixedUuid('sgt');
258 return toEditIdentity(id);
259 }
261 >
262 function toEditIdentity(id: string): EditSuggestionId {
263 return id as unknown as EditSuggestionId;
src/vs/editor/common/core/editorColorRegistry.ts 106 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editorColorRegistry.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 > import { Color, RGBA } from '../../../base/common/color.js';
8 > import { activeContrastBorder, editorBackground, registerColor, editorWarningForeground, editorInfoForeground, editorWarningBorder, editorInfoBorder, contrastBorder, editorFindMatchHighlight, editorWarningBackground } from '../../../platform/theme/common/colorRegistry.js';
9 > import { registerThemingParticipant } from '../../../platform/theme/common/themeService.js';
10 >
11 > /**
12 > * Definition of the editor colors
13 > */
14 > export const editorLineHighlight = registerColor('editor.lineHighlightBackground', null, nls.localize('lineHighlight', 'Background color for the highlight of line at the cursor position.'));
15 > export const editorInactiveLineHighlight = registerColor('editor.inactiveLineHighlightBackground', editorLineHighlight, nls.localize('inactiveLineHighlight', 'Background color for the highlight of line at the cursor position when the editor is not focused.'));
16 > export const editorLineHighlightBorder = registerColor('editor.lineHighlightBorder', { dark: '#282828', light: '#eeeeee', hcDark: '#f38518', hcLight: contrastBorder }, nls.localize('lineHighlightBorderBox', 'Background color for the border around the line at the cursor position.'));
17 > export const editorRangeHighlight = registerColor('editor.rangeHighlightBackground', { dark: '#ffffff0b', light: '#fdff0033', hcDark: null, hcLight: null }, nls.localize('rangeHighlight', 'Background color of highlighted ranges, like by quick open and find features. The color must not be opaque so as not to hide underlying decorations.'), true);
18 > export const editorRangeHighlightBorder = registerColor('editor.rangeHighlightBorder', { dark: null, light: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('rangeHighlightBorder', 'Background color of the border around highlighted ranges.'));
19 > export const editorSymbolHighlight = registerColor('editor.symbolHighlightBackground', { dark: editorFindMatchHighlight, light: editorFindMatchHighlight, hcDark: null, hcLight: null }, nls.localize('symbolHighlight', 'Background color of highlighted symbol, like for go to definition or go next/previous symbol. The color must not be opaque so as not to hide underlying decorations.'), true);
20 > export const editorSymbolHighlightBorder = registerColor('editor.symbolHighlightBorder', { dark: null, light: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('symbolHighlightBorder', 'Background color of the border around highlighted symbols.'));
21 >
22 > export const editorCursorForeground = registerColor('editorCursor.foreground', { dark: '#AEAFAD', light: Color.black, hcDark: Color.white, hcLight: '#0F4A85' }, nls.localize('caret', 'Color of the editor cursor.'));
23 > export const editorCursorBackground = registerColor('editorCursor.background', null, nls.localize('editorCursorBackground', 'The background color of the editor cursor. Allows customizing the color of a character overlapped by a block cursor.'));
24 > export const editorMultiCursorPrimaryForeground = registerColor('editorMultiCursor.primary.foreground', editorCursorForeground, nls.localize('editorMultiCursorPrimaryForeground', 'Color of the primary editor cursor when multiple cursors are present.'));
25 > export const editorMultiCursorPrimaryBackground = registerColor('editorMultiCursor.primary.background', editorCursorBackground, nls.localize('editorMultiCursorPrimaryBackground', 'The background color of the primary editor cursor when multiple cursors are present. Allows customizing the color of a character overlapped by a block cursor.'));
26 > export const editorMultiCursorSecondaryForeground = registerColor('editorMultiCursor.secondary.foreground', editorCursorForeground, nls.localize('editorMultiCursorSecondaryForeground', 'Color of secondary editor cursors when multiple cursors are present.'));
27 > export const editorMultiCursorSecondaryBackground = registerColor('editorMultiCursor.secondary.background', editorCursorBackground, nls.localize('editorMultiCursorSecondaryBackground', 'The background color of secondary editor cursors when multiple cursors are present. Allows customizing the color of a character overlapped by a block cursor.'));
28 > export const editorWhitespaces = registerColor('editorWhitespace.foreground', { dark: '#e3e4e229', light: '#33333333', hcDark: '#e3e4e229', hcLight: '#CCCCCC' }, nls.localize('editorWhitespaces', 'Color of whitespace characters in the editor.'));
29 > export const editorLineNumbers = registerColor('editorLineNumber.foreground', { dark: '#858585', light: '#237893', hcDark: Color.white, hcLight: '#292929' }, nls.localize('editorLineNumbers', 'Color of editor line numbers.'));
30 >
31 > export const deprecatedEditorIndentGuides = registerColor('editorIndentGuide.background', editorWhitespaces, nls.localize('editorIndentGuides', 'Color of the editor indentation guides.'), false, nls.localize('deprecatedEditorIndentGuides', '\'editorIndentGuide.background\' is deprecated. Use \'editorIndentGuide.background1\' instead.'));
32 > export const deprecatedEditorActiveIndentGuides = registerColor('editorIndentGuide.activeBackground', editorWhitespaces, nls.localize('editorActiveIndentGuide', 'Color of the active editor indentation guides.'), false, nls.localize('deprecatedEditorActiveIndentGuide', '\'editorIndentGuide.activeBackground\' is deprecated. Use \'editorIndentGuide.activeBackground1\' instead.'));
33 >
34 > export const editorIndentGuide1 = registerColor('editorIndentGuide.background1', deprecatedEditorIndentGuides, nls.localize('editorIndentGuides1', 'Color of the editor indentation guides (1).'));
35 > export const editorIndentGuide2 = registerColor('editorIndentGuide.background2', '#00000000', nls.localize('editorIndentGuides2', 'Color of the editor indentation guides (2).'));
36 > export const editorIndentGuide3 = registerColor('editorIndentGuide.background3', '#00000000', nls.localize('editorIndentGuides3', 'Color of the editor indentation guides (3).'));
37 > export const editorIndentGuide4 = registerColor('editorIndentGuide.background4', '#00000000', nls.localize('editorIndentGuides4', 'Color of the editor indentation guides (4).'));
38 > export const editorIndentGuide5 = registerColor('editorIndentGuide.background5', '#00000000', nls.localize('editorIndentGuides5', 'Color of the editor indentation guides (5).'));
39 > export const editorIndentGuide6 = registerColor('editorIndentGuide.background6', '#00000000', nls.localize('editorIndentGuides6', 'Color of the editor indentation guides (6).'));
40 >
41 > export const editorActiveIndentGuide1 = registerColor('editorIndentGuide.activeBackground1', deprecatedEditorActiveIndentGuides, nls.localize('editorActiveIndentGuide1', 'Color of the active editor indentation guides (1).'));
42 > export const editorActiveIndentGuide2 = registerColor('editorIndentGuide.activeBackground2', '#00000000', nls.localize('editorActiveIndentGuide2', 'Color of the active editor indentation guides (2).'));
43 > export const editorActiveIndentGuide3 = registerColor('editorIndentGuide.activeBackground3', '#00000000', nls.localize('editorActiveIndentGuide3', 'Color of the active editor indentation guides (3).'));
44 > export const editorActiveIndentGuide4 = registerColor('editorIndentGuide.activeBackground4', '#00000000', nls.localize('editorActiveIndentGuide4', 'Color of the active editor indentation guides (4).'));
45 > export const editorActiveIndentGuide5 = registerColor('editorIndentGuide.activeBackground5', '#00000000', nls.localize('editorActiveIndentGuide5', 'Color of the active editor indentation guides (5).'));
46 > export const editorActiveIndentGuide6 = registerColor('editorIndentGuide.activeBackground6', '#00000000', nls.localize('editorActiveIndentGuide6', 'Color of the active editor indentation guides (6).'));
47 >
48 > const deprecatedEditorActiveLineNumber = registerColor('editorActiveLineNumber.foreground', { dark: '#c6c6c6', light: '#0B216F', hcDark: activeContrastBorder, hcLight: activeContrastBorder }, nls.localize('editorActiveLineNumber', 'Color of editor active line number'), false, nls.localize('deprecatedEditorActiveLineNumber', 'Id is deprecated. Use \'editorLineNumber.activeForeground\' instead.'));
49 > export const editorActiveLineNumber = registerColor('editorLineNumber.activeForeground', deprecatedEditorActiveLineNumber, nls.localize('editorActiveLineNumber', 'Color of editor active line number'));
50 > export const editorDimmedLineNumber = registerColor('editorLineNumber.dimmedForeground', null, nls.localize('editorDimmedLineNumber', 'Color of the final editor line when editor.renderFinalNewline is set to dimmed.'));
51 >
52 > export const editorRuler = registerColor('editorRuler.foreground', { dark: '#5A5A5A', light: Color.lightgrey, hcDark: Color.white, hcLight: '#292929' }, nls.localize('editorRuler', 'Color of the editor rulers.'));
53 >
54 > export const editorCodeLensForeground = registerColor('editorCodeLens.foreground', { dark: '#999999', light: '#919191', hcDark: '#999999', hcLight: '#292929' }, nls.localize('editorCodeLensForeground', 'Foreground color of editor CodeLens'));
55 >
56 > export const editorBracketMatchBackground = registerColor('editorBracketMatch.background', { dark: '#0064001a', light: '#0064001a', hcDark: '#0064001a', hcLight: '#0000' }, nls.localize('editorBracketMatchBackground', 'Background color behind matching brackets'));
57 > export const editorBracketMatchBorder = registerColor('editorBracketMatch.border', { dark: '#888', light: '#B9B9B9', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('editorBracketMatchBorder', 'Color for matching brackets boxes'));
58 > export const editorBracketMatchForeground = registerColor('editorBracketMatch.foreground', null, nls.localize('editorBracketMatchForeground', 'Foreground color for matching brackets'));
59 >
60 > export const editorOverviewRulerBorder = registerColor('editorOverviewRuler.border', { dark: '#7f7f7f4d', light: '#7f7f7f4d', hcDark: '#7f7f7f4d', hcLight: '#666666' }, nls.localize('editorOverviewRulerBorder', 'Color of the overview ruler border.'));
61 > export const editorOverviewRulerBackground = registerColor('editorOverviewRuler.background', null, nls.localize('editorOverviewRulerBackground', 'Background color of the editor overview ruler.'));
62 >
63 > export const editorGutter = registerColor('editorGutter.background', editorBackground, nls.localize('editorGutter', 'Background color of the editor gutter. The gutter contains the glyph margins and the line numbers.'));
64 >
65 > export const editorUnnecessaryCodeBorder = registerColor('editorUnnecessaryCode.border', { dark: null, light: null, hcDark: Color.fromHex('#fff').transparent(0.8), hcLight: contrastBorder }, nls.localize('unnecessaryCodeBorder', 'Border color of unnecessary (unused) source code in the editor.'));
66 > export const editorUnnecessaryCodeOpacity = registerColor('editorUnnecessaryCode.opacity', { dark: Color.fromHex('#000a'), light: Color.fromHex('#0007'), hcDark: null, hcLight: null }, nls.localize('unnecessaryCodeOpacity', 'Opacity of unnecessary (unused) source code in the editor. For example, "#000000c0" will render the code with 75% opacity. For high contrast themes, use the \'editorUnnecessaryCode.border\' theme color to underline unnecessary code instead of fading it out.'));
67 >
68 > export const ghostTextBorder = registerColor('editorGhostText.border', { dark: null, light: null, hcDark: Color.fromHex('#fff').transparent(0.8), hcLight: Color.fromHex('#292929').transparent(0.8) }, nls.localize('editorGhostTextBorder', 'Border color of ghost text in the editor.'));
69 > export const ghostTextForeground = registerColor('editorGhostText.foreground', { dark: Color.fromHex('#ffffff56'), light: Color.fromHex('#0007'), hcDark: null, hcLight: null }, nls.localize('editorGhostTextForeground', 'Foreground color of the ghost text in the editor.'));
70 > export const ghostTextBackground = registerColor('editorGhostText.background', null, nls.localize('editorGhostTextBackground', 'Background color of the ghost text in the editor.'));
71 >
72 > const rulerRangeDefault = new Color(new RGBA(0, 122, 204, 0.6));
73 > export const overviewRulerRangeHighlight = registerColor('editorOverviewRuler.rangeHighlightForeground', rulerRangeDefault, nls.localize('overviewRulerRangeHighlight', 'Overview ruler marker color for range highlights. The color must not be opaque so as not to hide underlying decorations.'), true);
74 > export const overviewRulerError = registerColor('editorOverviewRuler.errorForeground', { dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hcDark: new Color(new RGBA(255, 50, 50, 1)), hcLight: '#B5200D' }, nls.localize('overviewRuleError', 'Overview ruler marker color for errors.'));
75 > export const overviewRulerWarning = registerColor('editorOverviewRuler.warningForeground', { dark: editorWarningForeground, light: editorWarningForeground, hcDark: editorWarningBorder, hcLight: editorWarningBorder }, nls.localize('overviewRuleWarning', 'Overview ruler marker color for warnings.'));
76 > export const overviewRulerInfo = registerColor('editorOverviewRuler.infoForeground', { dark: editorInfoForeground, light: editorInfoForeground, hcDark: editorInfoBorder, hcLight: editorInfoBorder }, nls.localize('overviewRuleInfo', 'Overview ruler marker color for infos.'));
77 >
78 > export const editorBracketHighlightingForeground1 = registerColor('editorBracketHighlight.foreground1', { dark: '#FFD700', light: '#0431FAFF', hcDark: '#FFD700', hcLight: '#0431FAFF' }, nls.localize('editorBracketHighlightForeground1', 'Foreground color of brackets (1). Requires enabling bracket pair colorization.'));
79 > export const editorBracketHighlightingForeground2 = registerColor('editorBracketHighlight.foreground2', { dark: '#DA70D6', light: '#319331FF', hcDark: '#DA70D6', hcLight: '#319331FF' }, nls.localize('editorBracketHighlightForeground2', 'Foreground color of brackets (2). Requires enabling bracket pair colorization.'));
80 > export const editorBracketHighlightingForeground3 = registerColor('editorBracketHighlight.foreground3', { dark: '#179FFF', light: '#7B3814FF', hcDark: '#87CEFA', hcLight: '#7B3814FF' }, nls.localize('editorBracketHighlightForeground3', 'Foreground color of brackets (3). Requires enabling bracket pair colorization.'));
81 > export const editorBracketHighlightingForeground4 = registerColor('editorBracketHighlight.foreground4', '#00000000', nls.localize('editorBracketHighlightForeground4', 'Foreground color of brackets (4). Requires enabling bracket pair colorization.'));
82 > export const editorBracketHighlightingForeground5 = registerColor('editorBracketHighlight.foreground5', '#00000000', nls.localize('editorBracketHighlightForeground5', 'Foreground color of brackets (5). Requires enabling bracket pair colorization.'));
83 > export const editorBracketHighlightingForeground6 = registerColor('editorBracketHighlight.foreground6', '#00000000', nls.localize('editorBracketHighlightForeground6', 'Foreground color of brackets (6). Requires enabling bracket pair colorization.'));
84 >
85 > export const editorBracketHighlightingUnexpectedBracketForeground = registerColor('editorBracketHighlight.unexpectedBracket.foreground', { dark: new Color(new RGBA(255, 18, 18, 0.8)), light: new Color(new RGBA(255, 18, 18, 0.8)), hcDark: new Color(new RGBA(255, 50, 50, 1)), hcLight: '#B5200D' }, nls.localize('editorBracketHighlightUnexpectedBracketForeground', 'Foreground color of unexpected brackets.'));
86 >
87 > export const editorBracketPairGuideBackground1 = registerColor('editorBracketPairGuide.background1', '#00000000', nls.localize('editorBracketPairGuide.background1', 'Background color of inactive bracket pair guides (1). Requires enabling bracket pair guides.'));
88 > export const editorBracketPairGuideBackground2 = registerColor('editorBracketPairGuide.background2', '#00000000', nls.localize('editorBracketPairGuide.background2', 'Background color of inactive bracket pair guides (2). Requires enabling bracket pair guides.'));
89 > export const editorBracketPairGuideBackground3 = registerColor('editorBracketPairGuide.background3', '#00000000', nls.localize('editorBracketPairGuide.background3', 'Background color of inactive bracket pair guides (3). Requires enabling bracket pair guides.'));
90 > export const editorBracketPairGuideBackground4 = registerColor('editorBracketPairGuide.background4', '#00000000', nls.localize('editorBracketPairGuide.background4', 'Background color of inactive bracket pair guides (4). Requires enabling bracket pair guides.'));
91 > export const editorBracketPairGuideBackground5 = registerColor('editorBracketPairGuide.background5', '#00000000', nls.localize('editorBracketPairGuide.background5', 'Background color of inactive bracket pair guides (5). Requires enabling bracket pair guides.'));
92 > export const editorBracketPairGuideBackground6 = registerColor('editorBracketPairGuide.background6', '#00000000', nls.localize('editorBracketPairGuide.background6', 'Background color of inactive bracket pair guides (6). Requires enabling bracket pair guides.'));
93 >
94 > export const editorBracketPairGuideActiveBackground1 = registerColor('editorBracketPairGuide.activeBackground1', '#00000000', nls.localize('editorBracketPairGuide.activeBackground1', 'Background color of active bracket pair guides (1). Requires enabling bracket pair guides.'));
95 > export const editorBracketPairGuideActiveBackground2 = registerColor('editorBracketPairGuide.activeBackground2', '#00000000', nls.localize('editorBracketPairGuide.activeBackground2', 'Background color of active bracket pair guides (2). Requires enabling bracket pair guides.'));
96 > export const editorBracketPairGuideActiveBackground3 = registerColor('editorBracketPairGuide.activeBackground3', '#00000000', nls.localize('editorBracketPairGuide.activeBackground3', 'Background color of active bracket pair guides (3). Requires enabling bracket pair guides.'));
97 > export const editorBracketPairGuideActiveBackground4 = registerColor('editorBracketPairGuide.activeBackground4', '#00000000', nls.localize('editorBracketPairGuide.activeBackground4', 'Background color of active bracket pair guides (4). Requires enabling bracket pair guides.'));
98 > export const editorBracketPairGuideActiveBackground5 = registerColor('editorBracketPairGuide.activeBackground5', '#00000000', nls.localize('editorBracketPairGuide.activeBackground5', 'Background color of active bracket pair guides (5). Requires enabling bracket pair guides.'));
99 > export const editorBracketPairGuideActiveBackground6 = registerColor('editorBracketPairGuide.activeBackground6', '#00000000', nls.localize('editorBracketPairGuide.activeBackground6', 'Background color of active bracket pair guides (6). Requires enabling bracket pair guides.'));
100 >
101 > export const editorUnicodeHighlightBorder = registerColor('editorUnicodeHighlight.border', editorWarningForeground, nls.localize('editorUnicodeHighlight.border', 'Border color used to highlight unicode characters.'));
102 > export const editorUnicodeHighlightBackground = registerColor('editorUnicodeHighlight.background', editorWarningBackground, nls.localize('editorUnicodeHighlight.background', 'Background color used to highlight unicode characters.'));
103 >
104 >
105 > // contains all color rules that used to defined in editor/browser/widget/editor.css
106 > registerThemingParticipant((theme, collector) => {
107 const background = theme.getColor(editorBackground);
108 const lineHighlight = theme.getColor(editorLineHighlight);
src/vs/base/common/observableInternal/observables/baseObservable.ts 104 covered LOC · 17 ranges

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languagesRegistry.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 '../../../base/common/event.js';
7 > import { Disposable, IDisposable } from '../../../base/common/lifecycle.js';
8 > import { compareIgnoreCase, regExpLeadsToEndlessLoop } from '../../../base/common/strings.js';
9 > import { clearPlatformLanguageAssociations, getLanguageIds, registerPlatformLanguageAssociation } from './languagesAssociations.js';
10 > import { URI } from '../../../base/common/uri.js';
11 > import { ILanguageIdCodec } from '../languages.js';
12 > import { LanguageId } from '../encodedTokenAttributes.js';
13 > import { ModesRegistry, PLAINTEXT_LANGUAGE_ID } from '../languages/modesRegistry.js';
14 > import { ILanguageExtensionPoint, ILanguageNameIdPair, ILanguageIcon } from '../languages/language.js';
15 > import { Extensions, IConfigurationRegistry } from '../../../platform/configuration/common/configurationRegistry.js';
16 > import { Registry } from '../../../platform/registry/common/platform.js';
17 >
18 > const hasOwnProperty = Object.prototype.hasOwnProperty;
19 > const NULL_LANGUAGE_ID = 'vs.editor.nullLanguage';
20 >
21 > interface IResolvedLanguage {
22 > identifier: string;
23 > name: string | null;
24 > mimetypes: string[];
25 > aliases: string[];
26 > extensions: string[];
27 > filenames: string[];
28 > configurationFiles: URI[];
29 > icons: ILanguageIcon[];
30 > }
31 >
32 > export class LanguageIdCodec implements ILanguageIdCodec {
33 >
34 > private _nextLanguageId: number;
35 > private readonly _languageIdToLanguage: string[] = [];
36 > private readonly _languageToLanguageId = new Map<string, number>();
37 >
38 > constructor() {
39 this._register(NULL_LANGUAGE_ID, LanguageId.Null);
40 this._register(PLAINTEXT_LANGUAGE_ID, LanguageId.PlainText);
41 this._nextLanguageId = 2;
42 }
44 > private _register(language: string, languageId: LanguageId): void {
45 this._languageIdToLanguage[languageId] = language;
46 this._languageToLanguageId.set(language, languageId);
47 }
49 > public register(language: string): void {
50 if (this._languageToLanguageId.has(language)) {
51 return;
54 this._register(language, languageId);
55 }
57 > public encodeLanguageId(languageId: string): LanguageId {
58 return this._languageToLanguageId.get(languageId) || LanguageId.Null;
59 }
61 > public decodeLanguageId(languageId: LanguageId): string {
62 return this._languageIdToLanguage[languageId] || NULL_LANGUAGE_ID;
63 }
65 >
66 > export class LanguagesRegistry extends Disposable {
67 >
68 > static instanceCount = 0;
69 >
70 > private readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
71 > public readonly onDidChange: Event<void> = this._onDidChange.event;
72 >
73 > private readonly _warnOnOverwrite: boolean;
74 > public readonly languageIdCodec: LanguageIdCodec;
75 > private _dynamicLanguages: ILanguageExtensionPoint[];
76 > private _languages: { [id: string]: IResolvedLanguage };
77 > private _mimeTypesMap: { [mimeType: string]: string };
78 > private _nameMap: { [name: string]: string };
79 > private _lowercaseNameMap: { [name: string]: string };
80 >
81 > constructor(useModesRegistry = true, warnOnOverwrite = false) {
82 super();
83 LanguagesRegistry.instanceCount++;
98 }
99 }
101 > override dispose() {
102 LanguagesRegistry.instanceCount--;
103 super.dispose();
104 }
106 > public setDynamicLanguages(def: ILanguageExtensionPoint[]): void {
107 this._dynamicLanguages = def;
108 this._initializeFromRegistry();
109 }
111 > private _initializeFromRegistry(): void {
112 this._languages = {};
113 this._mimeTypesMap = {};
119 this._registerLanguages(desc);
120 }
122 > registerLanguage(desc: ILanguageExtensionPoint): IDisposable {
123 return ModesRegistry.registerLanguage(desc);
124 }
126 > _registerLanguages(desc: ILanguageExtensionPoint[]): void {
127
128 for (const d of desc) {
151 this._onDidChange.fire();
152 }
154 > private _registerLanguage(lang: ILanguageExtensionPoint): void {
155 const langId = lang.id;
156
175 this._mergeLanguage(resolvedLanguage, lang);
176 }
178 > private _mergeLanguage(resolvedLanguage: IResolvedLanguage, lang: ILanguageExtensionPoint): void {
179 const langId = lang.id;
180
271 }
272 }
274 > public isRegisteredLanguageId(languageId: string | null | undefined): boolean {
275 if (!languageId) {
276 return false;
278 return hasOwnProperty.call(this._languages, languageId);
279 }
281 > public getRegisteredLanguageIds(): string[] {
282 return Object.keys(this._languages);
283 }
285 > public getSortedRegisteredLanguageNames(): ILanguageNameIdPair[] {
286 const result: ILanguageNameIdPair[] = [];
287 for (const languageName in this._nameMap) {
296 return result;
297 }
299 > public getLanguageName(languageId: string): string | null {
300 if (!hasOwnProperty.call(this._languages, languageId)) {
301 return null;
303 return this._languages[languageId].name;
304 }
306 > public getMimeType(languageId: string): string | null {
307 if (!hasOwnProperty.call(this._languages, languageId)) {
308 return null;
311 return (language.mimetypes[0] || null);
312 }
314 > public getExtensions(languageId: string): ReadonlyArray<string> {
315 if (!hasOwnProperty.call(this._languages, languageId)) {
316 return [];
318 return this._languages[languageId].extensions;
319 }
321 > public getFilenames(languageId: string): ReadonlyArray<string> {
322 if (!hasOwnProperty.call(this._languages, languageId)) {
323 return [];
325 return this._languages[languageId].filenames;
326 }
328 > public getIcon(languageId: string): ILanguageIcon | null {
329 if (!hasOwnProperty.call(this._languages, languageId)) {
330 return null;
333 return (language.icons[0] || null);
334 }
336 > public getConfigurationFiles(languageId: string): ReadonlyArray<URI> {
337 if (!hasOwnProperty.call(this._languages, languageId)) {
338 return [];
340 return this._languages[languageId].configurationFiles || [];
341 }
343 > public getLanguageIdByLanguageName(languageName: string): string | null {
344 const languageNameLower = languageName.toLowerCase();
345 if (!hasOwnProperty.call(this._lowercaseNameMap, languageNameLower)) {
348 return this._lowercaseNameMap[languageNameLower];
349 }
351 > public getLanguageIdByMimeType(mimeType: string | null | undefined): string | null {
352 if (!mimeType) {
353 return null;
358 return null;
359 }
361 > public guessLanguageIdByFilepathOrFirstLine(resource: URI | null, firstLine?: string): string[] {
362 if (!resource && !firstLine) {
363 return [];
src/vs/base/common/mime.ts 102 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mime.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 { extname } from './path.js';
7 >
8 > export const Mimes = Object.freeze({
9 > text: 'text/plain',
10 > binary: 'application/octet-stream',
11 > unknown: 'application/unknown',
12 > markdown: 'text/markdown',
13 > latex: 'text/latex',
14 > uriList: 'text/uri-list',
15 > html: 'text/html',
16 > });
17 >
18 > interface MapExtToMediaMimes {
19 > [index: string]: string | string[];
20 > }
21 >
22 > const mapExtToTextMimes: Record<string, string> = {
23 > '.css': 'text/css',
24 > '.csv': 'text/csv',
25 > '.htm': 'text/html',
26 > '.html': 'text/html',
27 > '.ics': 'text/calendar',
28 > '.js': 'text/javascript',
29 > '.mjs': 'text/javascript',
30 > '.txt': 'text/plain',
31 > '.xml': 'text/xml'
32 > };
33 >
34 > // Known media mimes that we can handle
35 > const mapExtToMediaMimes: MapExtToMediaMimes = {
36 > '.aac': 'audio/x-aac',
37 > '.avi': 'video/x-msvideo',
38 > '.bmp': 'image/bmp',
39 > '.flv': 'video/x-flv',
40 > '.gif': 'image/gif',
41 > '.ico': 'image/x-icon',
42 > '.jpe': ['image/jpg', 'image/jpeg'],
43 > '.jpeg': ['image/jpg', 'image/jpeg'],
44 > '.jpg': ['image/jpg', 'image/jpeg'],
45 > '.m1v': 'video/mpeg',
46 > '.m2a': 'audio/mpeg',
47 > '.m2v': 'video/mpeg',
48 > '.m3a': 'audio/mpeg',
49 > '.mid': 'audio/midi',
50 > '.midi': 'audio/midi',
51 > '.mk3d': 'video/x-matroska',
52 > '.mks': 'video/x-matroska',
53 > '.mkv': 'video/x-matroska',
54 > '.mov': 'video/quicktime',
55 > '.movie': 'video/x-sgi-movie',
56 > '.mp2': 'audio/mpeg',
57 > '.mp2a': 'audio/mpeg',
58 > '.mp3': 'audio/mpeg',
59 > '.mp4': 'video/mp4',
60 > '.mp4a': 'audio/mp4',
61 > '.mp4v': 'video/mp4',
62 > '.mpe': 'video/mpeg',
63 > '.mpeg': 'video/mpeg',
64 > '.mpg': 'video/mpeg',
65 > '.mpg4': 'video/mp4',
66 > '.mpga': 'audio/mpeg',
67 > '.oga': 'audio/ogg',
68 > '.ogg': 'audio/ogg',
69 > '.opus': 'audio/opus',
70 > '.ogv': 'video/ogg',
71 > '.png': 'image/png',
72 > '.psd': 'image/vnd.adobe.photoshop',
73 > '.qt': 'video/quicktime',
74 > '.spx': 'audio/ogg',
75 > '.svg': 'image/svg+xml',
76 > '.tga': 'image/x-tga',
77 > '.tif': 'image/tiff',
78 > '.tiff': 'image/tiff',
79 > '.wav': 'audio/x-wav',
80 > '.webm': 'video/webm',
81 > '.webp': 'image/webp',
82 > '.wma': 'audio/x-ms-wma',
83 > '.wmv': 'video/x-ms-wmv',
84 > '.woff': 'application/font-woff',
85 > };
86 >
87 > export function getMediaOrTextMime(path: string): string | undefined {
88 const ext = extname(path);
89 const textMime = mapExtToTextMimes[ext.toLowerCase()];
94 }
95 }
96 > mime.ts
97 > export function getMediaMime(path: string): string | undefined {
98 const ext = extname(path);
99 const mimeType = mapExtToMediaMimes[ext.toLowerCase()];
100 return Array.isArray(mimeType) ? mimeType[0] : mimeType;
101 }
102 > mime.ts
103 > export function getExtensionForMimeType(mimeType: string): string | undefined {
104 for (const extension in mapExtToMediaMimes) {
105 const value = mapExtToMediaMimes[extension];
111 return undefined;
112 }
113 > mime.ts
114 > const _simplePattern = /^(.+)\/(.+?)(;.+)?$/;
115 >
116 > export function normalizeMimeType(mimeType: string): string;
117 > export function normalizeMimeType(mimeType: string, strict: true): string | undefined;
118 > export function normalizeMimeType(mimeType: string, strict?: true): string | undefined {
119
120 const match = _simplePattern.exec(mimeType);
128 return `${match[1].toLowerCase()}/${match[2].toLowerCase()}${match[3] ?? ''}`;
129 }
130 > mime.ts
131 > /**
132 > * Whether the provided mime type is a text stream like `stdout`, `stderr`.
133 > */
134 > export function isTextStreamMime(mimeType: string) {
135 return ['application/vnd.code.notebook.stdout', 'application/vnd.code.notebook.stderr'].includes(mimeType);
136 }
src/vs/editor/common/tokenizationTextModelPart.ts 102 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tokenizationTextModelPart.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 { Range } from './core/range.js';
7 > import { StandardTokenType } from './encodedTokenAttributes.js';
8 > import { LineTokens } from './tokens/lineTokens.js';
9 > import { SparseMultilineTokens } from './tokens/sparseMultilineTokens.js';
10 >
11 > /**
12 > * Provides tokenization related functionality of the text model.
13 > */
14 > export interface ITokenizationTextModelPart {
15 > readonly hasTokens: boolean;
16 >
17 > /**
18 > * Replaces all semantic tokens with the provided `tokens`.
19 > * @internal
20 > */
21 > setSemanticTokens(tokens: SparseMultilineTokens[] | null, isComplete: boolean): void;
22 >
23 > /**
24 > * Merges the provided semantic tokens into existing semantic tokens.
25 > * @internal
26 > */
27 > setPartialSemanticTokens(range: Range, tokens: SparseMultilineTokens[] | null): void;
28 >
29 > /**
30 > * @internal
31 > */
32 > hasCompleteSemanticTokens(): boolean;
33 >
34 > /**
35 > * @internal
36 > */
37 > hasSomeSemanticTokens(): boolean;
38 >
39 > /**
40 > * Flush all tokenization state.
41 > * @internal
42 > */
43 > resetTokenization(): void;
44 >
45 > /**
46 > * Force tokenization information for `lineNumber` to be accurate.
47 > * @internal
48 > */
49 > forceTokenization(lineNumber: number): void;
50 >
51 > /**
52 > * If it is cheap, force tokenization information for `lineNumber` to be accurate.
53 > * This is based on a heuristic.
54 > * @internal
55 > */
56 > tokenizeIfCheap(lineNumber: number): void;
57 >
58 > /**
59 > * Check if tokenization information is accurate for `lineNumber`.
60 > * @internal
61 > */
62 > hasAccurateTokensForLine(lineNumber: number): boolean;
63 >
64 > /**
65 > * Check if calling `forceTokenization` for this `lineNumber` will be cheap (time-wise).
66 > * This is based on a heuristic.
67 > * @internal
68 > */
69 > isCheapToTokenize(lineNumber: number): boolean;
70 >
71 > /**
72 > * Get the tokens for the line `lineNumber`.
73 > * The tokens might be inaccurate. Use `forceTokenization` to ensure accurate tokens.
74 > * @internal
75 > */
76 > getLineTokens(lineNumber: number): LineTokens;
77 >
78 > /**
79 > * Returns the standard token type for a character if the character were to be inserted at
80 > * the given position. If the result cannot be accurate, it returns null.
81 > * @internal
82 > */
83 > getTokenTypeIfInsertingCharacter(lineNumber: number, column: number, character: string): StandardTokenType;
84 >
85 > /**
86 > * Tokens the lines as if they were inserted at [lineNumber, lineNumber).
87 > * @internal
88 > */
89 > tokenizeLinesAt(lineNumber: number, lines: string[]): LineTokens[] | null;
90 >
91 > getLanguageId(): string;
92 > getLanguageIdAtPosition(lineNumber: number, column: number): string;
93 >
94 > setLanguageId(languageId: string, source?: string): void;
95 >
96 > readonly backgroundTokenizationState: BackgroundTokenizationState;
97 > }
98 >
99 > export const enum BackgroundTokenizationState {
100 > InProgress = 1,
101 > Completed = 2,
102 > }
src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts 100 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- jsonContributionRegistry.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 '../../../base/common/event.js';
7 > import { getCompressedContent, IJSONSchema } from '../../../base/common/jsonSchema.js';
8 > import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../../base/common/lifecycle.js';
9 > import * as platform from '../../registry/common/platform.js';
10 >
11 > export const Extensions = {
12 > JSONContribution: 'base.contributions.json'
13 > };
14 >
15 > export interface ISchemaContributions {
16 > schemas: { [id: string]: IJSONSchema };
17 > }
18 >
19 > export interface IJSONContributionRegistry {
20 >
21 > readonly onDidChangeSchema: Event<string>;
22 > readonly onDidChangeSchemaAssociations: Event<void>;
23 >
24 > /**
25 > * Register a schema to the registry.
26 > */
27 > registerSchema(uri: string, unresolvedSchemaContent: IJSONSchema, store?: DisposableStore): void;
28 >
29 > registerSchemaAssociation(uri: string, glob: string): IDisposable;
30 >
31 > /**
32 > * Notifies all listeners that the content of the given schema has changed.
33 > * @param uri The id of the schema
34 > */
35 > notifySchemaChanged(uri: string): void;
36 >
37 > /**
38 > * Get all schemas
39 > */
40 > getSchemaContributions(): ISchemaContributions;
41 >
42 > getSchemaAssociations(): { [uri: string]: string[] };
43 >
44 > /**
45 > * Gets the (compressed) content of the schema with the given schema ID (if any)
46 > * @param uri The id of the schema
47 > */
48 > getSchemaContent(uri: string): string | undefined;
49 >
50 > /**
51 > * Returns true if there's a schema that matches the given schema ID
52 > * @param uri The id of the schema
53 > */
54 > hasSchemaContent(uri: string): boolean;
55 > }
56 >
57 >
58 >
59 > function normalizeId(id: string) {
60 > if (id.length > 0 && id.charAt(id.length - 1) === '#') {
61 return id.substring(0, id.length - 1);
62 }
63 > return id; jsonContributionRegistry.ts
64 > }
65 >
66 >
67 >
68 > class JSONContributionRegistry extends Disposable implements IJSONContributionRegistry {
69 >
70 > private readonly schemasById: { [id: string]: IJSONSchema } = {};
71 > private readonly schemaAssociations: { [uri: string]: string[] } = {};
72 >
73 > private readonly _onDidChangeSchema = this._register(new Emitter<string>());
74 > readonly onDidChangeSchema: Event<string> = this._onDidChangeSchema.event;
75 >
76 > private readonly _onDidChangeSchemaAssociations = this._register(new Emitter<void>());
77 > readonly onDidChangeSchemaAssociations: Event<void> = this._onDidChangeSchemaAssociations.event;
78 >
79 > public registerSchema(uri: string, unresolvedSchemaContent: IJSONSchema, store?: DisposableStore): void {
80 > const normalizedUri = normalizeId(uri);
81 > this.schemasById[normalizedUri] = unresolvedSchemaContent;
82 > this._onDidChangeSchema.fire(uri);
83 >
84 > if (store) {
85 store.add(toDisposable(() => {
86 delete this.schemasById[normalizedUri];
88 }));
89 }
91 >
92 > public registerSchemaAssociation(uri: string, glob: string): IDisposable {
93 const normalizedUri = normalizeId(uri);
94 if (!this.schemaAssociations[normalizedUri]) {
114 });
115 }
117 > public notifySchemaChanged(uri: string): void {
118 this._onDidChangeSchema.fire(uri);
119 }
121 > public getSchemaContributions(): ISchemaContributions {
122 return {
123 schemas: this.schemasById,
124 };
125 }
127 > public getSchemaContent(uri: string): string | undefined {
128 const schema = this.schemasById[uri];
129 return schema ? getCompressedContent(schema) : undefined;
130 }
132 > public hasSchemaContent(uri: string): boolean {
133 return !!this.schemasById[uri];
134 }
136 > public getSchemaAssociations(): { [uri: string]: string[] } {
137 return this.schemaAssociations;
138 }
140 > }
141 >
142 > const jsonContributionRegistry = new JSONContributionRegistry();
143 > platform.Registry.add(Extensions.JSONContribution, jsonContributionRegistry);
src/vs/platform/theme/common/colors/baseColors.ts 97 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- baseColors.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 > // Import the effects we need
9 > import { Color } from '../../../../base/common/color.js';
10 > import { registerColor, transparent } from '../colorUtils.js';
11 >
12 >
13 > export const foreground = registerColor('foreground',
14 > { dark: '#CCCCCC', light: '#616161', hcDark: '#FFFFFF', hcLight: '#292929' },
15 > nls.localize('foreground', "Overall foreground color. This color is only used if not overridden by a component."));
16 >
17 > export const strongForeground = registerColor('strongForeground',
18 > { dark: '#FFFFFF', light: '#000000', hcDark: '#FFFFFF', hcLight: '#000000' },
19 > nls.localize('strongForeground', "Highest-contrast foreground color, intended for text or icons that need maximum legibility across various backgrounds. This color is only used if not overridden by a component."));
20 >
21 > export const disabledForeground = registerColor('disabledForeground',
22 > { dark: '#CCCCCC80', light: '#61616180', hcDark: '#A5A5A5', hcLight: '#7F7F7F' },
23 > nls.localize('disabledForeground', "Overall foreground for disabled elements. This color is only used if not overridden by a component."));
24 >
25 > export const errorForeground = registerColor('errorForeground',
26 > { dark: '#F48771', light: '#A1260D', hcDark: '#F48771', hcLight: '#B5200D' },
27 > nls.localize('errorForeground', "Overall foreground color for error messages. This color is only used if not overridden by a component."));
28 >
29 > export const descriptionForeground = registerColor('descriptionForeground',
30 > { light: '#717171', dark: transparent(foreground, 0.7), hcDark: transparent(foreground, 0.7), hcLight: transparent(foreground, 0.7) },
31 > nls.localize('descriptionForeground', "Foreground color for description text providing additional information, for example for a label."));
32 >
33 > export const iconForeground = registerColor('icon.foreground',
34 > { dark: '#C5C5C5', light: '#424242', hcDark: '#FFFFFF', hcLight: '#292929' },
35 > nls.localize('iconForeground', "The default color for icons in the workbench."));
36 >
37 > export const focusBorder = registerColor('focusBorder',
38 > { dark: '#007FD4', light: '#0090F1', hcDark: '#F38518', hcLight: '#006BBD' },
39 > nls.localize('focusBorder', "Overall border color for focused elements. This color is only used if not overridden by a component."));
40 >
41 > export const contrastBorder = registerColor('contrastBorder',
42 > { light: null, dark: null, hcDark: '#6FC3DF', hcLight: '#0F4A85' },
43 > nls.localize('contrastBorder', "An extra border around elements to separate them from others for greater contrast."));
44 >
45 > export const activeContrastBorder = registerColor('contrastActiveBorder',
46 > { light: null, dark: null, hcDark: focusBorder, hcLight: focusBorder },
47 > nls.localize('activeContrastBorder', "An extra border around active elements to separate them from others for greater contrast."));
48 >
49 > export const selectionBackground = registerColor('selection.background',
50 > null,
51 > nls.localize('selectionBackground', "The background color of text selections in the workbench (e.g. for input fields or text areas). Note that this does not apply to selections within the editor."));
52 >
53 >
54 > // ------ text link
55 >
56 > export const textLinkForeground = registerColor('textLink.foreground',
57 > { light: '#006AB1', dark: '#3794FF', hcDark: '#21A6FF', hcLight: '#0F4A85' },
58 > nls.localize('textLinkForeground', "Foreground color for links in text."));
59 >
60 > export const textLinkActiveForeground = registerColor('textLink.activeForeground',
61 > { light: '#006AB1', dark: '#3794FF', hcDark: '#21A6FF', hcLight: '#0F4A85' },
62 > nls.localize('textLinkActiveForeground', "Foreground color for links in text when clicked on and on mouse hover."));
63 >
64 > export const textSeparatorForeground = registerColor('textSeparator.foreground',
65 > { light: '#0000002e', dark: '#ffffff2e', hcDark: Color.black, hcLight: '#292929' },
66 > nls.localize('textSeparatorForeground', "Color for text separators."));
67 >
68 >
69 > // ------ text preformat
70 >
71 > export const textPreformatForeground = registerColor('textPreformat.foreground',
72 > { light: '#A31515', dark: '#D7BA7D', hcDark: '#FFFFFF', hcLight: '#FFFFFF' },
73 > nls.localize('textPreformatForeground', "Foreground color for preformatted text segments."));
74 >
75 > export const textPreformatBackground = registerColor('textPreformat.background',
76 > { light: '#0000001A', dark: '#FFFFFF1A', hcDark: null, hcLight: '#09345f' },
77 > nls.localize('textPreformatBackground', "Background color for preformatted text segments."));
78 > export const textPreformatBorder = registerColor('textPreformat.border',
79 > { light: null, dark: null, hcDark: contrastBorder, hcLight: null },
80 > nls.localize('textPreformatBorder', "Border color for preformatted text segments."));
81 >
82 > // ------ text block quote
83 >
84 > export const textBlockQuoteBackground = registerColor('textBlockQuote.background',
85 > { light: '#f2f2f2', dark: '#222222', hcDark: null, hcLight: '#F2F2F2' },
86 > nls.localize('textBlockQuoteBackground', "Background color for block quotes in text."));
87 >
88 > export const textBlockQuoteBorder = registerColor('textBlockQuote.border',
89 > { light: '#007acc80', dark: '#007acc80', hcDark: Color.white, hcLight: '#292929' },
90 > nls.localize('textBlockQuoteBorder', "Border color for block quotes in text."));
91 >
92 >
93 > // ------ text code block
94 >
95 > export const textCodeBlockBackground = registerColor('textCodeBlock.background',
96 > { light: '#dcdcdc66', dark: '#0a0a0a66', hcDark: Color.black, hcLight: '#F2F2F2' },
97 > nls.localize('textCodeBlockBackground', "Background color for code blocks in text."));
src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsImpl.ts 96 covered LOC · 25 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- bracketPairsImpl.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 { CallbackIterable, compareBy } from '../../../../base/common/arrays.js';
7 > import { Emitter } from '../../../../base/common/event.js';
8 > import { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable } from '../../../../base/common/lifecycle.js';
9 > import { IPosition, Position } from '../../core/position.js';
10 > import { Range } from '../../core/range.js';
11 > import { ILanguageConfigurationService, LanguageConfigurationServiceChangeEvent } from '../../languages/languageConfigurationRegistry.js';
12 > import { ignoreBracketsInToken } from '../../languages/supports.js';
13 > import { LanguageBracketsConfiguration } from '../../languages/supports/languageBracketsConfiguration.js';
14 > import { BracketsUtils, RichEditBracket, RichEditBrackets } from '../../languages/supports/richEditBrackets.js';
15 > import { BracketPairsTree } from './bracketPairsTree/bracketPairsTree.js';
16 > import { TextModel } from '../textModel.js';
17 > import { BracketInfo, BracketPairInfo, BracketPairWithMinIndentationInfo, IBracketPairsTextModelPart, IFoundBracket } from '../../textModelBracketPairs.js';
18 > import { IModelContentChangedEvent, IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent } from '../../textModelEvents.js';
19 > import { LineTokens } from '../../tokens/lineTokens.js';
20 >
21 > export class BracketPairsTextModelPart extends Disposable implements IBracketPairsTextModelPart {
22 > private readonly bracketPairsTree = this._register(new MutableDisposable<IReference<BracketPairsTree>>());
23 >
24 > private readonly onDidChangeEmitter = this._register(new Emitter<void>());
25 > public readonly onDidChange = this.onDidChangeEmitter.event;
26 >
27 > private get canBuildAST() {
28 > const maxSupportedDocumentLength = /* max lines */ 50_000 * /* average column count */ 100;
29 > return this.textModel.getValueLength() <= maxSupportedDocumentLength;
30 > }
31 >
32 > private bracketsRequested = false;
33 >
34 > public constructor(
35 private readonly textModel: TextModel,
36 private readonly languageConfigurationService: ILanguageConfigurationService
38 super();
39 }
41 > //#region TextModel events
42 >
43 > public handleLanguageConfigurationServiceChange(e: LanguageConfigurationServiceChangeEvent): void {
44 if (!e.languageId || this.bracketPairsTree.value?.object.didLanguageChange(e.languageId)) {
45 this.bracketPairsTree.clear();
47 }
48 }
50 > public handleDidChangeOptions(e: IModelOptionsChangedEvent): void {
51 this.bracketPairsTree.clear();
52 this.updateBracketPairsTree();
53 }
55 > public handleDidChangeLanguage(e: IModelLanguageChangedEvent): void {
56 this.bracketPairsTree.clear();
57 this.updateBracketPairsTree();
58 }
60 > public handleDidChangeContent(change: IModelContentChangedEvent) {
61 this.bracketPairsTree.value?.object.handleContentChanged(change);
62 }
64 > public handleDidChangeBackgroundTokenizationState(): void {
65 this.bracketPairsTree.value?.object.handleDidChangeBackgroundTokenizationState();
66 }
68 > public handleDidChangeTokens(e: IModelTokensChangedEvent): void {
69 this.bracketPairsTree.value?.object.handleDidChangeTokens(e);
70 }
72 > //#endregion
73 >
74 > private updateBracketPairsTree() {
75 if (this.bracketsRequested && this.canBuildAST) {
76 if (!this.bracketPairsTree.value) {
96 }
97 }
99 > /**
100 > * Returns all bracket pairs that intersect the given range.
101 > * The result is sorted by the start position.
102 > */
103 > public getBracketPairsInRange(range: Range): CallbackIterable<BracketPairInfo> {
104 this.bracketsRequested = true;
105 this.updateBracketPairsTree();
106 return this.bracketPairsTree.value?.object.getBracketPairsInRange(range, false) || CallbackIterable.empty;
107 }
109 > public getBracketPairsInRangeWithMinIndentation(range: Range): CallbackIterable<BracketPairWithMinIndentationInfo> {
110 this.bracketsRequested = true;
111 this.updateBracketPairsTree();
112 return this.bracketPairsTree.value?.object.getBracketPairsInRange(range, true) || CallbackIterable.empty;
113 }
115 > public getBracketsInRange(range: Range, onlyColorizedBrackets: boolean = false): CallbackIterable<BracketInfo> {
116 this.bracketsRequested = true;
117 this.updateBracketPairsTree();
118 return this.bracketPairsTree.value?.object.getBracketsInRange(range, onlyColorizedBrackets) || CallbackIterable.empty;
119 }
121 > public findMatchingBracketUp(_bracket: string, _position: IPosition, maxDuration?: number): Range | null {
122 const position = this.textModel.validatePosition(_position);
123 const languageId = this.textModel.getLanguageIdAtPosition(position.lineNumber, position.column);
159 }
160 }
162 > public matchBracket(position: IPosition, maxDuration?: number): [Range, Range] | null {
163 if (this.canBuildAST) {
164 const bracketPair =
189 }
190 }
192 > private _establishBracketSearchOffsets(position: Position, lineTokens: LineTokens, modeBrackets: RichEditBrackets, tokenIndex: number) {
193 const tokenCount = lineTokens.getCount();
194 const currentLanguageId = lineTokens.getLanguageId(tokenIndex);
222 return { searchStartOffset, searchEndOffset };
223 }
225 > private _matchBracket(position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): [Range, Range] | null {
226 const lineNumber = position.lineNumber;
227 const lineTokens = this.textModel.tokenization.getLineTokens(lineNumber);
297 return null;
298 }
300 > private _matchFoundBracket(foundBracket: Range, data: RichEditBracket, isOpen: boolean, continueSearchPredicate: ContinueBracketSearchPredicate): [Range, Range] | null | BracketSearchCanceled {
301 if (!data) {
302 return null;
319 return [foundBracket, matched];
320 }
322 > private _findMatchingBracketUp(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {
323 // console.log('_findMatchingBracketUp: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
324
406 return null;
407 }
409 > private _findMatchingBracketDown(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {
410 // console.log('_findMatchingBracketDown: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
411
494 return null;
495 }
497 > public findPrevBracket(_position: IPosition): IFoundBracket | null {
498 const position = this.textModel.validatePosition(_position);
499
580 return null;
581 }
583 > public findNextBracket(_position: IPosition): IFoundBracket | null {
584 const position = this.textModel.validatePosition(_position);
585
667 return null;
668 }
670 > public findEnclosingBrackets(_position: IPosition, maxDuration?: number): [Range, Range] | null {
671 const position = this.textModel.validatePosition(_position);
672
803 return null;
804 }
806 > private _toFoundBracket(bracketConfig: LanguageBracketsConfiguration, r: Range): IFoundBracket | null {
807 if (!r) {
808 return null;
822 };
823 }
825 >
826 function createDisposableRef<T>(object: T, disposable?: IDisposable): IReference<T> {
827 return {
830 };
831 }
833 > type ContinueBracketSearchPredicate = (() => boolean);
834 >
835 function createTimeBasedContinueBracketSearchPredicate(maxDuration: number | undefined): ContinueBracketSearchPredicate {
836 if (typeof maxDuration === 'undefined') {
843 }
844 }
846 > class BracketSearchCanceled {
847 > public static INSTANCE = new BracketSearchCanceled();
848 > _searchCanceledBrand = undefined;
849 > private constructor() { }
850 > }
851 >
852 function stripBracketSearchCanceled<T>(result: T | null | BracketSearchCanceled): T | null {
853 if (result instanceof BracketSearchCanceled) {
src/vs/base/common/arraysFind.ts 95 covered LOC · 16 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lineEdit.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, groupAdjacentBy, numberComparator } from '../../../../base/common/arrays.js';
7 > import { assert, checkAdjacentItems } from '../../../../base/common/assert.js';
8 > import { splitLines } from '../../../../base/common/strings.js';
9 > import { LineRange } from '../ranges/lineRange.js';
10 > import { BaseStringEdit, StringEdit, StringReplacement } from './stringEdit.js';
11 > import { Position } from '../position.js';
12 > import { Range } from '../range.js';
13 > import { TextReplacement, TextEdit } from './textEdit.js';
14 > import { AbstractText } from '../text/abstractText.js';
15 >
16 > export class LineEdit {
17 > public static readonly empty = new LineEdit([]);
18 >
19 > public static deserialize(data: SerializedLineEdit): LineEdit {
20 return new LineEdit(data.map(e => LineReplacement.deserialize(e)));
21 }
23 > public static fromStringEdit(edit: BaseStringEdit, initialValue: AbstractText): LineEdit {
24 const textEdit = TextEdit.fromStringEdit(edit, initialValue);
25 return LineEdit.fromTextEdit(textEdit, initialValue);
26 }
28 > public static fromTextEdit(edit: TextEdit, initialValue: AbstractText): LineEdit {
29 const edits = edit.replacements;
30
49 return new LineEdit(result);
50 }
52 > public static createFromUnsorted(edits: readonly LineReplacement[]): LineEdit {
53 const result = edits.slice();
54 result.sort(compareBy(i => i.lineRange.startLineNumber, numberComparator));
55 return new LineEdit(result);
56 }
58 > constructor(
59 > /**
60 > * Have to be sorted by start line number and non-intersecting.
61 > */
62 > public readonly replacements: readonly LineReplacement[]
63 > ) {
64 > assert(checkAdjacentItems(replacements, (i1, i2) => i1.lineRange.endLineNumberExclusive <= i2.lineRange.startLineNumber));
65 > }
66 >
67 > public isEmpty(): boolean {
68 return this.replacements.length === 0;
69 }
71 > public toEdit(initialValue: AbstractText): StringEdit {
72 const edits: StringReplacement[] = [];
73 for (const edit of this.replacements) {
77 return new StringEdit(edits);
78 }
80 > public toString(): string {
81 return this.replacements.map(e => e.toString()).join(',');
82 }
84 > public serialize(): SerializedLineEdit {
85 return this.replacements.map(e => e.serialize());
86 }
88 > public getNewLineRanges(): LineRange[] {
89 const ranges: LineRange[] = [];
90 let offset = 0;
95 return ranges;
96 }
98 > public mapLineNumber(lineNumber: number): number {
99 let lineDelta = 0;
100 for (const e of this.replacements) {
107 return lineNumber + lineDelta;
108 }
109 > lineEdit.ts
110 > public mapLineRange(lineRange: LineRange): LineRange {
111 return new LineRange(
112 this.mapLineNumber(lineRange.startLineNumber),
114 );
115 }
116 > lineEdit.ts
117 >
118 > /** TODO improve, dont require originalLines */
119 > public mapBackLineRange(lineRange: LineRange, originalLines: string[]): LineRange {
120 const i = this.inverse(originalLines);
121 return i.mapLineRange(lineRange);
122 }
123 > lineEdit.ts
124 > public touches(other: LineEdit): boolean {
125 return this.replacements.some(e1 => other.replacements.some(e2 => e1.lineRange.intersect(e2.lineRange)));
126 }
127 > lineEdit.ts
128 > public rebase(base: LineEdit): LineEdit {
129 return new LineEdit(
130 this.replacements.map(e => new LineReplacement(base.mapLineRange(e.lineRange), e.newLines)),
131 );
132 }
133 > lineEdit.ts
134 > public humanReadablePatch(originalLines: string[]): string {
135 const result: string[] = [];
136
192 return result.join('\n');
193 }
194 > lineEdit.ts
195 > public apply(lines: string[]): string[] {
196 const result: string[] = [];
197
218 return result;
219 }
220 > lineEdit.ts
221 > public inverse(originalLines: string[]): LineEdit {
222 const newRanges = this.getNewLineRanges();
223 return new LineEdit(this.replacements.map((e, idx) => new LineReplacement(
226 )));
227 }
228 > } lineEdit.ts
229 >
230 > export class LineReplacement {
231 > public static deserialize(e: SerializedLineReplacement): LineReplacement {
232 > return new LineReplacement(
233 > LineRange.ofLength(e[0], e[1] - e[0]),
234 > e[2],
235 > );
236 > }
237 >
238 > public static fromSingleTextEdit(edit: TextReplacement, initialValue: AbstractText): LineReplacement {
239 // 1: ab[cde
240 // 2: fghijk
284 return new LineReplacement(new LineRange(startLineNumber, endLineNumberEx), newLines);
285 }
286 > lineEdit.ts
287 > constructor(
288 public readonly lineRange: LineRange,
289 public readonly newLines: readonly string[],
290 ) { }
291 > lineEdit.ts
292 > public toSingleTextEdit(initialValue: AbstractText): TextReplacement {
293 if (this.newLines.length === 0) {
294 // Deletion
344 }
345 }
346 > lineEdit.ts
347 > public toSingleEdit(initialValue: AbstractText): StringReplacement {
348 const textEdit = this.toSingleTextEdit(initialValue);
349 const range = initialValue.getTransformer().getOffsetRange(textEdit.range);
350 return new StringReplacement(range, textEdit.text);
351 }
352 > lineEdit.ts
353 > public toString(): string {
354 return `${this.lineRange}->${JSON.stringify(this.newLines)}`;
355 }
356 > lineEdit.ts
357 > public serialize(): SerializedLineReplacement {
358 return [
359 this.lineRange.startLineNumber,
362 ];
363 }
364 > lineEdit.ts
365 > public removeCommonSuffixPrefixLines(initialValue: AbstractText): LineReplacement {
366 let startLineNumber = this.lineRange.startLineNumber;
367 let endLineNumberEx = this.lineRange.endLineNumberExclusive;
390 return new LineReplacement(new LineRange(startLineNumber, endLineNumberEx), this.newLines.slice(trimStartCount, this.newLines.length - trimEndCount));
391 }
392 > lineEdit.ts
393 > public toLineEdit(): LineEdit {
394 return new LineEdit([this]);
395 }
396 > } lineEdit.ts
397 >
398 > export type SerializedLineEdit = SerializedLineReplacement[];
399 > export type SerializedLineReplacement = [startLineNumber: number, endLineNumber: number, newLines: readonly string[]];
400 >
401 > export namespace SerializedLineReplacement {
402 > export function is(thing: unknown): thing is SerializedLineReplacement {
403 return (
404 Array.isArray(thing)
src/vs/base/common/extpath.ts 91 covered LOC · 17 ranges

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- miscColors.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 > // Import the effects we need
9 > import { Color } from '../../../../base/common/color.js';
10 > import { registerColor, transparent } from '../colorUtils.js';
11 >
12 > // Import the colors we need
13 > import { contrastBorder, focusBorder } from './baseColors.js';
14 >
15 >
16 > // ----- sash
17 >
18 > export const sashHoverBorder = registerColor('sash.hoverBorder',
19 > focusBorder,
20 > nls.localize('sashActiveBorder', "Border color of active sashes."));
21 >
22 >
23 > // ----- badge
24 >
25 > export const badgeBackground = registerColor('badge.background',
26 > { dark: '#4D4D4D', light: '#C4C4C4', hcDark: Color.black, hcLight: '#0F4A85' },
27 > nls.localize('badgeBackground', "Badge background color. Badges are small information labels, e.g. for search results count."));
28 >
29 > export const badgeForeground = registerColor('badge.foreground',
30 > { dark: Color.white, light: '#333', hcDark: Color.white, hcLight: Color.white },
31 > nls.localize('badgeForeground', "Badge foreground color. Badges are small information labels, e.g. for search results count."));
32 >
33 > export const activityWarningBadgeForeground = registerColor('activityWarningBadge.foreground',
34 > { dark: Color.white, light: Color.white, hcDark: Color.white, hcLight: Color.white },
35 > nls.localize('activityWarningBadge.foreground', 'Foreground color of the warning activity badge'));
36 >
37 > export const activityWarningBadgeBackground = registerColor('activityWarningBadge.background',
38 > { dark: '#B27C00', light: '#B27C00', hcDark: null, hcLight: '#B27C00' },
39 > nls.localize('activityWarningBadge.background', 'Background color of the warning activity badge'));
40 >
41 > export const activityErrorBadgeForeground = registerColor('activityErrorBadge.foreground',
42 > { dark: Color.black.lighten(0.2), light: Color.white, hcDark: null, hcLight: Color.black.lighten(0.2) },
43 > nls.localize('activityErrorBadge.foreground', 'Foreground color of the error activity badge'));
44 >
45 > export const activityErrorBadgeBackground = registerColor('activityErrorBadge.background',
46 > { dark: '#F14C4C', light: '#E51400', hcDark: null, hcLight: '#F14C4C' },
47 > nls.localize('activityErrorBadge.background', 'Background color of the error activity badge'));
48 >
49 >
50 > // ----- scrollbar
51 >
52 > export const scrollbarShadow = registerColor('scrollbar.shadow',
53 > { dark: '#000000', light: '#DDDDDD', hcDark: null, hcLight: null },
54 > nls.localize('scrollbarShadow', "Scrollbar shadow to indicate that the view is scrolled."));
55 >
56 > export const scrollbarSliderBackground = registerColor('scrollbarSlider.background',
57 > { dark: Color.fromHex('#797979').transparent(0.4), light: Color.fromHex('#646464').transparent(0.4), hcDark: transparent(contrastBorder, 0.6), hcLight: transparent(contrastBorder, 0.4) },
58 > nls.localize('scrollbarSliderBackground', "Scrollbar slider background color."));
59 >
60 > export const scrollbarSliderHoverBackground = registerColor('scrollbarSlider.hoverBackground',
61 > { dark: Color.fromHex('#646464').transparent(0.7), light: Color.fromHex('#646464').transparent(0.7), hcDark: transparent(contrastBorder, 0.8), hcLight: transparent(contrastBorder, 0.8) },
62 > nls.localize('scrollbarSliderHoverBackground', "Scrollbar slider background color when hovering."));
63 >
64 > export const scrollbarSliderActiveBackground = registerColor('scrollbarSlider.activeBackground',
65 > { dark: Color.fromHex('#BFBFBF').transparent(0.4), light: Color.fromHex('#000000').transparent(0.6), hcDark: contrastBorder, hcLight: contrastBorder },
66 > nls.localize('scrollbarSliderActiveBackground', "Scrollbar slider background color when clicked on."));
67 >
68 > export const scrollbarBackground = registerColor('scrollbar.background',
69 > null,
70 > nls.localize('scrollbarBackground', "Scrollbar track background color."));
71 >
72 >
73 > // ----- progress bar
74 >
75 > export const progressBarBackground = registerColor('progressBar.background',
76 > { dark: Color.fromHex('#0E70C0'), light: Color.fromHex('#0E70C0'), hcDark: contrastBorder, hcLight: contrastBorder },
77 > nls.localize('progressBarBackground', "Background color of the progress bar that can show for long running operations."));
78 >
79 > // ----- chart
80 >
81 > export const chartLine = registerColor('chart.line',
82 > { dark: '#236B8E', light: '#236B8E', hcDark: '#236B8E', hcLight: '#236B8E' },
83 > nls.localize('chartLine', "Line color for the chart."));
84 >
85 > export const chartAxis = registerColor('chart.axis',
86 > { dark: Color.fromHex('#BFBFBF').transparent(0.4), light: Color.fromHex('#000000').transparent(0.6), hcDark: contrastBorder, hcLight: contrastBorder },
87 > nls.localize('chartAxis', "Axis color for the chart."));
88 >
89 > export const chartGuide = registerColor('chart.guide',
90 > { dark: Color.fromHex('#BFBFBF').transparent(0.2), light: Color.fromHex('#000000').transparent(0.2), hcDark: contrastBorder, hcLight: contrastBorder },
91 > nls.localize('chartGuide', "Guide line for the chart."));
src/vs/base/common/cancellation.ts 90 covered LOC · 18 ranges

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- bracketPairsTree.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 } from '../../../../../base/common/event.js';
7 > import { Disposable } from '../../../../../base/common/lifecycle.js';
8 > import { Range } from '../../../core/range.js';
9 > import { ITextModel } from '../../../model.js';
10 > import { BracketInfo, BracketPairWithMinIndentationInfo, IFoundBracket } from '../../../textModelBracketPairs.js';
11 > import { TextModel } from '../../textModel.js';
12 > import { IModelContentChangedEvent, IModelTokensChangedEvent } from '../../../textModelEvents.js';
13 > import { ResolvedLanguageConfiguration } from '../../../languages/languageConfigurationRegistry.js';
14 > import { AstNode, AstNodeKind } from './ast.js';
15 > import { TextEditInfo } from './beforeEditPositionMapper.js';
16 > import { LanguageAgnosticBracketTokens } from './brackets.js';
17 > import { Length, lengthAdd, lengthGreaterThanEqual, lengthLessThan, lengthLessThanEqual, lengthsToRange, lengthZero, positionToLength, toLength } from './length.js';
18 > import { parseDocument } from './parser.js';
19 > import { DenseKeyProvider } from './smallImmutableSet.js';
20 > import { FastTokenizer, TextBufferTokenizer } from './tokenizer.js';
21 > import { BackgroundTokenizationState } from '../../../tokenizationTextModelPart.js';
22 > import { Position } from '../../../core/position.js';
23 > import { CallbackIterable } from '../../../../../base/common/arrays.js';
24 > import { combineTextEditInfos } from './combineTextEditInfos.js';
25 > import { ClosingBracketKind, OpeningBracketKind } from '../../../languages/supports/languageBracketsConfiguration.js';
26 >
27 > export class BracketPairsTree extends Disposable {
28 > private readonly didChangeEmitter;
29 >
30 > /*
31 > There are two trees:
32 > * The initial tree that has no token information and is used for performant initial bracket colorization.
33 > * The tree that used token information to detect bracket pairs.
34 >
35 > To prevent flickering, we only switch from the initial tree to tree with token information
36 > when tokenization completes.
37 > Since the text can be edited while background tokenization is in progress, we need to update both trees.
38 > */
39 > private initialAstWithoutTokens: AstNode | undefined;
40 > private astWithTokens: AstNode | undefined;
41 >
42 > private readonly denseKeyProvider;
43 > private readonly brackets;
44 >
45 > public didLanguageChange(languageId: string): boolean {
46 > return this.brackets.didLanguageChange(languageId);
47 > }
48 >
49 > public readonly onDidChange;
50 > private queuedTextEditsForInitialAstWithoutTokens: TextEditInfo[];
51 > private queuedTextEdits: TextEditInfo[];
52 >
53 > public constructor(
54 private readonly textModel: TextModel,
55 private readonly getLanguageConfiguration: (languageId: string) => ResolvedLanguageConfiguration
79 }
80 }
82 > //#region TextModel events
83 >
84 > public handleDidChangeBackgroundTokenizationState(): void {
85 if (this.textModel.tokenization.backgroundTokenizationState === BackgroundTokenizationState.Completed) {
86 const wasUndefined = this.initialAstWithoutTokens === undefined;
92 }
93 }
95 > public handleDidChangeTokens({ ranges }: IModelTokensChangedEvent): void {
96 const edits = ranges.map(r =>
97 new TextEditInfo(
108 }
109 }
111 > public handleContentChanged(change: IModelContentChangedEvent) {
112 const edits = TextEditInfo.fromModelContentChanges(change.changes);
113 this.handleEdits(edits, false);
114 }
116 > private handleEdits(edits: TextEditInfo[], tokenChange: boolean): void {
117 // Lazily queue the edits and only apply them when the tree is accessed.
118 const result = combineTextEditInfos(this.queuedTextEdits, edits);
123 }
124 }
126 > //#endregion
127 >
128 > private flushQueue() {
129 if (this.queuedTextEdits.length > 0) {
130 this.astWithTokens = this.parseDocumentFromTextBuffer(this.queuedTextEdits, this.astWithTokens, false);
138 }
139 }
141 > /**
142 > * @pure (only if isPure = true)
143 > */
144 > private parseDocumentFromTextBuffer(edits: TextEditInfo[], previousAst: AstNode | undefined, immutable: boolean): AstNode {
145 // Is much faster if `isPure = false`.
146 const isPure = false;
150 return result;
151 }
153 > public getBracketsInRange(range: Range, onlyColorizedBrackets: boolean): CallbackIterable<BracketInfo> {
154 this.flushQueue();
155
161 });
162 }
164 > public getBracketPairsInRange(range: Range, includeMinIndentation: boolean): CallbackIterable<BracketPairWithMinIndentationInfo> {
165 this.flushQueue();
166
174 });
175 }
177 > public getFirstBracketAfter(position: Position): IFoundBracket | null {
178 this.flushQueue();
179
181 return getFirstBracketAfter(node, lengthZero, node.length, positionToLength(position));
182 }
184 > public getFirstBracketBefore(position: Position): IFoundBracket | null {
185 this.flushQueue();
186
188 return getFirstBracketBefore(node, lengthZero, node.length, positionToLength(position));
189 }
191 >
192 function getFirstBracketBefore(node: AstNode, nodeOffsetStart: Length, nodeOffsetEnd: Length, position: Length): IFoundBracket | null {
193 if (node.kind === AstNodeKind.List || node.kind === AstNodeKind.Pair) {
219 return null;
220 }
222 function getFirstBracketAfter(node: AstNode, nodeOffsetStart: Length, nodeOffsetEnd: Length, position: Length): IFoundBracket | null {
223 if (node.kind === AstNodeKind.List || node.kind === AstNodeKind.Pair) {
244 return null;
245 }
247 function collectBrackets(
248 node: AstNode,
373 }
374 }
376 > class CollectBracketPairsContext {
377 > constructor(
378 public readonly push: (item: BracketPairWithMinIndentationInfo) => boolean,
379 public readonly includeMinIndentation: boolean,
381 ) {
382 }
384 >
385 function collectBracketPairs(
386 node: AstNode,
src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length.ts 89 covered LOC · 22 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- length.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 { Position } from '../../../core/position.js';
8 > import { Range } from '../../../core/range.js';
9 > import { TextLength } from '../../../core/text/textLength.js';
10 >
11 > /**
12 > * The end must be greater than or equal to the start.
13 > */
14 > export function lengthDiff(startLineCount: number, startColumnCount: number, endLineCount: number, endColumnCount: number): Length {
15 return (startLineCount !== endLineCount)
16 ? toLength(endLineCount - startLineCount, endColumnCount)
17 : toLength(0, endColumnCount - startColumnCount);
18 }
19 > length.ts
20 > /**
21 > * Represents a non-negative length in terms of line and column count.
22 > * Does not allocate.
23 > */
24 > export type Length = { _brand: 'Length' };
25 >
26 > // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
27 > export const lengthZero = 0 as any as Length;
28 >
29 > export function lengthIsZero(length: Length): boolean {
30 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
31 return length as any as number === 0;
32 }
33 > length.ts
34 > /*
35 > * We have 52 bits available in a JS number.
36 > * We use the upper 26 bits to store the line and the lower 26 bits to store the column.
37 > */
38 > ///*
39 > const factor = 2 ** 26;
40 > /*/
41 > const factor = 1000000;
42 > // */
43 >
44 > export function toLength(lineCount: number, columnCount: number): Length {
45 // llllllllllllllllllllllllllcccccccccccccccccccccccccc (52 bits)
46 // line count (26 bits) column count (26 bits)
52 return (lineCount * factor + columnCount) as any as Length;
53 }
54 > length.ts
55 > export function lengthToObj(length: Length): TextLength {
56 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
57 const l = length as any as number;
60 return new TextLength(lineCount, columnCount);
61 }
62 > length.ts
63 > export function lengthGetLineCount(length: Length): number {
64 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
65 return Math.floor(length as any as number / factor);
66 }
67 > length.ts
68 > /**
69 > * Returns the amount of columns of the given length, assuming that it does not span any line.
70 > */
71 > export function lengthGetColumnCountIfZeroLineCount(length: Length): number {
72 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
73 return length as any as number;
74 }
75 > length.ts
76 >
77 > // [10 lines, 5 cols] + [ 0 lines, 3 cols] = [10 lines, 8 cols]
78 > // [10 lines, 5 cols] + [20 lines, 3 cols] = [30 lines, 3 cols]
79 > export function lengthAdd(length1: Length, length2: Length): Length;
80 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
81 > export function lengthAdd(l1: any, l2: any): Length {
82 let r = l1 + l2;
83 if (l2 >= factor) { r = r - (l1 % factor); }
84 return r;
85 }
86 > length.ts
87 > export function sumLengths<T>(items: readonly T[], lengthFn: (item: T) => Length): Length {
88 return items.reduce((a, b) => lengthAdd(a, lengthFn(b)), lengthZero);
89 }
90 > length.ts
91 > export function lengthEquals(length1: Length, length2: Length): boolean {
92 return length1 === length2;
93 }
94 > length.ts
95 > /**
96 > * Returns a non negative length `result` such that `lengthAdd(length1, result) = length2`, or zero if such length does not exist.
97 > */
98 > export function lengthDiffNonNegative(length1: Length, length2: Length): Length {
99 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
100 const l1 = length1 as any as number;
121 }
122 }
123 > length.ts
124 > export function lengthLessThan(length1: Length, length2: Length): boolean {
125 // First, compare line counts, then column counts.
126 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
127 return (length1 as any as number) < (length2 as any as number);
128 }
129 > length.ts
130 > export function lengthLessThanEqual(length1: Length, length2: Length): boolean {
131 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
132 return (length1 as any as number) <= (length2 as any as number);
133 }
134 > length.ts
135 > export function lengthGreaterThanEqual(length1: Length, length2: Length): boolean {
136 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
137 return (length1 as any as number) >= (length2 as any as number);
138 }
139 > length.ts
140 > export function lengthToPosition(length: Length): Position {
141 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
142 const l = length as any as number;
145 return new Position(lineCount + 1, colCount + 1);
146 }
147 > length.ts
148 > export function positionToLength(position: Position): Length {
149 return toLength(position.lineNumber - 1, position.column - 1);
150 }
151 > length.ts
152 > export function lengthsToRange(lengthStart: Length, lengthEnd: Length): Range {
153 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
154 const l = lengthStart as any as number;
163 return new Range(lineCount + 1, colCount + 1, lineCount2 + 1, colCount2 + 1);
164 }
165 > length.ts
166 > export function lengthOfRange(range: Range): TextLength {
167 if (range.startLineNumber === range.endLineNumber) {
168 return new TextLength(0, range.endColumn - range.startColumn);
171 }
172 }
173 > length.ts
174 > export function lengthCompare(length1: Length, length2: Length): number {
175 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
176 const l1 = length1 as any as number;
179 return l1 - l2;
180 }
181 > length.ts
182 > export function lengthOfString(str: string): Length {
183 const lines = splitLines(str);
184 return toLength(lines.length - 1, lines[lines.length - 1].length);
185 }
186 > length.ts
187 > export function lengthOfStringObj(str: string): TextLength {
188 const lines = splitLines(str);
189 return new TextLength(lines.length - 1, lines[lines.length - 1].length);
190 }
191 > length.ts
192 > /**
193 > * Computes a numeric hash of the given length.
194 > */
195 > export function lengthHash(length: Length): number {
196 // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
197 return length as any;
198 }
199 > length.ts
200 > export function lengthMax(length1: Length, length2: Length): Length {
201 return length1 > length2 ? length1 : length2;
202 }
src/vs/editor/common/services/textResourceConfiguration.ts 89 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textResourceConfiguration.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 { URI } from '../../../base/common/uri.js';
8 > import { IPosition } from '../core/position.js';
9 > import { ConfigurationTarget, IConfigurationValue } from '../../../platform/configuration/common/configuration.js';
10 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
11 >
12 > export const ITextResourceConfigurationService = createDecorator<ITextResourceConfigurationService>('textResourceConfigurationService');
13 >
14 > export interface ITextResourceConfigurationChangeEvent {
15 >
16 > /**
17 > * All affected keys. Also includes language overrides and keys changed under language overrides.
18 > */
19 > readonly affectedKeys: ReadonlySet<string>;
20 >
21 > /**
22 > * Returns `true` if the given section has changed for the given resource.
23 > *
24 > * Example: To check if the configuration section has changed for a given resource use `e.affectsConfiguration(resource, section)`.
25 > *
26 > * @param resource Resource for which the configuration has to be checked.
27 > * @param section Section of the configuration
28 > */
29 > affectsConfiguration(resource: URI | undefined, section: string): boolean;
30 > }
31 >
32 > export interface ITextResourceConfigurationService {
33 >
34 > readonly _serviceBrand: undefined;
35 >
36 > /**
37 > * Event that fires when the configuration changes.
38 > */
39 > readonly onDidChangeConfiguration: Event<ITextResourceConfigurationChangeEvent>;
40 >
41 > /**
42 > * Fetches the value of the section for the given resource by applying language overrides.
43 > * Value can be of native type or an object keyed off the section name.
44 > *
45 > * @param resource - Resource for which the configuration has to be fetched.
46 > * @param position - Position in the resource for which configuration has to be fetched.
47 > * @param section - Section of the configuration.
48 > *
49 > */
50 > getValue<T>(resource: URI | undefined, section?: string): T;
51 > getValue<T>(resource: URI | undefined, position?: IPosition, section?: string): T;
52 >
53 > /**
54 > * Inspects the values of the section for the given resource by applying language overrides.
55 > *
56 > * @param resource - Resource for which the configuration has to be fetched.
57 > * @param position - Position in the resource for which configuration has to be fetched.
58 > * @param section - Section of the configuration.
59 > *
60 > */
61 > inspect<T>(resource: URI | undefined, position: IPosition | null, section: string): IConfigurationValue<Readonly<T>>;
62 >
63 > /**
64 > * Update the configuration value for the given resource at the effective location.
65 > *
66 > * - If configurationTarget is not specified, target will be derived by checking where the configuration is defined.
67 > * - If the language overrides for the give resource contains the configuration, then it is updated.
68 > *
69 > * @param resource Resource for which the configuration has to be updated
70 > * @param key Configuration key
71 > * @param value Configuration value
72 > * @param configurationTarget Optional target into which the configuration has to be updated.
73 > * If not specified, target will be derived by checking where the configuration is defined.
74 > */
75 > updateValue(resource: URI | undefined, key: string, value: unknown, configurationTarget?: ConfigurationTarget): Promise<void>;
76 >
77 > }
78 >
79 > export const ITextResourcePropertiesService = createDecorator<ITextResourcePropertiesService>('textResourcePropertiesService');
80 >
81 > export interface ITextResourcePropertiesService {
82 >
83 > readonly _serviceBrand: undefined;
84 >
85 > /**
86 > * Returns the End of Line characters for the given resource
87 > */
88 > getEOL(resource: URI, language?: string): string;
89 > }
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/textModelBracketPairs.ts 88 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelBracketPairs.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 { CallbackIterable } from '../../base/common/arrays.js';
7 > import { Event } from '../../base/common/event.js';
8 > import { IPosition } from './core/position.js';
9 > import { IRange, Range } from './core/range.js';
10 > import { ClosingBracketKind, OpeningBracketKind } from './languages/supports/languageBracketsConfiguration.js';
11 > import { PairAstNode } from './model/bracketPairsTextModelPart/bracketPairsTree/ast.js';
12 >
13 > export interface IBracketPairsTextModelPart {
14 > /**
15 > * Is fired when bracket pairs change, either due to a text or a settings change.
16 > */
17 > readonly onDidChange: Event<void>;
18 >
19 > /**
20 > * Gets all bracket pairs that intersect the given position.
21 > * The result is sorted by the start position.
22 > */
23 > getBracketPairsInRange(range: IRange): CallbackIterable<BracketPairInfo>;
24 >
25 > /**
26 > * Gets all bracket pairs that intersect the given position.
27 > * The result is sorted by the start position.
28 > */
29 > getBracketPairsInRangeWithMinIndentation(range: IRange): CallbackIterable<BracketPairWithMinIndentationInfo>;
30 >
31 > getBracketsInRange(range: IRange, onlyColorizedBrackets?: boolean): CallbackIterable<BracketInfo>;
32 >
33 > /**
34 > * Find the matching bracket of `request` up, counting brackets.
35 > * @param request The bracket we're searching for
36 > * @param position The position at which to start the search.
37 > * @return The range of the matching bracket, or null if the bracket match was not found.
38 > */
39 > findMatchingBracketUp(bracket: string, position: IPosition, maxDuration?: number): Range | null;
40 >
41 > /**
42 > * Find the first bracket in the model before `position`.
43 > * @param position The position at which to start the search.
44 > * @return The info for the first bracket before `position`, or null if there are no more brackets before `positions`.
45 > */
46 > findPrevBracket(position: IPosition): IFoundBracket | null;
47 >
48 > /**
49 > * Find the first bracket in the model after `position`.
50 > * @param position The position at which to start the search.
51 > * @return The info for the first bracket after `position`, or null if there are no more brackets after `positions`.
52 > */
53 > findNextBracket(position: IPosition): IFoundBracket | null;
54 >
55 > /**
56 > * Find the enclosing brackets that contain `position`.
57 > * @param position The position at which to start the search.
58 > */
59 > findEnclosingBrackets(position: IPosition, maxDuration?: number): [Range, Range] | null;
60 >
61 > /**
62 > * Given a `position`, if the position is on top or near a bracket,
63 > * find the matching bracket of that bracket and return the ranges of both brackets.
64 > * @param position The position at which to look for a bracket.
65 > */
66 > matchBracket(position: IPosition, maxDuration?: number): [Range, Range] | null;
67 > }
68 >
69 > export interface IFoundBracket {
70 > range: Range;
71 > bracketInfo: OpeningBracketKind | ClosingBracketKind;
72 > }
73 >
74 > export class BracketInfo {
75 > constructor(
76 public readonly range: Range,
77 /** 0-based level */
80 public readonly isInvalid: boolean,
81 ) { }
83 >
84 > export class BracketPairInfo {
85 > constructor(
86 public readonly range: Range,
87 public readonly openingBracketRange: Range,
94 ) {
95 }
97 > public get openingBracketInfo(): OpeningBracketKind {
98 return this.bracketPairNode.openingBracket.bracketInfo as OpeningBracketKind;
99 }
101 > public get closingBracketInfo(): ClosingBracketKind | undefined {
102 return this.bracketPairNode.closingBracket?.bracketInfo as ClosingBracketKind | undefined;
103 }
105 >
106 > export class BracketPairWithMinIndentationInfo extends BracketPairInfo {
107 > constructor(
108 range: Range,
109 openingBracketRange: Range,
122 super(range, openingBracketRange, closingBracketRange, nestingLevel, nestingLevelOfEqualBracketType, bracketPairNode);
123 }
src/vs/editor/common/model/tokens/treeSitter/treeSitterTree.ts 87 covered LOC · 18 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- treeSitterTree.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 type * as TreeSitter from '@vscode/tree-sitter-wasm';
6 > import { TaskQueue } from '../../../../../base/common/async.js';
7 > import { Disposable, toDisposable } from '../../../../../base/common/lifecycle.js';
8 > import { IObservable, observableValue, transaction, IObservableWithChange } from '../../../../../base/common/observable.js';
9 > import { setTimeout0 } from '../../../../../base/common/platform.js';
10 > import { ILogService } from '../../../../../platform/log/common/log.js';
11 > import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js';
12 > import { TextLength } from '../../../core/text/textLength.js';
13 > import { IModelContentChangedEvent } from '../../../textModelEvents.js';
14 > import { IModelContentChange } from '../../mirrorTextModel.js';
15 > import { TextModel } from '../../textModel.js';
16 > import { gotoParent, getClosestPreviousNodes, nextSiblingOrParentSibling, gotoNthChild } from './cursorUtils.js';
17 > import { Range } from '../../../core/range.js';
18 >
19 > export class TreeSitterTree extends Disposable {
20 >
21 > private readonly _tree = observableValue<TreeSitter.Tree | undefined, TreeParseUpdateEvent>(this, undefined);
22 > public readonly tree: IObservableWithChange<TreeSitter.Tree | undefined, TreeParseUpdateEvent> = this._tree;
23 >
24 > private readonly _treeLastParsedVersion = observableValue(this, -1);
25 > public readonly treeLastParsedVersion: IObservable<number> = this._treeLastParsedVersion;
26 >
27 > private _lastFullyParsed: TreeSitter.Tree | undefined;
28 > private _lastFullyParsedWithEdits: TreeSitter.Tree | undefined;
29 >
30 > private _onDidChangeContentQueue: TaskQueue = new TaskQueue();
31 >
32 > constructor(
33 public readonly languageId: string,
34 private _ranges: TreeSitter.Range[] | undefined,
55 this.handleContentChange(undefined, this._ranges);
56 }
58 > public handleContentChange(e: IModelContentChangedEvent | undefined, ranges?: TreeSitter.Range[]): void {
59 const version = this.textModel.getVersionId();
60 let newRanges: TreeSitter.Range[] = [];
102 });
103 }
105 > get ranges(): TreeSitter.Range[] | undefined {
106 return this._ranges;
107 }
109 > public getInjectionTrees(startIndex: number, languageId: string): TreeSitterTree | undefined {
110 // TODO
111 return undefined;
112 }
114 > private _applyEdits(changes: IModelContentChange[]) {
115 for (const change of changes) {
116 const originalTextLength = TextLength.ofRange(Range.lift(change.range));
129 }
130 }
132 > private _findChangedNodes(newTree: TreeSitter.Tree, oldTree: TreeSitter.Tree): TreeSitter.Range[] | undefined {
133 if ((this._ranges && this._ranges.every(range => range.startPosition.row !== newTree.rootNode.startPosition.row)) || newTree.rootNode.startPosition.row !== 0) {
134 return [];
183 return nodes;
184 }
186 > private _findTreeChanges(newTree: TreeSitter.Tree, changedNodes: TreeSitter.Range[], newRanges: TreeSitter.Range[]): RangeChange[] {
187 let newRangeIndex = 0;
188 const mergedChanges: RangeChange[] = [];
259 return this._constrainRanges(mergedChanges);
260 }
262 > private _constrainRanges(changes: RangeChange[]): RangeChange[] {
263 if (!this._ranges) {
264 return changes;
300 return constrainedChanges;
301 }
303 > private async _parseAndUpdateTree(version: number): Promise<TreeSitter.Tree | undefined> {
304 const tree = await this._parse();
305 if (tree) {
317 return undefined;
318 }
320 > private _parse(): Promise<TreeSitter.Tree | undefined> {
321 let parseType: TelemetryParseType = TelemetryParseType.Full;
322 if (this._tree.get()) {
325 return this._parseAndYield(parseType);
326 }
328 > private async _parseAndYield(parseType: TelemetryParseType): Promise<TreeSitter.Tree | undefined> {
329 let time: number = 0;
330 let passes: number = 0;
349 return (newTree && (inProgressVersion === this.textModel.getVersionId())) ? newTree : undefined;
350 }
352 > private _parseCallback(index: number): string | undefined {
353 try {
354 return this.textModel.getTextBuffer().getNearestChunk(index);
358 return undefined;
359 }
361 > private _setRanges(newRanges: TreeSitter.Range[]): TreeSitter.Range[] {
362 const unKnownRanges: TreeSitter.Range[] = [];
363 // If we have existing ranges, find the parts of the new ranges that are not included in the existing ones
387 return unKnownRanges;
388 }
390 > private _sendParseTimeTelemetry(parseType: TelemetryParseType, time: number, passes: number): void {
391 this._logService.debug(`Tree parsing (${parseType}) took ${time} ms and ${passes} passes.`);
392 type ParseTimeClassification = {
403 }
404 }
406 > public createParsedTreeSync(src: string): TreeSitter.Tree | undefined {
407 const parser = new this._parserClass();
408 parser.setLanguage(this._parser.language);
411 return tree ?? undefined;
412 }
414 >
415 > const enum TelemetryParseType {
416 > Full = 'fullParse',
417 > Incremental = 'incrementalParse'
418 > }
419 >
420 > export interface TreeParseUpdateEvent {
421 > ranges: RangeChange[];
422 > versionId: number;
423 > }
424 >
425 > export interface RangeWithOffsets {
426 > range: Range;
427 > startOffset: number;
428 > endOffset: number;
429 > }
430 >
431 > export interface RangeChange {
432 > newRange: Range;
433 > newRangeStartOffset: number;
434 > newRangeEndOffset: number;
435 > }
436 >
437 function newTimeOutProgressCallback(): (state: TreeSitter.ParseState) => void {
438 let lastYieldTime: number = performance.now();
446 };
447 }
448 > export function rangesEqual(a: TreeSitter.Range, b: TreeSitter.Range) { treeSitterTree.ts
449 return (a.startPosition.row === b.startPosition.row)
450 && (a.startPosition.column === b.startPosition.column)
454 && (a.endIndex === b.endIndex);
455 }
457 > export function rangesIntersect(a: TreeSitter.Range, b: TreeSitter.Range) {
458 return (a.startIndex <= b.startIndex && a.endIndex >= b.startIndex) ||
459 (b.startIndex <= a.startIndex && b.endIndex >= a.startIndex);
src/vs/editor/common/services/languageService.ts 85 covered LOC · 24 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageService.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 '../../../base/common/event.js';
7 > import { Disposable, IDisposable } from '../../../base/common/lifecycle.js';
8 > import { URI } from '../../../base/common/uri.js';
9 > import { LanguagesRegistry } from './languagesRegistry.js';
10 > import { ILanguageNameIdPair, ILanguageSelection, ILanguageService, ILanguageIcon, ILanguageExtensionPoint } from '../languages/language.js';
11 > import { ILanguageIdCodec, TokenizationRegistry } from '../languages.js';
12 > import { PLAINTEXT_LANGUAGE_ID } from '../languages/modesRegistry.js';
13 > import { IObservable, observableFromEvent } from '../../../base/common/observable.js';
14 >
15 > export class LanguageService extends Disposable implements ILanguageService {
16 > public _serviceBrand: undefined;
17 >
18 > static instanceCount = 0;
19 >
20 > private readonly _onDidRequestBasicLanguageFeatures = this._register(new Emitter<string>());
21 > public readonly onDidRequestBasicLanguageFeatures = this._onDidRequestBasicLanguageFeatures.event;
22 >
23 > private readonly _onDidRequestRichLanguageFeatures = this._register(new Emitter<string>());
24 > public readonly onDidRequestRichLanguageFeatures = this._onDidRequestRichLanguageFeatures.event;
25 >
26 > protected readonly _onDidChange = this._register(new Emitter<void>({ leakWarningThreshold: 200, leakWarningName: 'LanguageService._onDidChange' /* https://github.com/microsoft/vscode/issues/119968 */ }));
27 > public readonly onDidChange: Event<void> = this._onDidChange.event;
28 >
29 > private readonly _requestedBasicLanguages = new Set<string>();
30 > private readonly _requestedRichLanguages = new Set<string>();
31 >
32 > protected readonly _registry: LanguagesRegistry;
33 > public readonly languageIdCodec: ILanguageIdCodec;
34 >
35 > constructor(warnOnOverwrite = false) {
36 super();
37 LanguageService.instanceCount++;
40 this._register(this._registry.onDidChange(() => this._onDidChange.fire()));
41 }
43 > public override dispose(): void {
44 LanguageService.instanceCount--;
45 super.dispose();
46 }
48 > public registerLanguage(def: ILanguageExtensionPoint): IDisposable {
49 return this._registry.registerLanguage(def);
50 }
52 > public isRegisteredLanguageId(languageId: string | null | undefined): boolean {
53 return this._registry.isRegisteredLanguageId(languageId);
54 }
56 > public getRegisteredLanguageIds(): string[] {
57 return this._registry.getRegisteredLanguageIds();
58 }
60 > public getSortedRegisteredLanguageNames(): ILanguageNameIdPair[] {
61 return this._registry.getSortedRegisteredLanguageNames();
62 }
64 > public getLanguageName(languageId: string): string | null {
65 return this._registry.getLanguageName(languageId);
66 }
68 > public getMimeType(languageId: string): string | null {
69 return this._registry.getMimeType(languageId);
70 }
72 > public getIcon(languageId: string): ILanguageIcon | null {
73 return this._registry.getIcon(languageId);
74 }
76 > public getExtensions(languageId: string): ReadonlyArray<string> {
77 return this._registry.getExtensions(languageId);
78 }
80 > public getFilenames(languageId: string): ReadonlyArray<string> {
81 return this._registry.getFilenames(languageId);
82 }
84 > public getConfigurationFiles(languageId: string): ReadonlyArray<URI> {
85 return this._registry.getConfigurationFiles(languageId);
86 }
88 > public getLanguageIdByLanguageName(languageName: string): string | null {
89 return this._registry.getLanguageIdByLanguageName(languageName);
90 }
92 > public getLanguageIdByMimeType(mimeType: string | null | undefined): string | null {
93 return this._registry.getLanguageIdByMimeType(mimeType);
94 }
96 > public guessLanguageIdByFilepathOrFirstLine(resource: URI | null, firstLine?: string): string | null {
97 const languageIds = this._registry.guessLanguageIdByFilepathOrFirstLine(resource, firstLine);
98 return languageIds.at(0) ?? null;
99 }
101 > public createById(languageId: string | null | undefined): ILanguageSelection {
102 return new LanguageSelection(this.onDidChange, () => {
103 return this._createAndGetLanguageIdentifier(languageId);
104 });
105 }
107 > public createByMimeType(mimeType: string | null | undefined): ILanguageSelection {
108 return new LanguageSelection(this.onDidChange, () => {
109 const languageId = this.getLanguageIdByMimeType(mimeType);
111 });
112 }
114 > public createByFilepathOrFirstLine(resource: URI | null, firstLine?: string): ILanguageSelection {
115 return new LanguageSelection(this.onDidChange, () => {
116 const languageId = this.guessLanguageIdByFilepathOrFirstLine(resource, firstLine);
118 });
119 }
121 > private _createAndGetLanguageIdentifier(languageId: string | null | undefined): string {
122 if (!languageId || !this.isRegisteredLanguageId(languageId)) {
123 // Fall back to plain text if language is unknown
127 return languageId;
128 }
130 > public requestBasicLanguageFeatures(languageId: string): void {
131 if (!this._requestedBasicLanguages.has(languageId)) {
132 this._requestedBasicLanguages.add(languageId);
134 }
135 }
137 > public requestRichLanguageFeatures(languageId: string): void {
138 if (!this._requestedRichLanguages.has(languageId)) {
139 this._requestedRichLanguages.add(languageId);
148 }
149 }
151 >
152 > class LanguageSelection implements ILanguageSelection {
153 > private readonly _value: IObservable<string>;
154 > public readonly onDidChange: Event<string>;
155 >
156 > constructor(onDidChangeLanguages: Event<void>, selector: () => string) {
157 this._value = observableFromEvent(this, onDidChangeLanguages, () => selector());
158 this.onDidChange = Event.fromObservable(this._value);
159 }
161 > public get languageId(): string {
162 return this._value.get();
163 }
src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/brackets.ts 82 covered LOC · 12 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- brackets.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 { escapeRegExpCharacters } from '../../../../../base/common/strings.js';
6 > import { ResolvedLanguageConfiguration } from '../../../languages/languageConfigurationRegistry.js';
7 > import { BracketKind } from '../../../languages/supports/languageBracketsConfiguration.js';
8 > import { BracketAstNode } from './ast.js';
9 > import { toLength } from './length.js';
10 > import { DenseKeyProvider, identityKeyProvider, SmallImmutableSet } from './smallImmutableSet.js';
11 > import { OpeningBracketId, Token, TokenKind } from './tokenizer.js';
12 >
13 > export class BracketTokens {
14 > static createFromLanguage(configuration: ResolvedLanguageConfiguration, denseKeyProvider: DenseKeyProvider<string>): BracketTokens {
15 > function getId(bracketInfo: BracketKind): OpeningBracketId {
16 > return denseKeyProvider.getKey(`${bracketInfo.languageId}:::${bracketInfo.bracketText}`);
17 > }
18 >
19 > const map = new Map<string, Token>();
20 > for (const openingBracket of configuration.bracketsNew.openingBrackets) {
21 > const length = toLength(0, openingBracket.bracketText.length);
22 > const openingTextId = getId(openingBracket);
23 > const bracketIds = SmallImmutableSet.getEmpty().add(openingTextId, identityKeyProvider);
24 > map.set(openingBracket.bracketText, new Token(
25 > length,
26 > TokenKind.OpeningBracket,
27 > openingTextId,
28 > bracketIds,
29 > BracketAstNode.create(length, openingBracket, bracketIds)
30 > ));
31 > }
32 >
33 > for (const closingBracket of configuration.bracketsNew.closingBrackets) {
34 > const length = toLength(0, closingBracket.bracketText.length);
35 > let bracketIds = SmallImmutableSet.getEmpty();
36 > const closingBrackets = closingBracket.getOpeningBrackets();
37 > for (const bracket of closingBrackets) {
38 > bracketIds = bracketIds.add(getId(bracket), identityKeyProvider);
39 > }
40 > map.set(closingBracket.bracketText, new Token(
41 > length,
42 > TokenKind.ClosingBracket,
43 > getId(closingBrackets[0]),
44 > bracketIds,
45 > BracketAstNode.create(length, closingBracket, bracketIds)
46 > ));
47 > }
48 >
49 > return new BracketTokens(map);
50 > }
51 >
52 > private hasRegExp = false;
53 > private _regExpGlobal: RegExp | null = null;
54 >
55 > constructor(
56 private readonly map: Map<string, Token>
57 ) { }
59 > getRegExpStr(): string | null {
60 if (this.isEmpty) {
61 return null;
67 }
68 }
70 > /**
71 > * Returns null if there is no such regexp (because there are no brackets).
72 > */
73 > get regExpGlobal(): RegExp | null {
74 if (!this.hasRegExp) {
75 const regExpStr = this.getRegExpStr();
79 return this._regExpGlobal;
80 }
82 > getToken(value: string): Token | undefined {
83 return this.map.get(value.toLowerCase());
84 }
86 > findClosingTokenText(openingBracketIds: SmallImmutableSet<OpeningBracketId>): string | undefined {
87 for (const [closingText, info] of this.map) {
88 if (info.kind === TokenKind.ClosingBracket && info.bracketIds.intersects(openingBracketIds)) {
92 return undefined;
93 }
95 > get isEmpty(): boolean {
96 return this.map.size === 0;
97 }
98 > } brackets.ts
99 >
100 function prepareBracketForRegExp(str: string): string {
101 let escaped = escapeRegExpCharacters(str);
110 return escaped;
111 }
112 > brackets.ts
113 > export class LanguageAgnosticBracketTokens {
114 > private readonly languageIdToBracketTokens = new Map<string, BracketTokens>();
115 >
116 > constructor(
117 private readonly denseKeyProvider: DenseKeyProvider<string>,
118 private readonly getLanguageConfiguration: (languageId: string) => ResolvedLanguageConfiguration,
119 ) {
120 }
121 > brackets.ts
122 > public didLanguageChange(languageId: string): boolean {
123 // Report a change whenever the language configuration updates.
124 return this.languageIdToBracketTokens.has(languageId);
125 }
126 > brackets.ts
127 > getSingleLanguageBracketTokens(languageId: string): BracketTokens {
128 let singleLanguageBracketTokens = this.languageIdToBracketTokens.get(languageId);
129 if (!singleLanguageBracketTokens) {
133 return singleLanguageBracketTokens;
134 }
135 > brackets.ts
136 > getToken(value: string, languageId: string): Token | undefined {
137 const singleLanguageBracketTokens = this.getSingleLanguageBracketTokens(languageId);
138 return singleLanguageBracketTokens.getToken(value);
139 }
140 > } brackets.ts
src/vs/editor/common/services/languageFeatures.ts 81 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageFeatures.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 { LanguageFeatureRegistry, NotebookInfoResolver } from '../languageFeatureRegistry.js';
7 > import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentDropEditProvider, DocumentPasteEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, MultiDocumentHighlightProvider, NewSymbolNamesProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider } from '../languages.js';
8 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
9 >
10 > export const ILanguageFeaturesService = createDecorator<ILanguageFeaturesService>('ILanguageFeaturesService');
11 >
12 > export interface ILanguageFeaturesService {
13 >
14 > readonly _serviceBrand: undefined;
15 >
16 > readonly referenceProvider: LanguageFeatureRegistry<ReferenceProvider>;
17 >
18 > readonly definitionProvider: LanguageFeatureRegistry<DefinitionProvider>;
19 >
20 > readonly typeDefinitionProvider: LanguageFeatureRegistry<TypeDefinitionProvider>;
21 >
22 > readonly declarationProvider: LanguageFeatureRegistry<DeclarationProvider>;
23 >
24 > readonly implementationProvider: LanguageFeatureRegistry<ImplementationProvider>;
25 >
26 > readonly codeActionProvider: LanguageFeatureRegistry<CodeActionProvider>;
27 >
28 > readonly documentPasteEditProvider: LanguageFeatureRegistry<DocumentPasteEditProvider>;
29 >
30 > readonly renameProvider: LanguageFeatureRegistry<RenameProvider>;
31 >
32 > readonly newSymbolNamesProvider: LanguageFeatureRegistry<NewSymbolNamesProvider>;
33 >
34 > readonly documentFormattingEditProvider: LanguageFeatureRegistry<DocumentFormattingEditProvider>;
35 >
36 > readonly documentRangeFormattingEditProvider: LanguageFeatureRegistry<DocumentRangeFormattingEditProvider>;
37 >
38 > readonly onTypeFormattingEditProvider: LanguageFeatureRegistry<OnTypeFormattingEditProvider>;
39 >
40 > readonly documentSymbolProvider: LanguageFeatureRegistry<DocumentSymbolProvider>;
41 >
42 > readonly inlayHintsProvider: LanguageFeatureRegistry<InlayHintsProvider>;
43 >
44 > readonly colorProvider: LanguageFeatureRegistry<DocumentColorProvider>;
45 >
46 > readonly codeLensProvider: LanguageFeatureRegistry<CodeLensProvider>;
47 >
48 > readonly signatureHelpProvider: LanguageFeatureRegistry<SignatureHelpProvider>;
49 >
50 > readonly hoverProvider: LanguageFeatureRegistry<HoverProvider>;
51 >
52 > readonly documentHighlightProvider: LanguageFeatureRegistry<DocumentHighlightProvider>;
53 >
54 > readonly multiDocumentHighlightProvider: LanguageFeatureRegistry<MultiDocumentHighlightProvider>;
55 >
56 > readonly documentRangeSemanticTokensProvider: LanguageFeatureRegistry<DocumentRangeSemanticTokensProvider>;
57 >
58 > readonly documentSemanticTokensProvider: LanguageFeatureRegistry<DocumentSemanticTokensProvider>;
59 >
60 > readonly selectionRangeProvider: LanguageFeatureRegistry<SelectionRangeProvider>;
61 >
62 > readonly foldingRangeProvider: LanguageFeatureRegistry<FoldingRangeProvider>;
63 >
64 > readonly linkProvider: LanguageFeatureRegistry<LinkProvider>;
65 >
66 > readonly inlineCompletionsProvider: LanguageFeatureRegistry<InlineCompletionsProvider>;
67 >
68 > readonly completionProvider: LanguageFeatureRegistry<CompletionItemProvider>;
69 >
70 > readonly linkedEditingRangeProvider: LanguageFeatureRegistry<LinkedEditingRangeProvider>;
71 >
72 > readonly inlineValuesProvider: LanguageFeatureRegistry<InlineValuesProvider>;
73 >
74 > readonly evaluatableExpressionProvider: LanguageFeatureRegistry<EvaluatableExpressionProvider>;
75 >
76 > readonly documentDropEditProvider: LanguageFeatureRegistry<DocumentDropEditProvider>;
77 >
78 > // --
79 >
80 > setNotebookTypeResolver(resolver: NotebookInfoResolver | undefined): void;
81 > }
src/vs/editor/common/services/languageFeatureDebounce.ts 80 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageFeatureDebounce.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 { doHash } from '../../../base/common/hash.js';
7 > import { LRUCache } from '../../../base/common/map.js';
8 > import { clamp, MovingAverage, SlidingWindowAverage } from '../../../base/common/numbers.js';
9 > import { LanguageFeatureRegistry } from '../languageFeatureRegistry.js';
10 > import { ITextModel } from '../model.js';
11 > import { IEnvironmentService } from '../../../platform/environment/common/environment.js';
12 > import { InstantiationType, registerSingleton } from '../../../platform/instantiation/common/extensions.js';
13 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
14 > import { ILogService } from '../../../platform/log/common/log.js';
15 > import { matchesScheme } from '../../../base/common/network.js';
16 >
17 >
18 > export const ILanguageFeatureDebounceService = createDecorator<ILanguageFeatureDebounceService>('ILanguageFeatureDebounceService');
19 >
20 > export interface ILanguageFeatureDebounceService {
21 >
22 > readonly _serviceBrand: undefined;
23 >
24 > for(feature: LanguageFeatureRegistry<object>, debugName: string, config?: { min?: number; max?: number; salt?: string }): IFeatureDebounceInformation;
25 > }
26 >
27 > export interface IFeatureDebounceInformation {
28 > get(model: ITextModel): number;
29 > update(model: ITextModel, value: number): number;
30 > default(): number;
31 > }
32 >
33 > namespace IdentityHash {
34 > const _hashes = new WeakMap<object, number>();
35 > let pool = 0;
36 > export function of(obj: object): number {
37 let value = _hashes.get(obj);
38 if (value === undefined) {
42 return value;
43 }
45 >
46 > class NullDebounceInformation implements IFeatureDebounceInformation {
47 >
48 > constructor(private readonly _default: number) { }
49 >
50 > get(_model: ITextModel): number {
51 return this._default;
52 }
53 > update(_model: ITextModel, _value: number): number { languageFeatureDebounce.ts
54 return this._default;
55 }
56 > default(): number { languageFeatureDebounce.ts
57 return this._default;
58 }
60 >
61 > class FeatureDebounceInformation implements IFeatureDebounceInformation {
62 >
63 > private readonly _cache = new LRUCache<string, SlidingWindowAverage>(50, 0.7);
64 >
65 > constructor(
66 private readonly _logService: ILogService,
67 private readonly _name: string,
71 private readonly _max: number,
72 ) { }
74 > private _key(model: ITextModel): string {
75 return model.id + this._registry.all(model).reduce((hashVal, obj) => doHash(IdentityHash.of(obj), hashVal), 0);
76 }
78 > get(model: ITextModel): number {
79 const key = this._key(model);
80 const avg = this._cache.get(key);
83 : this.default();
84 }
86 > update(model: ITextModel, value: number): number {
87 const key = this._key(model);
88 let avg = this._cache.get(key);
97 return newValue;
98 }
100 > private _overall(): number {
101 const result = new MovingAverage();
102 for (const [, avg] of this._cache) {
105 return result.value;
106 }
108 > default() {
109 const value = (this._overall() | 0) || this._default;
110 return clamp(value, this._min, this._max);
111 }
113 >
114 >
115 > export class LanguageFeatureDebounceService implements ILanguageFeatureDebounceService {
116 >
117 > declare _serviceBrand: undefined;
118 >
119 > private readonly _data = new Map<string, IFeatureDebounceInformation>();
120 > private readonly _isDev: boolean;
121 >
122 > constructor(
123 @ILogService private readonly _logService: ILogService,
124 @IEnvironmentService envService: IEnvironmentService,
127 this._isDev = envService.isExtensionDevelopment || !envService.isBuilt;
128 }
130 > for(feature: LanguageFeatureRegistry<object>, name: string, config?: { min?: number; max?: number; key?: string }): IFeatureDebounceInformation {
131 const min = config?.min ?? 50;
132 const max = config?.max ?? min ** 2;
152 return info;
153 }
155 > private _overallAverage(): number {
156 // Average of all language features. Not a great value but an approximation
157 const result = new MovingAverage();
161 return result.value;
162 }
164 >
165 > registerSingleton(ILanguageFeatureDebounceService, LanguageFeatureDebounceService, InstantiationType.Delayed);
src/vs/base/common/observableInternal/reactions/autorunImpl.ts 78 covered LOC · 18 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textChange.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 buffer from '../../../base/common/buffer.js';
7 > import { decodeUTF16LE } from './stringBuilder.js';
8 >
9 function escapeNewLine(str: string): string {
10 return (
14 );
15 }
17 > export class TextChange {
18 >
19 > public get oldLength(): number {
20 > return this.oldText.length;
21 > }
22 >
23 > public get oldEnd(): number {
24 return this.oldPosition + this.oldText.length;
25 }
27 > public get newLength(): number {
28 return this.newText.length;
29 }
31 > public get newEnd(): number {
32 return this.newPosition + this.newText.length;
33 }
35 > constructor(
36 public readonly oldPosition: number,
37 public readonly oldText: string,
39 public readonly newText: string
40 ) { }
42 > public toString(): string {
43 if (this.oldText.length === 0) {
44 return `(insert@${this.oldPosition} "${escapeNewLine(this.newText)}")`;
49 return `(replace@${this.oldPosition} "${escapeNewLine(this.oldText)}" with "${escapeNewLine(this.newText)}")`;
50 }
52 > private static _writeStringSize(str: string): number {
53 return (
54 4 + 2 * str.length
55 );
56 }
58 > private static _writeString(b: Uint8Array, str: string, offset: number): number {
59 const len = str.length;
60 buffer.writeUInt32BE(b, len, offset); offset += 4;
64 return offset;
65 }
67 > private static _readString(b: Uint8Array, offset: number): string {
68 const len = buffer.readUInt32BE(b, offset); offset += 4;
69 return decodeUTF16LE(b, offset, len);
70 }
72 > public writeSize(): number {
73 return (
74 + 4 // oldPosition
78 );
79 }
81 > public write(b: Uint8Array, offset: number): number {
82 buffer.writeUInt32BE(b, this.oldPosition, offset); offset += 4;
83 buffer.writeUInt32BE(b, this.newPosition, offset); offset += 4;
86 return offset;
87 }
89 > public static read(b: Uint8Array, offset: number, dest: TextChange[]): number {
90 const oldPosition = buffer.readUInt32BE(b, offset); offset += 4;
91 const newPosition = buffer.readUInt32BE(b, offset); offset += 4;
95 return offset;
96 }
97 > } textChange.ts
98 >
99 > export function compressConsecutiveTextChanges(prevEdits: TextChange[] | null, currEdits: TextChange[]): TextChange[] {
100 if (prevEdits === null || prevEdits.length === 0) {
101 return currEdits;
104 return compressor.compress();
105 }
107 > class TextChangeCompressor {
108 >
109 > private _prevEdits: TextChange[];
110 > private _currEdits: TextChange[];
111 >
112 > private _result: TextChange[];
113 > private _resultLen: number;
114 >
115 > private _prevLen: number;
116 > private _prevDeltaOffset: number;
117 >
118 > private _currLen: number;
119 > private _currDeltaOffset: number;
120 >
121 > constructor(prevEdits: TextChange[], currEdits: TextChange[]) {
122 this._prevEdits = prevEdits;
123 this._currEdits = currEdits;
132 this._currDeltaOffset = 0;
133 }
135 > public compress(): TextChange[] {
136 let prevIndex = 0;
137 let currIndex = 0;
218 return cleaned;
219 }
221 > private _acceptCurr(currEdit: TextChange): void {
222 this._result[this._resultLen++] = TextChangeCompressor._rebaseCurr(this._prevDeltaOffset, currEdit);
223 this._currDeltaOffset += currEdit.newLength - currEdit.oldLength;
224 }
226 > private _getCurr(currIndex: number): TextChange | null {
227 return (currIndex < this._currLen ? this._currEdits[currIndex] : null);
228 }
230 > private _acceptPrev(prevEdit: TextChange): void {
231 this._result[this._resultLen++] = TextChangeCompressor._rebasePrev(this._currDeltaOffset, prevEdit);
232 this._prevDeltaOffset += prevEdit.newLength - prevEdit.oldLength;
233 }
235 > private _getPrev(prevIndex: number): TextChange | null {
236 return (prevIndex < this._prevLen ? this._prevEdits[prevIndex] : null);
237 }
239 > private static _rebaseCurr(prevDeltaOffset: number, currEdit: TextChange): TextChange {
240 return new TextChange(
241 currEdit.oldPosition - prevDeltaOffset,
245 );
246 }
248 > private static _rebasePrev(currDeltaOffset: number, prevEdit: TextChange): TextChange {
249 return new TextChange(
250 prevEdit.oldPosition,
254 );
255 }
257 > private static _splitPrev(edit: TextChange, offset: number): [TextChange, TextChange] {
258 const preText = edit.newText.substr(0, offset);
259 const postText = edit.newText.substr(offset);
274 ];
275 }
277 > private static _splitCurr(edit: TextChange, offset: number): [TextChange, TextChange] {
278 const preText = edit.oldText.substr(0, offset);
279 const postText = edit.oldText.substr(offset);
294 ];
295 }
297 > private static _merge(edits: TextChange[]): TextChange[] {
298 if (edits.length === 0) {
299 return edits;
324 return result;
325 }
327 > private static _removeNoOps(edits: TextChange[]): TextChange[] {
328 if (edits.length === 0) {
329 return edits;
src/vs/platform/instantiation/test/common/instantiationServiceMock.ts 78 covered LOC · 18 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- instantiationServiceMock.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 sinon from 'sinon';
7 > import { DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
8 > import { SyncDescriptor, SyncDescriptor0 } from '../../common/descriptors.js';
9 > import { GetLeadingNonServiceArgs, ServiceIdentifier, ServicesAccessor } from '../../common/instantiation.js';
10 > import { InstantiationService, Trace } from '../../common/instantiationService.js';
11 > import { ServiceCollection } from '../../common/serviceCollection.js';
12 >
13 > interface IServiceMock<T> {
14 > id: ServiceIdentifier<T>;
15 > service: any;
16 > }
17 >
18 > const isSinonSpyLike = (fn: Function): fn is sinon.SinonSpy => fn && 'callCount' in fn;
19 >
20 > export class TestInstantiationService extends InstantiationService implements IDisposable, ServicesAccessor {
21 >
22 > private _servciesMap: Map<ServiceIdentifier<any>, any>;
23 > private readonly _classStubs: Map<Function, any> = new Map();
24 > private readonly _parentTestService: TestInstantiationService | undefined;
25 >
26 > constructor(private _serviceCollection: ServiceCollection = new ServiceCollection(), strict: boolean = false, parent?: InstantiationService, private _properDispose?: boolean) {
27 super(_serviceCollection, strict, parent);
28
32 }
33 }
35 > public get<T>(service: ServiceIdentifier<T>): T {
36 return super._getOrCreateServiceInstance(service, Trace.traceCreation(false, TestInstantiationService));
37 }
39 > public set<T>(service: ServiceIdentifier<T>, instance: T): T {
40 return <T>this._serviceCollection.set(service, instance);
41 }
43 > public mock<T>(service: ServiceIdentifier<T>): T | sinon.SinonMock {
44 return <T>this._create(service, { mock: true });
45 }
47 > public stubInstance<T>(ctor: new (...args: any[]) => T, instance: Partial<T>): void {
48 this._classStubs.set(ctor, instance);
49 }
51 > protected _getClassStub(ctor: Function): unknown {
52 return this._classStubs.get(ctor) ?? this._parentTestService?._getClassStub(ctor);
53 }
55 > public override createInstance<T>(descriptor: SyncDescriptor0<T>): T;
56 > public override createInstance<Ctor extends new (...args: any[]) => unknown, R extends InstanceType<Ctor>>(ctor: Ctor, ...args: GetLeadingNonServiceArgs<ConstructorParameters<Ctor>>): R;
57 > public override createInstance(ctorOrDescriptor: any | SyncDescriptor<any>, ...rest: unknown[]): unknown {
58 const stub = this._getClassStub(ctorOrDescriptor as Function);
59 if (stub) {
62 return super.createInstance(ctorOrDescriptor, ...rest);
63 }
65 > public stub<T>(service: ServiceIdentifier<T>, obj: Partial<NoInfer<T>> | Function): T;
66 > public stub<T, V>(service: ServiceIdentifier<T>, obj: Partial<NoInfer<T>> | Function, property: string, value: V): V extends Function ? sinon.SinonSpy : sinon.SinonStub;
67 > public stub<T, V>(service: ServiceIdentifier<T>, property: string, value: V): V extends Function ? sinon.SinonSpy : sinon.SinonStub;
68 > public stub<T>(serviceIdentifier: ServiceIdentifier<T>, arg2: any, arg3?: string, arg4?: any): sinon.SinonStub | sinon.SinonSpy {
69 const service = typeof arg2 !== 'string' ? arg2 : undefined;
70 const serviceMock: IServiceMock<any> = { id: serviceIdentifier, service: service };
93 return stubObject;
94 }
96 > public stubPromise<T>(service?: ServiceIdentifier<T>, fnProperty?: string, value?: any): T | sinon.SinonStub;
97 > public stubPromise<T, V>(service?: ServiceIdentifier<T>, ctor?: any, fnProperty?: string, value?: V): V extends Function ? sinon.SinonSpy : sinon.SinonStub;
98 > public stubPromise<T, V>(service?: ServiceIdentifier<T>, obj?: any, fnProperty?: string, value?: V): V extends Function ? sinon.SinonSpy : sinon.SinonStub;
99 > public stubPromise(arg1?: any, arg2?: any, arg3?: any, arg4?: any): sinon.SinonStub | sinon.SinonSpy {
100 arg3 = typeof arg2 === 'string' ? Promise.resolve(arg3) : arg3;
101 arg4 = typeof arg2 !== 'string' && typeof arg3 === 'string' ? Promise.resolve(arg4) : arg4;
102 return this.stub(arg1, arg2, arg3, arg4);
103 }
105 > public spy<T>(service: ServiceIdentifier<T>, fnProperty: string): sinon.SinonSpy {
106 const spy = sinon.spy();
107 this.stub(service, fnProperty, spy);
108 return spy;
109 }
111 > private _create<T>(serviceMock: IServiceMock<T>, options: SinonOptions, reset?: boolean): any;
112 > private _create<T>(ctor: any, options: SinonOptions): any;
113 > private _create(arg1: any, options: SinonOptions, reset: boolean = false): any {
114 if (this.isServiceMock(arg1)) {
115 const service = this._getOrCreateService(arg1, options, reset);
119 return options.mock ? sinon.mock(arg1) : this._createStub(arg1);
120 }
122 > private _getOrCreateService<T>(serviceMock: IServiceMock<T>, opts: SinonOptions, reset?: boolean): any {
123 const service: any = this._serviceCollection.get(serviceMock.id);
124 if (!reset && service) {
132 return this._createService(serviceMock, opts);
133 }
135 > private _createService(serviceMock: IServiceMock<any>, opts: SinonOptions): any {
136 serviceMock.service = serviceMock.service ? serviceMock.service : this._servciesMap.get(serviceMock.id);
137 const service = opts.mock ? sinon.mock(serviceMock.service) : this._createStub(serviceMock.service);
139 return service;
140 }
142 > private _createStub(arg: any): any {
143 return typeof arg === 'object' ? arg : sinon.createStubInstance(arg);
144 }
146 > private isServiceMock(arg1: any): boolean {
147 return typeof arg1 === 'object' && arg1.hasOwnProperty('id');
148 }
150 > override createChild(services: ServiceCollection): TestInstantiationService {
151 return new TestInstantiationService(services, false, this);
152 }
154 > override dispose() {
155 sinon.restore();
156 if (this._properDispose) {
158 }
159 }
161 >
162 > interface SinonOptions {
163 > mock?: boolean;
164 > stub?: boolean;
165 > }
166 >
167 > export type ServiceIdCtorPair<T> = [id: ServiceIdentifier<T>, ctorOrInstance: T | (new (...args: any[]) => T)];
168 >
169 > export function createServices(disposables: DisposableStore, services: ServiceIdCtorPair<any>[]): TestInstantiationService {
170 const serviceIdentifiers: ServiceIdentifier<any>[] = [];
171 const serviceCollection = new ServiceCollection();
src/vs/editor/common/languages/modesRegistry.ts 77 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- modesRegistry.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 > import { Emitter, Event } from '../../../base/common/event.js';
8 > import { ILanguageExtensionPoint } from './language.js';
9 > import { Registry } from '../../../platform/registry/common/platform.js';
10 > import { Disposable, IDisposable } from '../../../base/common/lifecycle.js';
11 > import { Mimes } from '../../../base/common/mime.js';
12 > import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from '../../../platform/configuration/common/configurationRegistry.js';
13 >
14 > // Define extension point ids
15 > export const Extensions = {
16 > ModesRegistry: 'editor.modesRegistry'
17 > };
18 >
19 > export class EditorModesRegistry extends Disposable {
20 >
21 > private readonly _languages: ILanguageExtensionPoint[];
22 >
23 > private readonly _onDidChangeLanguages = this._register(new Emitter<void>());
24 > public readonly onDidChangeLanguages: Event<void> = this._onDidChangeLanguages.event;
25 >
26 > constructor() {
27 > super();
28 > this._languages = [];
29 > }
30 >
31 > public registerLanguage(def: ILanguageExtensionPoint): IDisposable {
32 > this._languages.push(def);
33 > this._onDidChangeLanguages.fire(undefined);
34 > return {
35 > dispose: () => {
36 for (let i = 0, len = this._languages.length; i < len; i++) {
37 if (this._languages[i] === def) {
41 }
42 }
44 > }
45 >
46 > public getLanguages(): ReadonlyArray<ILanguageExtensionPoint> {
47 return this._languages;
48 }
50 >
51 > export const ModesRegistry = new EditorModesRegistry();
52 > Registry.add(Extensions.ModesRegistry, ModesRegistry);
53 >
54 > export const PLAINTEXT_LANGUAGE_ID = 'plaintext';
55 > export const PLAINTEXT_EXTENSION = '.txt';
56 >
57 > ModesRegistry.registerLanguage({
58 > id: PLAINTEXT_LANGUAGE_ID,
59 > extensions: [PLAINTEXT_EXTENSION],
60 > aliases: [nls.localize('plainText.alias', "Plain Text"), 'text'],
61 > mimetypes: [Mimes.text]
62 > });
63 >
64 > Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
65 > .registerDefaultConfigurations([{
66 > overrides: {
67 > '[plaintext]': {
68 > 'editor.unicodeHighlight.ambiguousCharacters': false,
69 > 'editor.unicodeHighlight.invisibleCharacters': false
70 > },
71 > // TODO: Below is a workaround for: https://github.com/microsoft/vscode/issues/240567
72 > '[go]': {
73 > 'editor.insertSpaces': false
74 > },
75 > '[makefile]': {
76 > 'editor.insertSpaces': false,
77 > },
78 > '[shellscript]': {
79 > 'files.eol': '\n'
80 > },
81 > '[yaml]': {
82 > 'editor.insertSpaces': true,
83 > 'editor.tabSize': 2
84 > }
85 > }
86 > }]);
src/vs/editor/common/services/languagesAssociations.ts 77 covered LOC · 11 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languagesAssociations.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 { ParsedPattern, parse } from '../../../base/common/glob.js';
7 > import { Mimes } from '../../../base/common/mime.js';
8 > import { Schemas } from '../../../base/common/network.js';
9 > import { basename, posix } from '../../../base/common/path.js';
10 > import { DataUri } from '../../../base/common/resources.js';
11 > import { endsWithIgnoreCase, equals, startsWithUTF8BOM } from '../../../base/common/strings.js';
12 > import { URI } from '../../../base/common/uri.js';
13 > import { PLAINTEXT_LANGUAGE_ID } from '../languages/modesRegistry.js';
14 >
15 > export interface ILanguageAssociation {
16 > readonly id: string;
17 > readonly mime: string;
18 > readonly filename?: string;
19 > readonly extension?: string;
20 > readonly filepattern?: string;
21 > readonly firstline?: RegExp;
22 > }
23 >
24 > interface ILanguageAssociationItem extends ILanguageAssociation {
25 > readonly userConfigured: boolean;
26 > readonly filepatternParsed?: ParsedPattern;
27 > readonly filepatternOnPath?: boolean;
28 > }
29 >
30 > let registeredAssociations: ILanguageAssociationItem[] = [];
31 > let nonUserRegisteredAssociations: ILanguageAssociationItem[] = [];
32 > let userRegisteredAssociations: ILanguageAssociationItem[] = [];
33 >
34 > /**
35 > * Associate a language to the registry (platform).
36 > * * **NOTE**: This association will lose over associations registered using `registerConfiguredLanguageAssociation`.
37 > * * **NOTE**: Use `clearPlatformLanguageAssociations` to remove all associations registered using this function.
38 > */
39 > export function registerPlatformLanguageAssociation(association: ILanguageAssociation, warnOnOverwrite = false): void {
40 _registerLanguageAssociation(association, false, warnOnOverwrite);
41 }
43 > /**
44 > * Associate a language to the registry (configured).
45 > * * **NOTE**: This association will win over associations registered using `registerPlatformLanguageAssociation`.
46 > * * **NOTE**: Use `clearConfiguredLanguageAssociations` to remove all associations registered using this function.
47 > */
48 > export function registerConfiguredLanguageAssociation(association: ILanguageAssociation): void {
49 _registerLanguageAssociation(association, true, false);
50 }
52 function _registerLanguageAssociation(association: ILanguageAssociation, userConfigured: boolean, warnOnOverwrite: boolean): void {
53
86 }
87 }
89 function toLanguageAssociationItem(association: ILanguageAssociation, userConfigured: boolean): ILanguageAssociationItem {
90 return {
100 };
101 }
103 > /**
104 > * Clear language associations from the registry (platform).
105 > */
106 > export function clearPlatformLanguageAssociations(): void {
107 registeredAssociations = registeredAssociations.filter(a => a.userConfigured);
108 nonUserRegisteredAssociations = [];
109 }
111 > /**
112 > * Clear language associations from the registry (configured).
113 > */
114 > export function clearConfiguredLanguageAssociations(): void {
115 registeredAssociations = registeredAssociations.filter(a => !a.userConfigured);
116 userRegisteredAssociations = [];
117 }
119 > interface IdAndMime {
120 > id: string;
121 > mime: string;
122 > }
123 >
124 > /**
125 > * Given a file, return the best matching mime types for it
126 > * based on the registered language associations.
127 > */
128 > export function getMimeTypes(resource: URI | null, firstLine?: string): string[] {
129 return getAssociations(resource, firstLine).map(item => item.mime);
130 }
132 > /**
133 > * @see `getMimeTypes`
134 > */
135 > export function getLanguageIds(resource: URI | null, firstLine?: string): string[] {
136 return getAssociations(resource, firstLine).map(item => item.id);
137 }
139 function getAssociations(resource: URI | null, firstLine?: string): IdAndMime[] {
140 let path: string | undefined;
188 return [{ id: 'unknown', mime: Mimes.unknown }];
189 }
191 function getAssociationByPath(path: string, filename: string, associations: ILanguageAssociationItem[]): ILanguageAssociationItem | undefined {
192 let filenameMatch: ILanguageAssociationItem | undefined = undefined;
242 return undefined;
243 }
245 function getAssociationByFirstline(firstLine: string): ILanguageAssociationItem | undefined {
246 if (startsWithUTF8BOM(firstLine)) {
src/vs/base/common/observableInternal/logging/debugGetDependencyGraph.ts 75 covered LOC · 10 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tokenizerSyntaxTokenBackend.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 { onUnexpectedError } from '../../../../base/common/errors.js';
7 > import { Emitter, Event } from '../../../../base/common/event.js';
8 > import { MutableDisposable, DisposableMap } from '../../../../base/common/lifecycle.js';
9 > import { countEOL } from '../../core/misc/eolCounter.js';
10 > import { Position } from '../../core/position.js';
11 > import { LineRange } from '../../core/ranges/lineRange.js';
12 > import { StandardTokenType } from '../../encodedTokenAttributes.js';
13 > import { IBackgroundTokenizer, IState, ILanguageIdCodec, TokenizationRegistry, ITokenizationSupport, IBackgroundTokenizationStore } from '../../languages.js';
14 > import { IAttachedView } from '../../model.js';
15 > import { FontTokensUpdate, IModelContentChangedEvent } from '../../textModelEvents.js';
16 > import { BackgroundTokenizationState } from '../../tokenizationTextModelPart.js';
17 > import { ContiguousMultilineTokens } from '../../tokens/contiguousMultilineTokens.js';
18 > import { ContiguousMultilineTokensBuilder } from '../../tokens/contiguousMultilineTokensBuilder.js';
19 > import { ContiguousTokensStore } from '../../tokens/contiguousTokensStore.js';
20 > import { LineTokens } from '../../tokens/lineTokens.js';
21 > import { TextModel } from '../textModel.js';
22 > import { TokenizerWithStateStoreAndTextModel, DefaultBackgroundTokenizer, TrackingTokenizationStateStore } from '../textModelTokens.js';
23 > import { AbstractSyntaxTokenBackend, AttachedViewHandler, AttachedViews } from './abstractSyntaxTokenBackend.js';
24 >
25 > /** For TextMate */
26 > export class TokenizerSyntaxTokenBackend extends AbstractSyntaxTokenBackend {
27 > private _tokenizer: TokenizerWithStateStoreAndTextModel | null = null;
28 > protected _backgroundTokenizationState: BackgroundTokenizationState = BackgroundTokenizationState.InProgress;
29 > protected readonly _onDidChangeBackgroundTokenizationState: Emitter<void> = this._register(new Emitter<void>());
30 > public readonly onDidChangeBackgroundTokenizationState: Event<void> = this._onDidChangeBackgroundTokenizationState.event;
31 >
32 > private _defaultBackgroundTokenizer: DefaultBackgroundTokenizer | null = null;
33 > private readonly _backgroundTokenizer = this._register(new MutableDisposable<IBackgroundTokenizer>());
34 >
35 > private readonly _tokens = new ContiguousTokensStore(this._languageIdCodec);
36 > private _debugBackgroundTokens: ContiguousTokensStore | undefined;
37 > private _debugBackgroundStates: TrackingTokenizationStateStore<IState> | undefined;
38 >
39 > private readonly _debugBackgroundTokenizer = this._register(new MutableDisposable<IBackgroundTokenizer>());
40 >
41 > private readonly _attachedViewStates = this._register(new DisposableMap<IAttachedView, AttachedViewHandler>());
42 >
43 > constructor(
44 languageIdCodec: ILanguageIdCodec,
45 textModel: TextModel,
72 }));
73 }
75 > public todo_resetTokenization(fireTokenChangeEvent: boolean = true): void {
76 this._tokens.flush();
77 this._debugBackgroundTokens?.flush();
182 this.refreshAllVisibleLineTokens();
183 }
185 > public handleDidChangeAttached() {
186 this._defaultBackgroundTokenizer?.handleChanges();
187 }
189 > public handleDidChangeContent(e: IModelContentChangedEvent): void {
190 if (e.isFlush) {
191 // Don't fire the event, as the view might not have got the text change event yet
206 }
207 }
209 > private setTokens(tokens: ContiguousMultilineTokens[]): { changes: { fromLineNumber: number; toLineNumber: number }[] } {
210 const { changes } = this._tokens.setMultilineTokens(tokens, this._textModel);
211
216 return { changes: changes };
217 }
219 > private setFontInfo(changes: FontTokensUpdate): void {
220 this._onDidChangeFontTokens.fire({ changes });
221 }
223 > private refreshAllVisibleLineTokens(): void {
224 const ranges = LineRange.joinMany([...this._attachedViewStates].map(([_, s]) => s.lineRanges));
225 this.refreshRanges(ranges);
226 }
228 > private refreshRanges(ranges: readonly LineRange[]): void {
229 for (const range of ranges) {
230 this.refreshRange(range.startLineNumber, range.endLineNumberExclusive - 1);
231 }
232 }
234 > private refreshRange(startLineNumber: number, endLineNumber: number): void {
235 if (!this._tokenizer) {
236 return;
255 this._defaultBackgroundTokenizer?.checkFinished();
256 }
258 > public forceTokenization(lineNumber: number): void {
259 const builder = new ContiguousMultilineTokensBuilder();
260 this._tokenizer?.updateTokensUntilLine(builder, lineNumber);
262 this._defaultBackgroundTokenizer?.checkFinished();
263 }
265 > public hasAccurateTokensForLine(lineNumber: number): boolean {
266 if (!this._tokenizer) {
267 return true;
269 return this._tokenizer.hasAccurateTokensForLine(lineNumber);
270 }
272 > public isCheapToTokenize(lineNumber: number): boolean {
273 if (!this._tokenizer) {
274 return true;
276 return this._tokenizer.isCheapToTokenize(lineNumber);
277 }
279 > public getLineTokens(lineNumber: number): LineTokens {
280 const lineText = this._textModel.getLineContent(lineNumber);
281 const result = this._tokens.getTokens(
298 return result;
299 }
301 > public getTokenTypeIfInsertingCharacter(lineNumber: number, column: number, character: string): StandardTokenType {
302 if (!this._tokenizer) {
303 return StandardTokenType.Other;
308 return this._tokenizer.getTokenTypeIfInsertingCharacter(position, character);
309 }
311 >
312 > public tokenizeLinesAt(lineNumber: number, lines: string[]): LineTokens[] | null {
313 if (!this._tokenizer) {
314 return null;
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 71 covered LOC · 19 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;
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/cursorColumns.ts 70 covered LOC · 9 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- cursorColumns.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 >
9 > /**
10 > * A column in a position is the gap between two adjacent characters. The methods here
11 > * work with a concept called "visible column". A visible column is a very rough approximation
12 > * of the horizontal screen position of a column. For example, using a tab size of 4:
13 > * ```txt
14 > * |<TAB>|<TAB>|T|ext
15 > * | | | \---- column = 4, visible column = 9
16 > * | | \------ column = 3, visible column = 8
17 > * | \------------ column = 2, visible column = 4
18 > * \------------------ column = 1, visible column = 0
19 > * ```
20 > *
21 > * **NOTE**: Visual columns do not work well for RTL text or variable-width fonts or characters.
22 > *
23 > * **NOTE**: These methods work and make sense both on the model and on the view model.
24 > */
25 > export class CursorColumns {
26 >
27 > private static _nextVisibleColumn(codePoint: number, visibleColumn: number, tabSize: number): number {
28 if (codePoint === CharCode.Tab) {
29 return CursorColumns.nextRenderTabStop(visibleColumn, tabSize);
34 return visibleColumn + 1;
35 }
37 > /**
38 > * Returns a visible column from a column.
39 > * @see {@link CursorColumns}
40 > */
41 > public static visibleColumnFromColumn(lineContent: string, column: number, tabSize: number): number {
42 const textLen = Math.min(column - 1, lineContent.length);
43 const text = lineContent.substring(0, textLen);
54 return result;
55 }
57 > /**
58 > * Returns the value to display as "Col" in the status bar.
59 > * @see {@link CursorColumns}
60 > */
61 > public static toStatusbarColumn(lineContent: string, column: number, tabSize: number): number {
62 const text = lineContent.substring(0, Math.min(column - 1, lineContent.length));
63 const iterator = new strings.CodePointIterator(text);
76 return result + 1;
77 }
79 > /**
80 > * Returns a column from a visible column.
81 > * @see {@link CursorColumns}
82 > */
83 > public static columnFromVisibleColumn(lineContent: string, visibleColumn: number, tabSize: number): number {
84 if (visibleColumn <= 0) {
85 return 1;
115 return lineContentLength + 1;
116 }
118 > /**
119 > * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
120 > * @see {@link CursorColumns}
121 > */
122 > public static nextRenderTabStop(visibleColumn: number, tabSize: number): number {
123 return visibleColumn + tabSize - visibleColumn % tabSize;
124 }
126 > /**
127 > * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
128 > * @see {@link CursorColumns}
129 > */
130 > public static nextIndentTabStop(visibleColumn: number, indentSize: number): number {
131 return CursorColumns.nextRenderTabStop(visibleColumn, indentSize);
132 }
134 > /**
135 > * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
136 > * @see {@link CursorColumns}
137 > */
138 > public static prevRenderTabStop(column: number, tabSize: number): number {
139 return Math.max(0, column - 1 - (column - 1) % tabSize);
140 }
142 > /**
143 > * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
144 > * @see {@link CursorColumns}
145 > */
146 > public static prevIndentTabStop(column: number, indentSize: number): number {
147 return CursorColumns.prevRenderTabStop(column, indentSize);
148 }
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/editor/common/languages/supports/languageBracketsConfiguration.ts 69 covered LOC · 16 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageBracketsConfiguration.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 { CachedFunction } from '../../../../base/common/cache.js';
7 > import { RegExpOptions } from '../../../../base/common/strings.js';
8 > import { LanguageConfiguration } from '../languageConfiguration.js';
9 > import { createBracketOrRegExp } from './richEditBrackets.js';
10 >
11 > /**
12 > * Captures all bracket related configurations for a single language.
13 > * Immutable.
14 > */
15 > export class LanguageBracketsConfiguration {
16 > private readonly _openingBrackets: ReadonlyMap<string, OpeningBracketKind>;
17 > private readonly _closingBrackets: ReadonlyMap<string, ClosingBracketKind>;
18 >
19 > constructor(
20 public readonly languageId: string,
21 config: LanguageConfiguration,
68 this._closingBrackets = new Map([...closingBracketInfos.cachedValues].map(([k, v]) => [k, v.info]));
69 }
71 > /**
72 > * No two brackets have the same bracket text.
73 > */
74 > public get openingBrackets(): readonly OpeningBracketKind[] {
75 return [...this._openingBrackets.values()];
76 }
78 > /**
79 > * No two brackets have the same bracket text.
80 > */
81 > public get closingBrackets(): readonly ClosingBracketKind[] {
82 return [...this._closingBrackets.values()];
83 }
85 > public getOpeningBracketInfo(bracketText: string): OpeningBracketKind | undefined {
86 return this._openingBrackets.get(bracketText);
87 }
89 > public getClosingBracketInfo(bracketText: string): ClosingBracketKind | undefined {
90 return this._closingBrackets.get(bracketText);
91 }
93 > public getBracketInfo(bracketText: string): BracketKind | undefined {
94 return this.getOpeningBracketInfo(bracketText) || this.getClosingBracketInfo(bracketText);
95 }
97 > public getBracketRegExp(options?: RegExpOptions): RegExp {
98 const brackets = Array.from([...this._openingBrackets.keys(), ...this._closingBrackets.keys()]);
99 return createBracketOrRegExp(brackets, options);
100 }
102 >
103 function filterValidBrackets(bracketPairs: [string, string][]): [string, string][] {
104 return bracketPairs.filter(([open, close]) => open !== '' && close !== '');
105 }
107 > export type BracketKind = OpeningBracketKind | ClosingBracketKind;
108 >
109 > export class BracketKindBase {
110 > constructor(
111 protected readonly config: LanguageBracketsConfiguration,
112 public readonly bracketText: string,
113 ) { }
115 > public get languageId(): string {
116 return this.config.languageId;
117 }
119 >
120 > export class OpeningBracketKind extends BracketKindBase {
121 > public readonly isOpeningBracket = true;
122 >
123 > constructor(
124 config: LanguageBracketsConfiguration,
125 bracketText: string,
128 super(config, bracketText);
129 }
131 >
132 > export class ClosingBracketKind extends BracketKindBase {
133 > public readonly isOpeningBracket = false;
134 >
135 > constructor(
136 config: LanguageBracketsConfiguration,
137 bracketText: string,
144 super(config, bracketText);
145 }
147 > /**
148 > * Checks if this bracket closes the given other bracket.
149 > * If the bracket infos come from different configurations, this method will return false.
150 > */
151 > public closes(other: OpeningBracketKind): boolean {
152 if (other['config'] !== this.config) {
153 return false;
155 return this.openingBrackets.has(other);
156 }
158 > public closesColorized(other: OpeningBracketKind): boolean {
159 if (other['config'] !== this.config) {
160 return false;
src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/smallImmutableSet.ts 69 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- smallImmutableSet.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 > const emptyArr: number[] = [];
7 >
8 > /**
9 > * Represents an immutable set that works best for a small number of elements (less than 32).
10 > * It uses bits to encode element membership efficiently.
11 > */
12 > export class SmallImmutableSet<T> {
13 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
14 > private static cache = new Array<SmallImmutableSet<any>>(129);
15 >
16 > private static create<T>(items: number, additionalItems: readonly number[]): SmallImmutableSet<T> {
17 > if (items <= 128 && additionalItems.length === 0) {
18 > // We create a cache of 128=2^7 elements to cover all sets with up to 7 (dense) elements.
19 > let cached = SmallImmutableSet.cache[items];
20 > if (!cached) {
21 > cached = new SmallImmutableSet(items, additionalItems);
22 > SmallImmutableSet.cache[items] = cached;
23 > }
24 > return cached;
25 > }
26
27 return new SmallImmutableSet(items, additionalItems);
29 >
30 > // eslint-disable-next-line @typescript-eslint/no-explicit-any
31 > private static empty = SmallImmutableSet.create<any>(0, emptyArr);
32 > public static getEmpty<T>(): SmallImmutableSet<T> {
33 return this.empty;
34 }
36 > private constructor(
37 > private readonly items: number,
38 > private readonly additionalItems: readonly number[]
39 > ) {
40 > }
41 >
42 > public add(value: T, keyProvider: IDenseKeyProvider<T>): SmallImmutableSet<T> {
43 const key = keyProvider.getKey(value);
44 let idx = key >> 5; // divided by 32
61 return SmallImmutableSet.create(this.items, newItems);
62 }
64 > public has(value: T, keyProvider: IDenseKeyProvider<T>): boolean {
65 const key = keyProvider.getKey(value);
66 let idx = key >> 5; // divided by 32
73 return ((this.additionalItems[idx] || 0) & (1 << (key & 31))) !== 0;
74 }
76 > public merge(other: SmallImmutableSet<T>): SmallImmutableSet<T> {
77 const merged = this.items | other.items;
78
98 return SmallImmutableSet.create(merged, newItems);
99 }
101 > public intersects(other: SmallImmutableSet<T>): boolean {
102 if ((this.items & other.items) !== 0) {
103 return true;
112 return false;
113 }
115 > public equals(other: SmallImmutableSet<T>): boolean {
116 if (this.items !== other.items) {
117 return false;
130 return true;
131 }
133 >
134 > export interface IDenseKeyProvider<T> {
135 > getKey(value: T): number;
136 > }
137 >
138 > export const identityKeyProvider: IDenseKeyProvider<number> = {
139 > getKey(value: number) {
140 return value;
141 }
143 >
144 > /**
145 > * Assigns values a unique incrementing key.
146 > */
147 > export class DenseKeyProvider<T> {
148 private readonly items = new Map<T, number>();
150 > getKey(value: T): number {
151 let existing = this.items.get(value);
152 if (existing === undefined) {
156 return existing;
157 }
159 > reverseLookup(value: number): T | undefined {
160 return [...this.items].find(([_key, v]) => v === value)?.[0];
161 }
163 > reverseLookupSet(set: SmallImmutableSet<T>): T[] {
164 const result: T[] = [];
165 for (const [key] of this.items) {
src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/beforeEditPositionMapper.ts 68 covered LOC · 11 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- beforeEditPositionMapper.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 { Range } from '../../../core/range.js';
7 > import { Length, lengthAdd, lengthDiffNonNegative, lengthLessThanEqual, lengthOfString, lengthToObj, positionToLength, toLength } from './length.js';
8 > import { TextLength } from '../../../core/text/textLength.js';
9 > import { IModelContentChange } from '../../mirrorTextModel.js';
10 >
11 > export class TextEditInfo {
12 > public static fromModelContentChanges(changes: IModelContentChange[]): TextEditInfo[] {
13 > // Must be sorted in ascending order
14 > const edits = changes.map(c => {
15 > const range = Range.lift(c.range);
16 > return new TextEditInfo(
17 > positionToLength(range.getStartPosition()),
18 > positionToLength(range.getEndPosition()),
19 > lengthOfString(c.text)
20 > );
21 > }).reverse();
22 > return edits;
23 > }
24 >
25 > constructor(
26 public readonly startOffset: Length,
27 public readonly endOffset: Length,
29 ) {
30 }
32 > toString(): string {
33 return `[${lengthToObj(this.startOffset)}...${lengthToObj(this.endOffset)}) -> ${lengthToObj(this.newLength)}`;
34 }
36 >
37 > export class BeforeEditPositionMapper {
38 > private nextEditIdx = 0;
39 > private deltaOldToNewLineCount = 0;
40 > private deltaOldToNewColumnCount = 0;
41 > private deltaLineIdxInOld = -1;
42 > private readonly edits: readonly TextEditInfoCache[];
43 >
44 > /**
45 > * @param edits Must be sorted by offset in ascending order.
46 > */
47 > constructor(
48 edits: readonly TextEditInfo[],
49 ) {
50 this.edits = edits.map(edit => TextEditInfoCache.from(edit));
51 }
53 > /**
54 > * @param offset Must be equal to or greater than the last offset this method has been called with.
55 > */
56 > getOffsetBeforeChange(offset: Length): Length {
57 this.adjustNextEdit(offset);
58 return this.translateCurToOld(offset);
59 }
61 > /**
62 > * @param offset Must be equal to or greater than the last offset this method has been called with.
63 > * Returns null if there is no edit anymore.
64 > */
65 > getDistanceToNextChange(offset: Length): Length | null {
66 this.adjustNextEdit(offset);
67
74 return lengthDiffNonNegative(offset, nextChangeOffset);
75 }
77 > private translateOldToCur(oldOffsetObj: TextLength): Length {
78 if (oldOffsetObj.lineCount === this.deltaLineIdxInOld) {
79 return toLength(oldOffsetObj.lineCount + this.deltaOldToNewLineCount, oldOffsetObj.columnCount + this.deltaOldToNewColumnCount);
82 }
83 }
85 > private translateCurToOld(newOffset: Length): Length {
86 const offsetObj = lengthToObj(newOffset);
87 if (offsetObj.lineCount - this.deltaOldToNewLineCount === this.deltaLineIdxInOld) {
91 }
92 }
94 > private adjustNextEdit(offset: Length) {
95 while (this.nextEditIdx < this.edits.length) {
96 const nextEdit = this.edits[this.nextEditIdx];
121 }
122 }
124 >
125 > class TextEditInfoCache {
126 > static from(edit: TextEditInfo): TextEditInfoCache {
127 return new TextEditInfoCache(edit.startOffset, edit.endOffset, edit.newLength);
128 }
130 > public readonly endOffsetBeforeObj: TextLength;
131 > public readonly endOffsetAfterObj: TextLength;
132 > public readonly offsetObj: TextLength;
133 >
134 > constructor(
135 startOffset: Length,
136 endOffset: Length,
src/vs/editor/common/tokens/contiguousMultilineTokens.ts 68 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- contiguousMultilineTokens.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as arrays from '../../../base/common/arrays.js';
7 > import { readUInt32BE, writeUInt32BE } from '../../../base/common/buffer.js';
8 > import { Position } from '../core/position.js';
9 > import { IRange } from '../core/range.js';
10 > import { countEOL } from '../core/misc/eolCounter.js';
11 > import { ContiguousTokensEditing } from './contiguousTokensEditing.js';
12 > import { LineRange } from '../core/ranges/lineRange.js';
13 >
14 > /**
15 > * Represents contiguous tokens over a contiguous range of lines.
16 > */
17 > export class ContiguousMultilineTokens {
18 > public static deserialize(buff: Uint8Array, offset: number, result: ContiguousMultilineTokens[]): number {
19 const view32 = new Uint32Array(buff.buffer);
20 const startLineNumber = readUInt32BE(buff, offset); offset += 4;
29 return offset;
30 }
32 > /**
33 > * The start line number for this block of tokens.
34 > */
35 > private _startLineNumber: number;
36 >
37 > /**
38 > * The tokens are stored in a binary format. There is an element for each line,
39 > * so `tokens[index]` contains all tokens on line `startLineNumber + index`.
40 > *
41 > * On a specific line, each token occupies two array indices. For token i:
42 > * - at offset 2*i => endOffset
43 > * - at offset 2*i + 1 => metadata
44 > *
45 > */
46 > private _tokens: (Uint32Array | ArrayBuffer | null)[];
47 >
48 > /**
49 > * (Inclusive) start line number for these tokens.
50 > */
51 > public get startLineNumber(): number {
52 return this._startLineNumber;
53 }
55 > /**
56 > * (Inclusive) end line number for these tokens.
57 > */
58 > public get endLineNumber(): number {
59 return this._startLineNumber + this._tokens.length - 1;
60 }
62 > constructor(startLineNumber: number, tokens: Uint32Array[]) {
63 this._startLineNumber = startLineNumber;
64 this._tokens = tokens;
65 }
67 > getLineRange(): LineRange {
68 return new LineRange(this._startLineNumber, this._startLineNumber + this._tokens.length);
69 }
71 > /**
72 > * @see {@link _tokens}
73 > */
74 > public getLineTokens(lineNumber: number): Uint32Array | ArrayBuffer | null {
75 return this._tokens[lineNumber - this._startLineNumber];
76 }
78 > public appendLineTokens(lineTokens: Uint32Array): void {
79 this._tokens.push(lineTokens);
80 }
82 > public serializeSize(): number {
83 let result = 0;
84 result += 4; // 4 bytes for the start line number
94 return result;
95 }
97 > public serialize(destination: Uint8Array, offset: number): number {
98 writeUInt32BE(destination, this._startLineNumber, offset); offset += 4;
99 writeUInt32BE(destination, this._tokens.length, offset); offset += 4;
108 return offset;
109 }
111 > public applyEdit(range: IRange, text: string): void {
112 const [eolCount, firstLineLength] = countEOL(text);
113 this._acceptDeleteRange(range);
114 this._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength);
115 }
117 > private _acceptDeleteRange(range: IRange): void {
118 if (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) {
119 // Nothing to delete
184 }
185 }
187 > private _acceptInsertText(position: Position, eolCount: number, firstLineLength: number): void {
188
189 if (eolCount === 0 && firstLineLength === 0) {
216 this._insertLines(position.lineNumber, eolCount);
217 }
219 > private _insertLines(insertIndex: number, insertCount: number): void {
220 if (insertCount === 0) {
221 return;
src/vs/base/common/observableInternal/logging/logging.ts 67 covered LOC · 17 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageFeatureRegistry.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 } from '../../base/common/event.js';
7 > import { IDisposable, toDisposable } from '../../base/common/lifecycle.js';
8 > import { ITextModel, shouldSynchronizeModel } from './model.js';
9 > import { LanguageFilter, LanguageSelector, score, selectLanguageIds } from './languageSelector.js';
10 > import { URI } from '../../base/common/uri.js';
11 >
12 > interface Entry<T> {
13 > readonly selector: LanguageSelector;
14 > readonly provider: T;
15 > _score: number;
16 > readonly _time: number;
17 > }
18 >
19 function isExclusive(selector: LanguageSelector): boolean {
20 if (typeof selector === 'string') {
26 }
27 }
29 > export interface NotebookInfo {
30 > readonly uri: URI;
31 > readonly type: string;
32 > }
33 >
34 > export interface NotebookInfoResolver {
35 > (uri: URI): NotebookInfo | undefined;
36 > }
37 >
38 > class MatchCandidate {
39 > constructor(
40 readonly uri: URI,
41 readonly languageId: string,
44 readonly recursive: boolean,
45 ) { }
47 > equals(other: MatchCandidate): boolean {
48 return this.notebookType === other.notebookType
49 && this.languageId === other.languageId
52 && this.recursive === other.recursive;
53 }
55 >
56 > export class LanguageFeatureRegistry<T> {
57 >
58 > private _clock: number = 0;
59 > private readonly _entries: Entry<T>[] = [];
60 >
61 > private readonly _onDidChange = new Emitter<number>();
62 > get onDidChange() { return this._onDidChange.event; }
63 >
64 > constructor(private readonly _notebookInfoResolver?: NotebookInfoResolver) { }
65 >
66 > register(selector: LanguageSelector, provider: T): IDisposable {
67
68 let entry: Entry<T> | undefined = {
111 return result;
112 }
114 > allNoModel(): T[] {
115 return this._entries.map(entry => entry.provider);
116 }
118 > get registeredLanguageIds(): ReadonlySet<string> {
119 const result = new Set<string>();
120 for (const entry of this._entries) {
123 return result;
124 }
126 > ordered(model: ITextModel, recursive = false): T[] {
127 const result: T[] = [];
128 this._orderedForEach(model, recursive, entry => result.push(entry.provider));
129 return result;
130 }
132 > orderedGroups(model: ITextModel): T[][] {
133 const result: T[][] = [];
134 let lastBucket: T[];
147 return result;
148 }
150 > private _orderedForEach(model: ITextModel, recursive: boolean, callback: (provider: Entry<T>) => void): void {
151
152 this._updateScores(model, recursive);
158 }
159 }
161 > private _lastCandidate: MatchCandidate | undefined;
162 >
163 > private _updateScores(model: ITextModel, recursive: boolean): void {
164
165 const notebookInfo = this._notebookInfoResolver?.(model.uri);
199 this._entries.sort(LanguageFeatureRegistry._compareByScoreAndTime);
200 }
202 > private static _compareByScoreAndTime(a: Entry<unknown>, b: Entry<unknown>): number {
203 if (a._score < b._score) {
204 return 1;
222 }
223 }
225 >
226 function isBuiltinSelector(selector: LanguageSelector): boolean {
227 if (typeof selector === 'string') {
src/vs/editor/common/services/treeSitter/treeSitterLibraryService.ts 67 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- treeSitterLibraryService.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 { Language, Parser, Query } from '@vscode/tree-sitter-wasm';
7 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
8 > import { IReader } from '../../../../base/common/observable.js';
9 >
10 > export const ITreeSitterLibraryService = createDecorator<ITreeSitterLibraryService>('treeSitterLibraryService');
11 >
12 > export interface ITreeSitterLibraryService {
13 > readonly _serviceBrand: undefined;
14 >
15 > /**
16 > * Gets the tree sitter Parser constructor.
17 > */
18 > getParserClass(): Promise<typeof Parser>;
19 >
20 > /**
21 > * Checks whether a language is supported and available based setting enablement.
22 > * @param languageId The language identifier to check.
23 > * @param reader Optional observable reader.
24 > */
25 > supportsLanguage(languageId: string, reader: IReader | undefined): boolean;
26 >
27 > /**
28 > * Gets the tree sitter Language object synchronously.
29 > * @param languageId The language identifier to retrieve.
30 > * @param ignoreSupportsCheck Whether to ignore the supportsLanguage check.
31 > * @param reader Optional observable reader.
32 > */
33 > getLanguage(languageId: string, ignoreSupportsCheck: boolean, reader: IReader | undefined): Language | undefined;
34 >
35 > /**
36 > * Gets the language as a promise, as opposed to via observables. This ignores the automatic
37 > * supportsLanguage check.
38 > *
39 > * Warning: This approach is generally not recommended as it's not reactive, but it's the only
40 > * way to catch and handle import errors when the grammar fails to load.
41 > * @param languageId The language identifier to retrieve.
42 > */
43 > getLanguagePromise(languageId: string): Promise<Language | undefined>;
44 >
45 > /**
46 > * Gets the injection queries for a language. A return value of `null`
47 > * indicates that there are no highlights queries for this language.
48 > * @param languageId The language identifier to retrieve queries for.
49 > * @param reader Optional observable reader.
50 > */
51 > getInjectionQueries(languageId: string, reader: IReader | undefined): Query | null | undefined;
52 >
53 > /**
54 > * Gets the highlighting queries for a language. A return value of `null`
55 > * indicates that there are no highlights queries for this language.
56 > * @param languageId The language identifier to retrieve queries for.
57 > * @param reader Optional observable reader.
58 > */
59 > getHighlightingQueries(languageId: string, reader: IReader | undefined): Query | null | undefined;
60 >
61 > /**
62 > * Creates a one-off custom query for a language.
63 > * @param language The Language to create the query for.
64 > * @param querySource The query source string to compile.
65 > */
66 > createQuery(language: Language, querySource: string): Promise<Query>;
67 > }
src/vs/base/common/iterator.ts 65 covered LOC · 23 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'; iterator.ts
12 > }
14 > const _empty: Iterable<never> = Object.freeze([]);
15 > export function empty<T = never>(): readonly never[] {
16 return _empty as readonly never[];
17 }
19 > export function* single<T>(element: T): Iterable<T> {
20 yield element;
21 }
23 > export function wrap<T>(iterableOrElement: Iterable<T> | T): Iterable<T> {
24 if (is(iterableOrElement)) {
25 return iterableOrElement;
28 }
29 }
31 > export function from<T>(iterable: Iterable<T> | undefined | null): Iterable<T> {
32 return iterable ?? (_empty as Iterable<T>);
33 }
35 > export function* reverse<T>(array: ReadonlyArray<T>): Iterable<T> {
36 for (let i = array.length - 1; i >= 0; i--) {
37 yield array[i];
38 }
39 }
41 > export function isEmpty<T>(iterable: Iterable<T> | undefined | null): boolean {
42 return !iterable || iterable[Symbol.iterator]().next().done === true;
43 }
45 > export function first<T>(iterable: Iterable<T>): T | undefined {
46 return iterable[Symbol.iterator]().next().value;
47 }
49 > export function some<T>(iterable: Iterable<T>, predicate: (t: T, i: number) => unknown): boolean {
50 let i = 0;
51 for (const element of iterable) {
56 return false;
57 }
59 > export function every<T>(iterable: Iterable<T>, predicate: (t: T, i: number) => unknown): boolean {
60 let i = 0;
61 for (const element of iterable) {
66 return true;
67 }
69 > export function find<T, R extends T>(iterable: Iterable<T>, predicate: (t: T) => t is R): R | undefined;
70 > export function find<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): T | undefined;
71 > export function find<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): T | undefined {
72 for (const element of iterable) {
73 if (predicate(element)) {
78 return undefined;
79 }
81 > export function filter<T, R extends T>(iterable: Iterable<T>, predicate: (t: T) => t is R): Iterable<R>;
82 > export function filter<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): Iterable<T>;
83 > export function* filter<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): Iterable<T> {
84 for (const element of iterable) {
85 if (predicate(element)) {
88 }
89 }
91 > export function* map<T, R>(iterable: Iterable<T>, fn: (t: T, index: number) => R): Iterable<R> {
92 let index = 0;
93 for (const element of iterable) {
95 }
96 }
98 > export function* flatMap<T, R>(iterable: Iterable<T>, fn: (t: T, index: number) => Iterable<R>): Iterable<R> {
99 let index = 0;
100 for (const element of iterable) {
102 }
103 }
104 > iterator.ts
105 > export function* concat<T>(...iterables: (Iterable<T> | T)[]): Iterable<T> {
106 for (const item of iterables) {
107 if (isIterable(item)) {
112 }
113 }
114 > iterator.ts
115 > export function reduce<T, R>(iterable: Iterable<T>, reducer: (previousValue: R, currentValue: T) => R, initialValue: R): R {
116 let value = initialValue;
117 for (const element of iterable) {
120 return value;
121 }
122 > iterator.ts
123 > export function length<T>(iterable: Iterable<T>): number {
124 let count = 0;
125 for (const _ of iterable) {
128 return count;
129 }
130 > iterator.ts
131 > /**
132 > * Returns an iterable slice of the array, with the same semantics as `array.slice()`.
133 > */
134 > export function* slice<T>(arr: ReadonlyArray<T>, from: number, to = arr.length): Iterable<T> {
135 if (from < -arr.length) {
136 from = 0;
150 }
151 }
152 > iterator.ts
153 > /**
154 > * Consumes `atMost` elements from iterable and returns the consumed elements,
155 > * and an iterable for the rest of the elements.
156 > */
157 > export function consume<T>(iterable: Iterable<T>, atMost: number = Number.POSITIVE_INFINITY): [T[], Iterable<T>] {
158 const consumed: T[] = [];
159
176 return [consumed, { [Symbol.iterator]() { return iterator; } }];
177 }
178 > iterator.ts
179 > export async function asyncToArray<T>(iterable: AsyncIterable<T>): Promise<T[]> {
180 const result: T[] = [];
181 for await (const item of iterable) {
184 return result;
185 }
186 > iterator.ts
187 > export async function asyncToArrayFlat<T>(iterable: AsyncIterable<T[]>): Promise<T[]> {
188 let result: T[] = [];
189 for await (const item of iterable) {
src/vs/base/common/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/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/editor/test/common/testTextModel.ts 63 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testTextModel.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, IDisposable } from '../../../base/common/lifecycle.js';
7 > import { URI } from '../../../base/common/uri.js';
8 > import { BracketPairColorizationOptions, DefaultEndOfLine, ITextBufferFactory, ITextModelCreationOptions } from '../../common/model.js';
9 > import { TextModel } from '../../common/model/textModel.js';
10 > import { ILanguageConfigurationService } from '../../common/languages/languageConfigurationRegistry.js';
11 > import { ILanguageService } from '../../common/languages/language.js';
12 > import { LanguageService } from '../../common/services/languageService.js';
13 > import { ITextResourcePropertiesService } from '../../common/services/textResourceConfiguration.js';
14 > import { TestLanguageConfigurationService } from './modes/testLanguageConfigurationService.js';
15 > import { IConfigurationService } from '../../../platform/configuration/common/configuration.js';
16 > import { TestConfigurationService } from '../../../platform/configuration/test/common/testConfigurationService.js';
17 > import { IDialogService } from '../../../platform/dialogs/common/dialogs.js';
18 > import { TestDialogService } from '../../../platform/dialogs/test/common/testDialogService.js';
19 > import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
20 > import { ILogService, NullLogService } from '../../../platform/log/common/log.js';
21 > import { INotificationService } from '../../../platform/notification/common/notification.js';
22 > import { TestNotificationService } from '../../../platform/notification/test/common/testNotificationService.js';
23 > import { IThemeService } from '../../../platform/theme/common/themeService.js';
24 > import { TestThemeService } from '../../../platform/theme/test/common/testThemeService.js';
25 > import { IUndoRedoService } from '../../../platform/undoRedo/common/undoRedo.js';
26 > import { UndoRedoService } from '../../../platform/undoRedo/common/undoRedoService.js';
27 > import { TestTextResourcePropertiesService } from './services/testTextResourcePropertiesService.js';
28 > import { IModelService } from '../../common/services/model.js';
29 > import { ModelService } from '../../common/services/modelService.js';
30 > import { createServices, ServiceIdCtorPair, TestInstantiationService } from '../../../platform/instantiation/test/common/instantiationServiceMock.js';
31 > import { PLAINTEXT_LANGUAGE_ID } from '../../common/languages/modesRegistry.js';
32 > import { ILanguageFeatureDebounceService, LanguageFeatureDebounceService } from '../../common/services/languageFeatureDebounce.js';
33 > import { ILanguageFeaturesService } from '../../common/services/languageFeatures.js';
34 > import { LanguageFeaturesService } from '../../common/services/languageFeaturesService.js';
35 > import { IEnvironmentService } from '../../../platform/environment/common/environment.js';
36 > import { mock } from '../../../base/test/common/mock.js';
37 > import { ITreeSitterLibraryService } from '../../common/services/treeSitter/treeSitterLibraryService.js';
38 > import { TestTreeSitterLibraryService } from './services/testTreeSitterLibraryService.js';
39 >
40 > class TestTextModel extends TextModel {
41 > public registerDisposable(disposable: IDisposable): void {
42 this._register(disposable);
43 }
45 >
46 > export function withEditorModel(text: string[], callback: (model: TextModel) => void): void {
47 const model = createTextModel(text.join('\n'));
48 callback(model);
49 model.dispose();
50 }
52 > export interface IRelaxedTextModelCreationOptions {
53 > tabSize?: number;
54 > indentSize?: number | 'tabSize';
55 > insertSpaces?: boolean;
56 > detectIndentation?: boolean;
57 > trimAutoWhitespace?: boolean;
58 > defaultEOL?: DefaultEndOfLine;
59 > isForSimpleWidget?: boolean;
60 > largeFileOptimizations?: boolean;
61 > bracketColorizationOptions?: BracketPairColorizationOptions;
62 > }
63 >
64 function resolveOptions(_options: IRelaxedTextModelCreationOptions): ITextModelCreationOptions {
65 const defaultOptions = TextModel.DEFAULT_CREATION_OPTIONS;
76 };
77 }
79 > export function createTextModel(text: string | ITextBufferFactory, languageId: string | null = null, options: IRelaxedTextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS, uri: URI | null = null): TextModel {
80 const disposables = new DisposableStore();
81 const instantiationService = createModelServices(disposables);
84 return model;
85 }
87 > export function instantiateTextModel(instantiationService: IInstantiationService, text: string | ITextBufferFactory, languageId: string | null = null, _options: IRelaxedTextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS, uri: URI | null = null): TestTextModel {
88 const options = resolveOptions(_options);
89 return instantiationService.createInstance(TestTextModel, text, languageId || PLAINTEXT_LANGUAGE_ID, options, uri);
90 }
92 > export function createModelServices(disposables: DisposableStore, services: ServiceIdCtorPair<any>[] = []): TestInstantiationService {
93 return createServices(disposables, services.concat([
94 [INotificationService, TestNotificationService],
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/platform/theme/test/common/testThemeService.ts 62 covered LOC · 18 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testThemeService.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 { IconContribution } from '../../common/iconRegistry.js';
9 > import { ColorScheme } from '../../common/theme.js';
10 > import { IColorTheme, IFileIconTheme, IProductIconTheme, IThemeService, IFontTokenOptions, ITokenStyle } from '../../common/themeService.js';
11 >
12 > export class TestColorTheme implements IColorTheme {
13 >
14 > public readonly label = 'test';
15 >
16 > constructor(
17 private colors: { [id: string]: string | undefined } = {},
18 public type = ColorScheme.DARK,
19 public readonly semanticHighlighting = false
20 ) { }
22 > getColor(color: string, useDefault?: boolean): Color | undefined {
23 const value = this.colors[color];
24 if (value) {
27 return undefined;
28 }
30 > defines(color: string): boolean {
31 throw new Error('Method not implemented.');
32 }
34 > getTokenStyleMetadata(type: string, modifiers: string[], modelLanguage: string): ITokenStyle | undefined {
35 return undefined;
36 }
38 > get tokenColorMap(): string[] {
39 return [];
40 }
42 > get tokenFontMap(): IFontTokenOptions[] {
43 return [];
44 }
46 >
47 class TestFileIconTheme implements IFileIconTheme {
48 hasFileIcons = false;
49 hasFolderIcons = false;
50 hidesExplorerArrows = false;
52 >
53 > class UnthemedProductIconTheme implements IProductIconTheme {
54 > getIcon(contribution: IconContribution) {
55 return undefined;
56 }
58 >
59 > export class TestThemeService implements IThemeService {
60 >
61 > declare readonly _serviceBrand: undefined;
62 > _colorTheme: IColorTheme;
63 > _fileIconTheme: IFileIconTheme;
64 > _productIconTheme: IProductIconTheme;
65 > _onThemeChange = new Emitter<IColorTheme>();
66 > _onFileIconThemeChange = new Emitter<IFileIconTheme>();
67 > _onProductIconThemeChange = new Emitter<IProductIconTheme>();
68 >
69 > constructor(theme: IColorTheme = new TestColorTheme(), fileIconTheme: IFileIconTheme = new TestFileIconTheme(), productIconTheme: IProductIconTheme = new UnthemedProductIconTheme()) {
70 this._colorTheme = theme;
71 this._fileIconTheme = fileIconTheme;
72 this._productIconTheme = productIconTheme;
73 }
75 > getColorTheme(): IColorTheme {
76 return this._colorTheme;
77 }
79 > setTheme(theme: IColorTheme) {
80 this._colorTheme = theme;
81 this.fireThemeChange();
82 }
84 > fireThemeChange() {
85 this._onThemeChange.fire(this._colorTheme);
86 }
88 > public get onDidColorThemeChange(): Event<IColorTheme> {
89 return this._onThemeChange.event;
90 }
92 > getFileIconTheme(): IFileIconTheme {
93 return this._fileIconTheme;
94 }
96 > public get onDidFileIconThemeChange(): Event<IFileIconTheme> {
97 return this._onFileIconThemeChange.event;
98 }
100 > getProductIconTheme(): IProductIconTheme {
101 return this._productIconTheme;
102 }
104 > public get onDidProductIconThemeChange(): Event<IProductIconTheme> {
105 return this._onProductIconThemeChange.event;
106 }
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/base/common/assert.ts 59 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- assert.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { BugIndicatingError, onUnexpectedError } from './errors.js';
7 >
8 > /**
9 > * Throws an error with the provided message if the provided value does not evaluate to a true Javascript value.
10 > *
11 > * @deprecated Use `assert(...)` instead.
12 > * This method is usually used like this:
13 > * ```ts
14 > * import * as assert from 'vs/base/common/assert';
15 > * assert.ok(...);
16 > * ```
17 > *
18 > * However, `assert` in that example is a user chosen name.
19 > * There is no tooling for generating such an import statement.
20 > * Thus, the `assert(...)` function should be used instead.
21 > */
22 > export function ok(value?: unknown, message?: string) {
23 > if (!value) { assert.ts
24 throw new Error(message ? `Assertion failed (${message})` : 'Assertion Failed');
25 }
26 > } assert.ts
27 > assert.ts
28 > export function assertNever(value: never, message = 'Unreachable'): never {
29 throw new Error(message);
30 }
31 > assert.ts
32 > export function softAssertNever(value: never): void {
33 // no-op
34 }
35 > assert.ts
36 > /**
37 > * Asserts that a condition is `truthy`.
38 > *
39 > * @throws provided {@linkcode messageOrError} if the {@linkcode condition} is `falsy`.
40 > *
41 > * @param condition The condition to assert.
42 > * @param messageOrError An error message or error object to throw if condition is `falsy`.
43 > */
44 > export function assert(
45 > condition: boolean, 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()) {
72 // eslint-disable-next-line no-debugger
77 }
78 }
79 > assert.ts
80 > export function checkAdjacentItems<T>(items: readonly T[], predicate: (item1: T, item2: T) => boolean): boolean {
81 > let i = 0; assert.ts
82 > while (i < items.length - 1) {
83 const a = items[i];
84 const b = items[i + 1];
88 i++;
89 }
90 > return true; assert.ts
91 > }
src/vs/editor/common/core/edits/lengthEdit.ts 59 covered LOC · 16 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lengthEdit.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 '../ranges/offsetRange.js';
7 > import { AnyEdit, BaseEdit, BaseReplacement } from './edit.js';
8 >
9 > /**
10 > * Like a normal edit, but only captures the length information.
11 > */
12 > export class LengthEdit extends BaseEdit<LengthReplacement, LengthEdit> {
13 > public static readonly empty = new LengthEdit([]);
14 >
15 > public static fromEdit(edit: AnyEdit): LengthEdit {
16 return new LengthEdit(edit.replacements.map(r => new LengthReplacement(r.replaceRange, r.getNewLength())));
17 }
19 > public static create(replacements: readonly LengthReplacement[]): LengthEdit {
20 return new LengthEdit(replacements);
21 }
23 > public static single(replacement: LengthReplacement): LengthEdit {
24 return new LengthEdit([replacement]);
25 }
27 > public static replace(range: OffsetRange, newLength: number): LengthEdit {
28 return new LengthEdit([new LengthReplacement(range, newLength)]);
29 }
31 > public static insert(offset: number, newLength: number): LengthEdit {
32 return new LengthEdit([new LengthReplacement(OffsetRange.emptyAt(offset), newLength)]);
33 }
35 > public static delete(range: OffsetRange): LengthEdit {
36 return new LengthEdit([new LengthReplacement(range, 0)]);
37 }
39 > public static compose(edits: readonly LengthEdit[]): LengthEdit {
40 let e = LengthEdit.empty;
41 for (const edit of edits) {
44 return e;
45 }
47 > /**
48 > * Creates an edit that reverts this edit.
49 > */
50 > public inverse(): LengthEdit {
51 const edits: LengthReplacement[] = [];
52 let offset = 0;
60 return new LengthEdit(edits);
61 }
63 > protected override _createNew(replacements: readonly LengthReplacement[]): LengthEdit {
64 return new LengthEdit(replacements);
65 }
67 > public applyArray<T>(arr: readonly T[], fillItem: T): T[] {
68 const newArr = new Array(this.getNewDataLength(arr.length));
69
93 return newArr;
94 }
95 > } lengthEdit.ts
96 >
97 > export class LengthReplacement extends BaseReplacement<LengthReplacement> {
98 > public static create(
99 > startOffset: number,
100 > endOffsetExclusive: number,
101 > newLength: number,
102 > ): LengthReplacement {
103 > return new LengthReplacement(new OffsetRange(startOffset, endOffsetExclusive), newLength);
104 > }
105 >
106 > constructor(
107 range: OffsetRange,
108 public readonly newLength: number,
110 super(range);
111 }
113 > override equals(other: LengthReplacement): boolean {
114 return this.replaceRange.equals(other.replaceRange) && this.newLength === other.newLength;
115 }
117 > getNewLength(): number { return this.newLength; }
118 >
119 > tryJoinTouching(other: LengthReplacement): LengthReplacement | undefined {
120 return new LengthReplacement(this.replaceRange.joinRightTouching(other.replaceRange), this.newLength + other.newLength);
121 }
123 > slice(range: OffsetRange, rangeInReplacement: OffsetRange): LengthReplacement {
124 return new LengthReplacement(range, rangeInReplacement.length);
125 }
127 > override toString() {
128 return `[${this.replaceRange.start}, +${this.replaceRange.length}) -> +${this.newLength}}`;
129 }
130 > } lengthEdit.ts
src/vs/platform/theme/common/colors/minimapColors.ts 59 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- minimapColors.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 > // Import the effects we need
9 > import { Color, RGBA } from '../../../../base/common/color.js';
10 > import { registerColor, transparent } from '../colorUtils.js';
11 >
12 > // Import the colors we need
13 > import { editorFindMatchHighlight, editorInfoBorder, editorInfoForeground, editorSelectionBackground, editorSelectionHighlight, editorWarningBorder, editorWarningForeground } from './editorColors.js';
14 > import { scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from './miscColors.js';
15 >
16 >
17 > export const minimapFindMatch = registerColor('minimap.findMatchHighlight',
18 > editorFindMatchHighlight,
19 > nls.localize('minimapFindMatchHighlight', 'Minimap marker color for find matches.'), true);
20 >
21 > export const minimapSelectionOccurrenceHighlight = registerColor('minimap.selectionOccurrenceHighlight',
22 > editorSelectionHighlight,
23 > nls.localize('minimapSelectionOccurrenceHighlight', 'Minimap marker color for repeating editor selections.'), true);
24 >
25 > export const minimapSelection = registerColor('minimap.selectionHighlight',
26 > editorSelectionBackground,
27 > nls.localize('minimapSelectionHighlight', 'Minimap marker color for the editor selection.'), true);
28 >
29 > export const minimapInfo = registerColor('minimap.infoHighlight',
30 > { dark: editorInfoForeground, light: editorInfoForeground, hcDark: editorInfoBorder, hcLight: editorInfoBorder },
31 > nls.localize('minimapInfo', 'Minimap marker color for infos.'));
32 >
33 > export const minimapWarning = registerColor('minimap.warningHighlight',
34 > { dark: editorWarningForeground, light: editorWarningForeground, hcDark: editorWarningBorder, hcLight: editorWarningBorder },
35 > nls.localize('overviewRuleWarning', 'Minimap marker color for warnings.'));
36 >
37 > export const minimapError = registerColor('minimap.errorHighlight',
38 > { dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hcDark: new Color(new RGBA(255, 50, 50, 1)), hcLight: '#B5200D' },
39 > nls.localize('minimapError', 'Minimap marker color for errors.'));
40 >
41 > export const minimapBackground = registerColor('minimap.background',
42 > null,
43 > nls.localize('minimapBackground', "Minimap background color."));
44 >
45 > export const minimapForegroundOpacity = registerColor('minimap.foregroundOpacity',
46 > Color.fromHex('#000f'),
47 > nls.localize('minimapForegroundOpacity', 'Opacity of foreground elements rendered in the minimap. For example, "#000000c0" will render the elements with 75% opacity.'));
48 >
49 > export const minimapSliderBackground = registerColor('minimapSlider.background',
50 > transparent(scrollbarSliderBackground, 0.5),
51 > nls.localize('minimapSliderBackground', "Minimap slider background color."));
52 >
53 > export const minimapSliderHoverBackground = registerColor('minimapSlider.hoverBackground',
54 > transparent(scrollbarSliderHoverBackground, 0.5),
55 > nls.localize('minimapSliderHoverBackground', "Minimap slider background color when hovering."));
56 >
57 > export const minimapSliderActiveBackground = registerColor('minimapSlider.activeBackground',
58 > transparent(scrollbarSliderActiveBackground, 0.5),
59 > nls.localize('minimapSliderActiveBackground', "Minimap slider background color when clicked on."));
src/vs/base/common/observableInternal/observables/observableValue.ts 58 covered LOC · 12 ranges

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- contiguousTokensStore.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as arrays from '../../../base/common/arrays.js';
7 > import { Position } from '../core/position.js';
8 > import { IRange } from '../core/range.js';
9 > import { ContiguousTokensEditing, EMPTY_LINE_TOKENS, toUint32Array } from './contiguousTokensEditing.js';
10 > import { LineTokens } from './lineTokens.js';
11 > import { ILanguageIdCodec } from '../languages.js';
12 > import { LanguageId, FontStyle, ColorId, StandardTokenType, MetadataConsts, TokenMetadata } from '../encodedTokenAttributes.js';
13 > import { ITextModel } from '../model.js';
14 > import { ContiguousMultilineTokens } from './contiguousMultilineTokens.js';
15 >
16 > /**
17 > * Represents contiguous tokens in a text model.
18 > */
19 > export class ContiguousTokensStore {
20 > private _lineTokens: (Uint32Array | ArrayBuffer | null)[];
21 > private _len: number;
22 > private readonly _languageIdCodec: ILanguageIdCodec;
23 >
24 > constructor(languageIdCodec: ILanguageIdCodec) {
25 this._lineTokens = [];
26 this._len = 0;
27 this._languageIdCodec = languageIdCodec;
28 }
30 > public flush(): void {
31 this._lineTokens = [];
32 this._len = 0;
33 }
35 > get hasTokens(): boolean {
36 return this._lineTokens.length > 0;
37 }
39 > public getTokens(topLevelLanguageId: string, lineIndex: number, lineText: string): LineTokens {
40 let rawLineTokens: Uint32Array | ArrayBuffer | null = null;
41 if (lineIndex < this._len) {
52 return new LineTokens(lineTokens, lineText, this._languageIdCodec);
53 }
55 > private static _massageTokens(topLevelLanguageId: LanguageId, lineTextLength: number, _tokens: Uint32Array | ArrayBuffer | null): Uint32Array | ArrayBuffer {
56
57 const tokens = _tokens ? toUint32Array(_tokens) : null;
84 return tokens;
85 }
87 > private _ensureLine(lineIndex: number): void {
88 while (lineIndex >= this._len) {
89 this._lineTokens[this._len] = null;
91 }
92 }
94 > private _deleteLines(start: number, deleteCount: number): void {
95 if (deleteCount === 0) {
96 return;
102 this._len -= deleteCount;
103 }
105 > private _insertLines(insertIndex: number, insertCount: number): void {
106 if (insertCount === 0) {
107 return;
114 this._len += insertCount;
115 }
117 > public setTokens(topLevelLanguageId: string, lineIndex: number, lineTextLength: number, _tokens: Uint32Array | ArrayBuffer | null, checkEquality: boolean): boolean {
118 const tokens = ContiguousTokensStore._massageTokens(this._languageIdCodec.encodeLanguageId(topLevelLanguageId), lineTextLength, _tokens);
119 this._ensureLine(lineIndex);
126 return false;
127 }
129 > private static _equals(_a: Uint32Array | ArrayBuffer | null, _b: Uint32Array | ArrayBuffer | null) {
130 if (!_a || !_b) {
131 return !_a && !_b;
145 return true;
146 }
148 > //#region Editing
149 >
150 > public acceptEdit(range: IRange, eolCount: number, firstLineLength: number): void {
151 this._acceptDeleteRange(range);
152 this._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength);
153 }
155 > private _acceptDeleteRange(range: IRange): void {
156
157 const firstLineIndex = range.startLineNumber - 1;
184 this._deleteLines(range.startLineNumber, range.endLineNumber - range.startLineNumber);
185 }
187 > private _acceptInsertText(position: Position, eolCount: number, firstLineLength: number): void {
188
189 if (eolCount === 0 && firstLineLength === 0) {
208 this._insertLines(position.lineNumber, eolCount);
209 }
211 > //#endregion
212 >
213 > public setMultilineTokens(tokens: ContiguousMultilineTokens[], textModel: ITextModel): { changes: { fromLineNumber: number; toLineNumber: number }[] } {
214 if (tokens.length === 0) {
215 return { changes: [] };
243 return { changes: ranges };
244 }
246 >
247 function getDefaultMetadata(topLevelLanguageId: LanguageId): number {
248 return (
src/vs/editor/common/model/tokens/treeSitter/treeSitterSyntaxTokenBackend.ts 55 covered LOC · 14 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- treeSitterSyntaxTokenBackend.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 '../../../../../base/common/event.js';
7 > import { toDisposable } from '../../../../../base/common/lifecycle.js';
8 > import { StandardTokenType } from '../../../encodedTokenAttributes.js';
9 > import { ILanguageIdCodec } from '../../../languages.js';
10 > import { IModelContentChangedEvent } from '../../../textModelEvents.js';
11 > import { BackgroundTokenizationState } from '../../../tokenizationTextModelPart.js';
12 > import { LineTokens } from '../../../tokens/lineTokens.js';
13 > import { TextModel } from '../../textModel.js';
14 > import { AbstractSyntaxTokenBackend } from '../abstractSyntaxTokenBackend.js';
15 > import { autorun, derived, IObservable, ObservablePromise } from '../../../../../base/common/observable.js';
16 > import { TreeSitterTree } from './treeSitterTree.js';
17 > import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
18 > import { TreeSitterTokenizationImpl } from './treeSitterTokenizationImpl.js';
19 > import { ITreeSitterLibraryService } from '../../../services/treeSitter/treeSitterLibraryService.js';
20 > import { LineRange } from '../../../core/ranges/lineRange.js';
21 >
22 > export class TreeSitterSyntaxTokenBackend extends AbstractSyntaxTokenBackend {
23 > protected _backgroundTokenizationState: BackgroundTokenizationState = BackgroundTokenizationState.InProgress;
24 > protected readonly _onDidChangeBackgroundTokenizationState: Emitter<void> = this._register(new Emitter<void>());
25 > public readonly onDidChangeBackgroundTokenizationState: Event<void> = this._onDidChangeBackgroundTokenizationState.event;
26 >
27 > private readonly _tree: IObservable<TreeSitterTree | undefined>;
28 > private readonly _tokenizationImpl: IObservable<TreeSitterTokenizationImpl | undefined>;
29 >
30 > constructor(
31 private readonly _languageIdObs: IObservable<string>,
32 languageIdCodec: ILanguageIdCodec,
103 }));
104 }
106 > get tree(): IObservable<TreeSitterTree | undefined> {
107 return this._tree;
108 }
110 > get tokenizationImpl(): IObservable<TreeSitterTokenizationImpl | undefined> {
111 return this._tokenizationImpl;
112 }
114 > public getLineTokens(lineNumber: number): LineTokens {
115 const model = this._tokenizationImpl.get();
116 if (!model) {
120 return model.getLineTokens(lineNumber);
121 }
123 > public todo_resetTokenization(fireTokenChangeEvent: boolean = true): void {
124 if (fireTokenChangeEvent) {
125 this._onDidChangeTokens.fire({
134 }
135 }
137 > public override handleDidChangeAttached(): void {
138 // TODO @alexr00 implement for background tokenization
139 }
141 > public override handleDidChangeContent(e: IModelContentChangedEvent): void {
142 if (e.isFlush) {
143 // Don't fire the event, as the view might not have got the text change event yet
151 treeModel?.handleContentChange(e);
152 }
154 > public override forceTokenization(lineNumber: number): void {
155 const model = this._tokenizationImpl.get();
156 if (!model) {
161 }
162 }
164 > public override hasAccurateTokensForLine(lineNumber: number): boolean {
165 const model = this._tokenizationImpl.get();
166 if (!model) {
169 return model.hasAccurateTokensForLine(lineNumber);
170 }
172 > public override isCheapToTokenize(lineNumber: number): boolean {
173 // TODO @alexr00 determine what makes it cheap to tokenize?
174 return true;
175 }
177 > public override getTokenTypeIfInsertingCharacter(lineNumber: number, column: number, character: string): StandardTokenType {
178 // TODO @alexr00 implement once we have custom parsing and don't just feed in the whole text model value
179 return StandardTokenType.Other;
180 }
182 > public override tokenizeLinesAt(lineNumber: number, lines: string[]): LineTokens[] | null {
183 const model = this._tokenizationImpl.get();
184 if (!model) {
187 return model.tokenizeLinesAt(lineNumber, lines);
188 }
190 > public override get hasTokens(): boolean {
191 const model = this._tokenizationImpl.get();
192 if (!model) {
src/vs/platform/theme/common/colors/quickpickColors.ts 55 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- quickpickColors.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 > // Import the effects we need
9 > import { Color, RGBA } from '../../../../base/common/color.js';
10 > import { registerColor, oneOf } from '../colorUtils.js';
11 >
12 > // Import the colors we need
13 > import { editorWidgetBackground, editorWidgetForeground } from './editorColors.js';
14 > import { listActiveSelectionBackground, listActiveSelectionForeground, listActiveSelectionIconForeground, listFocusHighlightForeground } from './listColors.js';
15 >
16 >
17 > export const quickInputBackground = registerColor('quickInput.background',
18 > editorWidgetBackground,
19 > nls.localize('pickerBackground', "Quick picker background color. The quick picker widget is the container for pickers like the command palette."));
20 >
21 > export const quickInputForeground = registerColor('quickInput.foreground',
22 > editorWidgetForeground,
23 > nls.localize('pickerForeground', "Quick picker foreground color. The quick picker widget is the container for pickers like the command palette."));
24 >
25 > export const quickInputTitleBackground = registerColor('quickInputTitle.background',
26 > { dark: new Color(new RGBA(255, 255, 255, 0.105)), light: new Color(new RGBA(0, 0, 0, 0.06)), hcDark: '#000000', hcLight: Color.white },
27 > nls.localize('pickerTitleBackground', "Quick picker title background color. The quick picker widget is the container for pickers like the command palette."));
28 >
29 > export const pickerGroupForeground = registerColor('pickerGroup.foreground',
30 > { dark: '#3794FF', light: '#0066BF', hcDark: Color.white, hcLight: '#0F4A85' },
31 > nls.localize('pickerGroupForeground', "Quick picker color for grouping labels."));
32 >
33 > export const pickerGroupBorder = registerColor('pickerGroup.border',
34 > { dark: '#3F3F46', light: '#CCCEDB', hcDark: Color.white, hcLight: '#0F4A85' },
35 > nls.localize('pickerGroupBorder', "Quick picker color for grouping borders."));
36 >
37 > export const _deprecatedQuickInputListFocusBackground = registerColor('quickInput.list.focusBackground',
38 > null, '', undefined,
39 > nls.localize('quickInput.list.focusBackground deprecation', "Please use quickInputList.focusBackground instead"));
40 >
41 > export const quickInputListFocusForeground = registerColor('quickInputList.focusForeground',
42 > listActiveSelectionForeground,
43 > nls.localize('quickInput.listFocusForeground', "Quick picker foreground color for the focused item."));
44 >
45 > export const quickInputListFocusIconForeground = registerColor('quickInputList.focusIconForeground',
46 > listActiveSelectionIconForeground,
47 > nls.localize('quickInput.listFocusIconForeground', "Quick picker icon foreground color for the focused item."));
48 >
49 > export const quickInputListFocusBackground = registerColor('quickInputList.focusBackground',
50 > { dark: oneOf(_deprecatedQuickInputListFocusBackground, listActiveSelectionBackground), light: oneOf(_deprecatedQuickInputListFocusBackground, listActiveSelectionBackground), hcDark: null, hcLight: null },
51 > nls.localize('quickInput.listFocusBackground', "Quick picker background color for the focused item."));
52 >
53 > export const quickInputListFocusHighlightForeground = registerColor('quickInputList.focusHighlightForeground',
54 > listFocusHighlightForeground,
55 > nls.localize('quickInput.listFocusHighlightForeground', "Quick picker foreground color of the match highlights on the focused item."));
src/vs/platform/registry/common/platform.ts 54 covered LOC · 7 ranges

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelGuides.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 } from './core/position.js';
7 >
8 > export interface IGuidesTextModelPart {
9 > /**
10 > * @internal
11 > */
12 > getActiveIndentGuide(lineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo;
13 >
14 > /**
15 > * @internal
16 > */
17 > getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[];
18 >
19 > /**
20 > * Requests the indent guides for the given range of lines.
21 > * `result[i]` will contain the indent guides of the `startLineNumber + i`th line.
22 > * @internal
23 > */
24 > getLinesBracketGuides(startLineNumber: number, endLineNumber: number, activePosition: IPosition | null, options: BracketGuideOptions): IndentGuide[][];
25 > }
26 >
27 > export interface IActiveIndentGuideInfo {
28 > startLineNumber: number;
29 > endLineNumber: number;
30 > indent: number;
31 > }
32 >
33 > export enum HorizontalGuidesState {
34 > Disabled,
35 > EnabledForActive,
36 > Enabled
37 > }
38 >
39 > export interface BracketGuideOptions {
40 > includeInactive: boolean;
41 > horizontalGuides: HorizontalGuidesState;
42 > highlightActive: boolean;
43 > }
44 >
45 > export class IndentGuide {
46 > constructor(
47 public readonly visibleColumn: number | -1,
48 public readonly column: number | -1,
63 }
64 }
66 >
67 > export class IndentGuideHorizontalLine {
68 > constructor(
69 public readonly top: boolean,
70 public readonly endColumn: number,
71 ) { }
src/vs/base/common/observableInternal/observables/lazyObservableValue.ts 49 covered LOC · 11 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- stringBuilder.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 strings from '../../../base/common/strings.js';
7 > import * as platform from '../../../base/common/platform.js';
8 > import * as buffer from '../../../base/common/buffer.js';
9 >
10 > let _utf16LE_TextDecoder: TextDecoder | null;
11 function getUTF16LE_TextDecoder(): TextDecoder {
12 if (!_utf16LE_TextDecoder) {
15 return _utf16LE_TextDecoder;
16 }
18 > let _utf16BE_TextDecoder: TextDecoder | null;
19 function getUTF16BE_TextDecoder(): TextDecoder {
20 if (!_utf16BE_TextDecoder) {
23 return _utf16BE_TextDecoder;
24 }
26 > let _platformTextDecoder: TextDecoder | null;
27 > export function getPlatformTextDecoder(): TextDecoder {
28 if (!_platformTextDecoder) {
29 _platformTextDecoder = platform.isLittleEndian() ? getUTF16LE_TextDecoder() : getUTF16BE_TextDecoder();
31 return _platformTextDecoder;
32 }
34 > export function decodeUTF16LE(source: Uint8Array, offset: number, len: number): string {
35 const view = new Uint16Array(source.buffer, offset, len);
36 if (len > 0 && (view[0] === 0xFEFF || view[0] === 0xFFFE)) {
43 return getUTF16LE_TextDecoder().decode(view);
44 }
46 function compatDecodeUTF16LE(source: Uint8Array, offset: number, len: number): string {
47 const result: string[] = [];
53 return result.join('');
54 }
56 > export class StringBuilder {
57 >
58 > private readonly _capacity: number;
59 > private readonly _buffer: Uint16Array;
60 >
61 > private _completedStrings: string[] | null;
62 > private _bufferLength: number;
63 >
64 > constructor(capacity: number) {
65 this._capacity = capacity | 0;
66 this._buffer = new Uint16Array(this._capacity);
69 this._bufferLength = 0;
70 }
72 > public reset(): void {
73 this._completedStrings = null;
74 this._bufferLength = 0;
75 }
77 > public build(): string {
78 if (this._completedStrings !== null) {
79 this._flushBuffer();
82 return this._buildBuffer();
83 }
85 > private _buildBuffer(): string {
86 if (this._bufferLength === 0) {
87 return '';
91 return getPlatformTextDecoder().decode(view);
92 }
94 > private _flushBuffer(): void {
95 const bufferString = this._buildBuffer();
96 this._bufferLength = 0;
102 }
103 }
105 > /**
106 > * Append a char code (<2^16)
107 > */
108 > public appendCharCode(charCode: number): void {
109 const remainingSpace = this._capacity - this._bufferLength;
110
117 this._buffer[this._bufferLength++] = charCode;
118 }
120 > /**
121 > * Append an ASCII char code (<2^8)
122 > */
123 > public appendASCIICharCode(charCode: number): void {
124 if (this._bufferLength === this._capacity) {
125 // buffer is full
128 this._buffer[this._bufferLength++] = charCode;
129 }
131 > public appendString(str: string): void {
132 const strLen = str.length;
133
src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/parser.ts 49 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- parser.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 { AstNode, AstNodeKind, BracketAstNode, InvalidBracketAstNode, ListAstNode, PairAstNode, TextAstNode } from './ast.js';
7 > import { BeforeEditPositionMapper, TextEditInfo } from './beforeEditPositionMapper.js';
8 > import { SmallImmutableSet } from './smallImmutableSet.js';
9 > import { lengthIsZero, lengthLessThan } from './length.js';
10 > import { concat23Trees, concat23TreesOfSameHeight } from './concat23Trees.js';
11 > import { NodeReader } from './nodeReader.js';
12 > import { OpeningBracketId, Tokenizer, TokenKind } from './tokenizer.js';
13 >
14 > /**
15 > * Non incrementally built ASTs are immutable.
16 > */
17 > export function parseDocument(tokenizer: Tokenizer, edits: TextEditInfo[], oldNode: AstNode | undefined, createImmutableLists: boolean): AstNode {
18 const parser = new Parser(tokenizer, edits, oldNode, createImmutableLists);
19 return parser.parseDocument();
20 }
21 > parser.ts
22 > /**
23 > * Non incrementally built ASTs are immutable.
24 > */
25 > class Parser {
26 > private readonly oldNodeReader?: NodeReader;
27 > private readonly positionMapper: BeforeEditPositionMapper;
28 > private _itemsConstructed: number = 0;
29 > private _itemsFromCache: number = 0;
30 >
31 > /**
32 > * Reports how many nodes were constructed in the last parse operation.
33 > */
34 > get nodesConstructed() {
35 > return this._itemsConstructed;
36 > }
37 >
38 > /**
39 > * Reports how many nodes were reused in the last parse operation.
40 > */
41 > get nodesReused() {
42 return this._itemsFromCache;
43 }
44 > parser.ts
45 > constructor(
46 private readonly tokenizer: Tokenizer,
47 edits: TextEditInfo[],
56 this.positionMapper = new BeforeEditPositionMapper(edits);
57 }
58 > parser.ts
59 > parseDocument(): AstNode {
60 this._itemsConstructed = 0;
61 this._itemsFromCache = 0;
68 return result;
69 }
70 > parser.ts
71 > private parseList(
72 openedBracketIds: SmallImmutableSet<OpeningBracketId>,
73 level: number,
102 return result;
103 }
104 > parser.ts
105 > private tryReadChildFromCache(openedBracketIds: SmallImmutableSet<number>): AstNode | undefined {
106 if (this.oldNodeReader) {
107 const maxCacheableLength = this.positionMapper.getDistanceToNextChange(this.tokenizer.offset);
128 return undefined;
129 }
130 > parser.ts
131 > private parseChild(
132 openedBracketIds: SmallImmutableSet<number>,
133 level: number,
src/vs/platform/accessibility/common/accessibility.ts 49 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- accessibility.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 { RawContextKey } from '../../contextkey/common/contextkey.js';
8 > import { createDecorator } from '../../instantiation/common/instantiation.js';
9 >
10 > export const IAccessibilityService = createDecorator<IAccessibilityService>('accessibilityService');
11 >
12 > export interface IAccessibilityService {
13 > readonly _serviceBrand: undefined;
14 >
15 > readonly onDidChangeScreenReaderOptimized: Event<void>;
16 > readonly onDidChangeReducedMotion: Event<void>;
17 > readonly onDidChangeReducedTransparency: Event<void>;
18 >
19 > alwaysUnderlineAccessKeys(): Promise<boolean>;
20 > isScreenReaderOptimized(): boolean;
21 > isMotionReduced(): boolean;
22 > isTransparencyReduced(): boolean;
23 > getAccessibilitySupport(): AccessibilitySupport;
24 > setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void;
25 > alert(message: string): void;
26 > status(message: string): void;
27 > }
28 >
29 > export const enum AccessibilitySupport {
30 > /**
31 > * This should be the browser case where it is not known if a screen reader is attached or no.
32 > */
33 > Unknown = 0,
34 >
35 > Disabled = 1,
36 >
37 > Enabled = 2
38 > }
39 >
40 > export const CONTEXT_ACCESSIBILITY_MODE_ENABLED = new RawContextKey<boolean>('accessibilityModeEnabled', false);
41 >
42 > export interface IAccessibilityInformation {
43 > label: string;
44 > role?: string;
45 > }
46 >
47 > export function isAccessibilityInformation(obj: unknown): obj is IAccessibilityInformation {
48 if (!obj || typeof obj !== 'object') {
49 return false;
54 && (typeof candidate.role === 'undefined' || typeof candidate.role === 'string');
55 }
57 > export const ACCESSIBLE_VIEW_SHOWN_STORAGE_PREFIX = 'ACCESSIBLE_VIEW_SHOWN_';
src/vs/base/common/numbers.ts 48 covered LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- numbers.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 > export function clamp(value: number, min: number, max: number): number {
9 return Math.min(Math.max(value, min), max);
10 }
11 > numbers.ts
12 > /**
13 > * Formats a token count for compact display (e.g. `128K`, `1M`, `1.5M`).
14 > */
15 > export function formatTokenCount(count: number): string {
16 if (count >= 1_000_000) {
17 const value = count / 1_000_000;
25 return count.toString();
26 }
27 > numbers.ts
28 > export function rot(index: number, modulo: number): number {
29 return (modulo + (index % modulo)) % modulo;
30 }
31 > numbers.ts
32 > export class Counter {
33 private _next = 0;
34 > numbers.ts
35 > getNext(): number {
36 return this._next++;
37 }
38 > } numbers.ts
39 >
40 > export class MovingAverage {
41
42 private _n = 1;
43 private _val = 0;
44 > numbers.ts
45 > update(value: number): number {
46 this._val = this._val + (value - this._val) / this._n;
47 this._n += 1;
48 return this._val;
49 }
50 > numbers.ts
51 > get value(): number {
52 return this._val;
53 }
54 > } numbers.ts
55 >
56 > export class SlidingWindowAverage {
57 >
58 > private _n: number = 0;
59 > private _val = 0;
60 >
61 > private readonly _values: number[] = [];
62 > private _index: number = 0;
63 > private _sum = 0;
64 >
65 > constructor(size: number) {
66 this._values = new Array(size);
67 this._values.fill(0, 0, size);
68 }
69 > numbers.ts
70 > update(value: number): number {
71 const oldValue = this._values[this._index];
72 this._values[this._index] = value;
83 return this._val;
84 }
85 > numbers.ts
86 > get value(): number {
87 return this._val;
88 }
89 > } numbers.ts
90 >
91 > /** Returns whether the point is within the triangle formed by the following 6 x/y point pairs */
92 > export function isPointWithinTriangle(
93 x: number, y: number,
94 ax: number, ay: number,
115 return u >= 0 && v >= 0 && u + v < 1;
116 }
117 > numbers.ts
118 > export function randomChance(p: number): boolean {
119 assert(p >= 0 && p <= 1, 'p must be between 0 and 1');
120 return Math.random() < p;
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/model/bracketPairsTextModelPart/colorizedBracketPairsDecorationProvider.ts 46 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- colorizedBracketPairsDecorationProvider.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 } from '../../../../base/common/event.js';
8 > import { Disposable } from '../../../../base/common/lifecycle.js';
9 > import { Range } from '../../core/range.js';
10 > import { BracketPairColorizationOptions, IModelDecoration } from '../../model.js';
11 > import { BracketInfo } from '../../textModelBracketPairs.js';
12 > import { DecorationProvider } from '../decorationProvider.js';
13 > import { TextModel } from '../textModel.js';
14 > import {
15 > editorBracketHighlightingForeground1, editorBracketHighlightingForeground2, editorBracketHighlightingForeground3, editorBracketHighlightingForeground4, editorBracketHighlightingForeground5, editorBracketHighlightingForeground6, editorBracketHighlightingUnexpectedBracketForeground
16 > } from '../../core/editorColorRegistry.js';
17 > import { registerThemingParticipant } from '../../../../platform/theme/common/themeService.js';
18 > import { IModelOptionsChangedEvent } from '../../textModelEvents.js';
19 >
20 > export class ColorizedBracketPairsDecorationProvider extends Disposable implements DecorationProvider {
21 > private colorizationOptions: BracketPairColorizationOptions;
22 > private readonly colorProvider = new ColorProvider();
23 >
24 > private readonly onDidChangeEmitter = this._register(new Emitter<void>());
25 > public readonly onDidChange = this.onDidChangeEmitter.event;
26 >
27 > constructor(private readonly textModel: TextModel) {
28 super();
29
34 }));
35 }
37 > //#region TextModel events
38 >
39 > public handleDidChangeOptions(e: IModelOptionsChangedEvent): void {
40 this.colorizationOptions = this.textModel.getOptions().bracketPairColorizationOptions;
41 }
43 > //#endregion
44 >
45 > getDecorationsInRange(range: Range, ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean, onlyMinimapDecorations?: boolean): IModelDecoration[] {
46 if (onlyMinimapDecorations) {
47 // Bracket pair colorization decorations are not rendered in the minimap
70 return result;
71 }
73 > getAllDecorations(ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean): IModelDecoration[] {
74 if (ownerId === undefined) {
75 return [];
96 return this.getInlineClassNameOfLevel(independentColorPoolPerBracketType ? bracket.nestingLevelOfEqualBracketType : bracket.nestingLevel);
97 }
99 > getInlineClassNameOfLevel(level: number): string {
100 // To support a dynamic amount of colors up to 6 colors,
101 // we use a number that is a lcm of all numbers from 1 to 6.
102 return `bracket-highlighting-${level % 30}`;
103 }
105 >
106 > registerThemingParticipant((theme, collector) => {
107 const colors = [
108 editorBracketHighlightingForeground1,
src/vs/editor/common/model/decorationProvider.ts 45 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- decorationProvider.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 { Range } from '../core/range.js';
7 > import { IModelDecoration } from '../model.js';
8 >
9 > export interface DecorationProvider {
10 > /**
11 > * Gets all the decorations in a range as an array. Only `startLineNumber` and `endLineNumber` from `range` are used for filtering.
12 > * So for now it returns all the decorations on the same line as `range`.
13 > * @param range The range to search in
14 > * @param ownerId If set, it will ignore decorations belonging to other owners.
15 > * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
16 > * @return An array with the decorations
17 > */
18 > getDecorationsInRange(range: Range, ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean): IModelDecoration[];
19 >
20 > /**
21 > * Gets all the decorations as an array.
22 > * @param ownerId If set, it will ignore decorations belonging to other owners.
23 > * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
24 > */
25 > getAllDecorations(ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean, onlyMinimapDecorations?: boolean): IModelDecoration[];
26 >
27 > }
28 >
29 > export class LineHeightChangingDecoration {
30 >
31 > public static toKey(obj: LineHeightChangingDecoration): string {
32 > return `${obj.ownerId};${obj.decorationId};${obj.lineNumber}`;
33 > }
34 >
35 > constructor(
36 public readonly ownerId: number,
37 public readonly decorationId: string,
39 public readonly lineHeight: number | null
40 ) { }
42 >
43 > export class LineFontChangingDecoration {
44 >
45 > public static toKey(obj: LineFontChangingDecoration): string {
46 > return `${obj.ownerId};${obj.decorationId};${obj.lineNumber}`;
47 > }
48 >
49 > constructor(
50 public readonly ownerId: number,
51 public readonly decorationId: string,
52 public readonly lineNumber: number
53 ) { }
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/editor/common/languages/supports.ts 44 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- supports.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 { IViewLineTokens, LineTokens } from '../tokens/lineTokens.js';
7 > import { StandardTokenType } from '../encodedTokenAttributes.js';
8 > import { ILanguageIdCodec } from '../languages.js';
9 >
10 > export function createScopedLineTokens(context: LineTokens, offset: number): ScopedLineTokens {
11 const tokenCount = context.getCount();
12 const tokenIndex = context.findTokenIndexAtOffset(offset);
32 );
33 }
35 > export class ScopedLineTokens {
36 > _scopedLineTokensBrand: void = undefined;
37 >
38 > public readonly languageIdCodec: ILanguageIdCodec;
39 > public readonly languageId: string;
40 > private readonly _actual: LineTokens;
41 > private readonly _firstTokenIndex: number;
42 > private readonly _lastTokenIndex: number;
43 > public readonly firstCharOffset: number;
44 > private readonly _lastCharOffset: number;
45 >
46 > constructor(
47 actual: LineTokens,
48 languageId: string,
60 this.languageIdCodec = actual.languageIdCodec;
61 }
63 > public getLineContent(): string {
64 const actualLineContent = this._actual.getLineContent();
65 return actualLineContent.substring(this.firstCharOffset, this._lastCharOffset);
66 }
68 > public getLineLength(): number {
69 return this._lastCharOffset - this.firstCharOffset;
70 }
72 > public getActualLineContentBefore(offset: number): string {
73 const actualLineContent = this._actual.getLineContent();
74 return actualLineContent.substring(0, this.firstCharOffset + offset);
75 }
77 > public getTokenCount(): number {
78 return this._lastTokenIndex - this._firstTokenIndex;
79 }
81 > public findTokenIndexAtOffset(offset: number): number {
82 return this._actual.findTokenIndexAtOffset(offset + this.firstCharOffset) - this._firstTokenIndex;
83 }
85 > public getStandardTokenType(tokenIndex: number): StandardTokenType {
86 return this._actual.getStandardTokenType(tokenIndex + this._firstTokenIndex);
87 }
89 > public toIViewLineTokens(): IViewLineTokens {
90 return this._actual.sliceAndInflate(this.firstCharOffset, this._lastCharOffset, 0);
91 }
92 > } supports.ts
93 >
94 > const enum IgnoreBracketsInTokens {
95 > value = StandardTokenType.Comment | StandardTokenType.String | StandardTokenType.RegEx
96 > }
97 >
98 > export function ignoreBracketsInToken(standardTokenType: StandardTokenType): boolean {
99 return (standardTokenType & IgnoreBracketsInTokens.value) !== 0;
100 }
src/vs/platform/theme/common/colors/chartsColors.ts 44 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- chartsColors.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 > import { registerColor, transparent } from '../colorUtils.js';
8 >
9 > import { foreground } from './baseColors.js';
10 > import { editorErrorForeground, editorInfoForeground, editorWarningForeground } from './editorColors.js';
11 > import { minimapFindMatch } from './minimapColors.js';
12 >
13 >
14 > export const chartsForeground = registerColor('charts.foreground',
15 > foreground,
16 > nls.localize('chartsForeground', "The foreground color used in charts."));
17 >
18 > export const chartsLines = registerColor('charts.lines',
19 > transparent(foreground, .5),
20 > nls.localize('chartsLines', "The color used for horizontal lines in charts."));
21 >
22 > export const chartsRed = registerColor('charts.red',
23 > editorErrorForeground,
24 > nls.localize('chartsRed', "The red color used in chart visualizations."));
25 >
26 > export const chartsBlue = registerColor('charts.blue',
27 > editorInfoForeground,
28 > nls.localize('chartsBlue', "The blue color used in chart visualizations."));
29 >
30 > export const chartsYellow = registerColor('charts.yellow',
31 > editorWarningForeground,
32 > nls.localize('chartsYellow', "The yellow color used in chart visualizations."));
33 >
34 > export const chartsOrange = registerColor('charts.orange',
35 > minimapFindMatch,
36 > nls.localize('chartsOrange', "The orange color used in chart visualizations."));
37 >
38 > export const chartsGreen = registerColor('charts.green',
39 > { dark: '#89D185', light: '#388A34', hcDark: '#89D185', hcLight: '#374e06' },
40 > nls.localize('chartsGreen', "The green color used in chart visualizations."));
41 >
42 > export const chartsPurple = registerColor('charts.purple',
43 > { dark: '#B180D7', light: '#652D90', hcDark: '#B180D7', hcLight: '#652D90' },
44 > nls.localize('chartsPurple', "The purple color used in chart visualizations."));
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/model/tokens/tokenizationFontDecorationsProvider.ts 43 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- tokenizationFontDecorationsProvider.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 { Disposable } from '../../../../base/common/lifecycle.js';
7 > import { IModelDecoration, ITextModel } from '../../model.js';
8 > import { TokenizationTextModelPart } from './tokenizationTextModelPart.js';
9 > import { Range } from '../../core/range.js';
10 > import { DecorationProvider, LineFontChangingDecoration, LineHeightChangingDecoration } from '../decorationProvider.js';
11 > import { Emitter } from '../../../../base/common/event.js';
12 > import { IFontTokenOption, IModelContentChangedEvent } from '../../textModelEvents.js';
13 > import { classNameForFontTokenDecorations } from '../../languages/supports/tokenization.js';
14 > import { Position } from '../../core/position.js';
15 > import { AnnotatedString, AnnotationsUpdate, IAnnotatedString, IAnnotationUpdate } from './annotations.js';
16 > import { OffsetRange } from '../../core/ranges/offsetRange.js';
17 > import { offsetEditFromContentChanges } from '../textModelStringEdit.js';
18 >
19 > export interface IFontTokenAnnotation {
20 > decorationId: string;
21 > fontToken: IFontTokenOption;
22 > }
23 >
24 > export class TokenizationFontDecorationProvider extends Disposable implements DecorationProvider {
25 >
26 > private static DECORATION_COUNT = 0;
27 >
28 > private readonly _onDidChangeLineHeight = this._register(new Emitter<Set<LineHeightChangingDecoration>>());
29 > public readonly onDidChangeLineHeight = this._onDidChangeLineHeight.event;
30 >
31 > private readonly _onDidChangeFont = this._register(new Emitter<Set<LineFontChangingDecoration>>());
32 > public readonly onDidChangeFont = this._onDidChangeFont.event;
33 >
34 > private _fontAnnotatedString: IAnnotatedString<IFontTokenAnnotation> = new AnnotatedString<IFontTokenAnnotation>();
35 >
36 > constructor(
37 private readonly textModel: ITextModel,
38 private readonly tokenizationTextModelPart: TokenizationTextModelPart
97 }));
98 }
100 > public handleDidChangeContent(change: IModelContentChangedEvent) {
101 const edits = offsetEditFromContentChanges(change.changes);
102 const deletedAnnotations = this._fontAnnotatedString.applyEdit(edits);
118 this._onDidChangeFont.fire(affectedLineFonts);
119 }
121 > public getDecorationsInRange(range: Range, ownerId?: number, filterOutValidation?: boolean, filterFontDecorations?: boolean, onlyMinimapDecorations?: boolean): IModelDecoration[] {
122 const startOffsetOfRange = this.textModel.getOffsetAt(range.getStartPosition());
123 const endOffsetOfRange = this.textModel.getOffsetAt(range.getEndPosition());
150 return decorations;
151 }
153 > public getAllDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[] {
154 return this.getDecorationsInRange(
155 new Range(1, 1, this.textModel.getLineCount(), this.textModel.getLineMaxColumn(this.textModel.getLineCount())),
src/vs/platform/theme/common/colors/menuColors.ts 43 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- menuColors.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 > // Import the effects we need
9 > import { registerColor, transparent } from '../colorUtils.js';
10 >
11 > // Import the colors we need
12 > import { contrastBorder, activeContrastBorder, foreground } from './baseColors.js';
13 > import { selectForeground, selectBackground } from './inputColors.js';
14 > import { listActiveSelectionBackground, listActiveSelectionForeground } from './listColors.js';
15 >
16 >
17 > export const menuBorder = registerColor('menu.border',
18 > { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },
19 > nls.localize('menuBorder', "Border color of menus."));
20 >
21 > export const menuForeground = registerColor('menu.foreground',
22 > selectForeground,
23 > nls.localize('menuForeground', "Foreground color of menu items."));
24 >
25 > export const menuBackground = registerColor('menu.background',
26 > selectBackground,
27 > nls.localize('menuBackground', "Background color of menu items."));
28 >
29 > export const menuSelectionForeground = registerColor('menu.selectionForeground',
30 > listActiveSelectionForeground,
31 > nls.localize('menuSelectionForeground', "Foreground color of the selected menu item in menus."));
32 >
33 > export const menuSelectionBackground = registerColor('menu.selectionBackground',
34 > listActiveSelectionBackground,
35 > nls.localize('menuSelectionBackground', "Background color of the selected menu item in menus."));
36 >
37 > export const menuSelectionBorder = registerColor('menu.selectionBorder',
38 > { dark: null, light: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },
39 > nls.localize('menuSelectionBorder', "Border color of the selected menu item in menus."));
40 >
41 > export const menuSeparatorBackground = registerColor('menu.separatorBackground',
42 > { dark: transparent(foreground, 0.2), light: transparent(foreground, 0.2), hcDark: contrastBorder, hcLight: contrastBorder },
43 > nls.localize('menuSeparatorBackground', "Color of a separator menu item in menus."));
src/vs/base/common/observableInternal/debugLocation.ts 42 covered LOC · 4 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- graph.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 class Node<T> {
7 >
8 >
9 > readonly incoming = new Map<string, Node<T>>();
10 > readonly outgoing = new Map<string, Node<T>>();
11 >
12 > constructor(
13 readonly key: string,
14 readonly data: T
15 ) { }
16 > } graph.ts
17 >
18 > export class Graph<T> {
19 >
20 > private readonly _nodes = new Map<string, Node<T>>();
21 >
22 > constructor(private readonly _hashFn: (element: T) => string) {
23 // empty
24 }
25 > graph.ts
26 > roots(): Node<T>[] {
27 const ret: Node<T>[] = [];
28 for (const node of this._nodes.values()) {
33 return ret;
34 }
35 > graph.ts
36 > insertEdge(from: T, to: T): void {
37 const fromNode = this.lookupOrInsertNode(from);
38 const toNode = this.lookupOrInsertNode(to);
41 toNode.incoming.set(fromNode.key, fromNode);
42 }
43 > graph.ts
44 > removeNode(data: T): void {
45 const key = this._hashFn(data);
46 this._nodes.delete(key);
50 }
51 }
52 > graph.ts
53 > lookupOrInsertNode(data: T): Node<T> {
54 const key = this._hashFn(data);
55 let node = this._nodes.get(key);
62 return node;
63 }
64 > graph.ts
65 > lookup(data: T): Node<T> | undefined {
66 return this._nodes.get(this._hashFn(data));
67 }
68 > graph.ts
69 > isEmpty(): boolean {
70 return this._nodes.size === 0;
71 }
72 > graph.ts
73 > toString(): string {
74 const data: string[] = [];
75 for (const [key, value] of this._nodes) {
79 return data.join('\n');
80 }
81 > graph.ts
82 > /**
83 > * This is brute force and slow and **only** be used
84 > * to trouble shoot.
85 > */
86 > findCycleSlow() {
87 for (const [id, node] of this._nodes) {
88 const seen = new Set<string>([id]);
94 return undefined;
95 }
96 > graph.ts
97 > private _findCycle(node: Node<T>, seen: Set<string>): string | undefined {
98 for (const [id, outgoing] of node.outgoing) {
99 if (seen.has(id)) {
109 return undefined;
110 }
111 > } graph.ts
src/vs/editor/common/model/guidesTextModelPart.ts 41 covered LOC · 12 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- guidesTextModelPart.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 { findLast } from '../../../base/common/arraysFind.js';
7 > import * as strings from '../../../base/common/strings.js';
8 > import { CursorColumns } from '../core/cursorColumns.js';
9 > import { IPosition, Position } from '../core/position.js';
10 > import { Range } from '../core/range.js';
11 > import type { TextModel } from './textModel.js';
12 > import { TextModelPart } from './textModelPart.js';
13 > import { computeIndentLevel } from './utils.js';
14 > import { ILanguageConfigurationService, ResolvedLanguageConfiguration } from '../languages/languageConfigurationRegistry.js';
15 > import { BracketGuideOptions, HorizontalGuidesState, IActiveIndentGuideInfo, IGuidesTextModelPart, IndentGuide, IndentGuideHorizontalLine } from '../textModelGuides.js';
16 > import { BugIndicatingError } from '../../../base/common/errors.js';
17 >
18 > export class GuidesTextModelPart extends TextModelPart implements IGuidesTextModelPart {
19 > constructor(
20 private readonly textModel: TextModel,
21 private readonly languageConfigurationService: ILanguageConfigurationService
23 super();
24 }
26 > private getLanguageConfiguration(
27 languageId: string
28 ): ResolvedLanguageConfiguration {
31 );
32 }
34 > private _computeIndentLevel(lineIndex: number): number {
35 return computeIndentLevel(
36 this.textModel.getLineContent(lineIndex + 1),
38 );
39 }
41 > public getActiveIndentGuide(
42 lineNumber: number,
43 minLineNumber: number,
271 return { startLineNumber, endLineNumber, indent };
272 }
274 > public getLinesBracketGuides(
275 startLineNumber: number,
276 endLineNumber: number,
458 return result;
459 }
461 > private getVisibleColumnFromPosition(position: Position): number {
462 return (
463 CursorColumns.visibleColumnFromColumn(
468 );
469 }
471 > public getLinesIndentGuides(
472 startLineNumber: number,
473 endLineNumber: number
559 return result;
560 }
562 > private _getIndentLevelForWhitespaceLine(
563 offSide: boolean,
564 aboveContentLineIndent: number,
586 }
587 }
589 >
590 > export class BracketPairGuidesClassNames {
591 public readonly activeClassName = 'indent-active';
593 > getInlineClassName(nestingLevel: number, nestingLevelOfEqualBracketType: number, independentColorPoolPerBracketType: boolean): string {
594 return this.getInlineClassNameOfLevel(independentColorPoolPerBracketType ? nestingLevelOfEqualBracketType : nestingLevel);
595 }
597 > getInlineClassNameOfLevel(level: number): string {
598 // To support a dynamic amount of colors up to 6 colors,
599 // we use a number that is a lcm of all numbers from 1 to 6.
600 return `bracket-indent-guide lvl-${level % 30}`;
601 }
src/vs/editor/common/tokens/sparseTokensStore.ts 40 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- sparseTokensStore.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as arrays from '../../../base/common/arrays.js';
7 > import { IRange, Range } from '../core/range.js';
8 > import { LineTokens } from './lineTokens.js';
9 > import { SparseMultilineTokens } from './sparseMultilineTokens.js';
10 > import { ILanguageIdCodec } from '../languages.js';
11 > import { MetadataConsts } from '../encodedTokenAttributes.js';
12 > import { ITextModel } from '../model.js';
13 >
14 > /**
15 > * Represents sparse tokens in a text model.
16 > */
17 > export class SparseTokensStore {
18 >
19 > private _pieces: SparseMultilineTokens[];
20 > private _isComplete: boolean;
21 > private readonly _languageIdCodec: ILanguageIdCodec;
22 >
23 > constructor(languageIdCodec: ILanguageIdCodec) {
24 this._pieces = [];
25 this._isComplete = false;
26 this._languageIdCodec = languageIdCodec;
27 }
29 > public flush(): void {
30 this._pieces = [];
31 this._isComplete = false;
32 }
34 > public isEmpty(): boolean {
35 return (this._pieces.length === 0);
36 }
38 > public set(pieces: SparseMultilineTokens[] | null, isComplete: boolean, textModel: ITextModel | undefined = undefined): void {
39 this._pieces = pieces || [];
40 this._isComplete = isComplete;
46 }
47 }
49 > public setPartial(_range: Range, pieces: SparseMultilineTokens[]): Range {
50 // console.log(`setPartial ${_range} ${pieces.map(p => p.toString()).join(', ')}`);
51
126 return range;
127 }
129 > public isComplete(): boolean {
130 return this._isComplete;
131 }
133 > public addSparseTokens(lineNumber: number, aTokens: LineTokens): LineTokens {
134 if (aTokens.getTextLength() === 0) {
135 // Don't do anything for empty lines
223 return new LineTokens(new Uint32Array(result), aTokens.getLineContent(), this._languageIdCodec);
224 }
226 > private static _findFirstPieceWithLine(pieces: SparseMultilineTokens[], lineNumber: number): number {
227 let low = 0;
228 let high = pieces.length - 1;
245 return low;
246 }
248 > public acceptEdit(range: IRange, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {
249 for (let i = 0; i < this._pieces.length; i++) {
250 const piece = this._pieces[i];
src/vs/platform/configuration/test/common/testConfigurationService.ts 40 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testConfigurationService.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 } from '../../../../base/common/event.js';
7 > import { TernarySearchTree } from '../../../../base/common/ternarySearchTree.js';
8 > import { URI } from '../../../../base/common/uri.js';
9 > import { getConfigurationValue, IConfigurationChangeEvent, IConfigurationOverrides, IConfigurationService, IConfigurationValue, isConfigurationOverrides } from '../../common/configuration.js';
10 > import { Extensions, IConfigurationRegistry } from '../../common/configurationRegistry.js';
11 > import { Registry } from '../../../registry/common/platform.js';
12 >
13 > export class TestConfigurationService implements IConfigurationService {
14 > public _serviceBrand: undefined;
15 >
16 > private configuration: Record<string, unknown>;
17 > readonly onDidChangeConfigurationEmitter = new Emitter<IConfigurationChangeEvent>();
18 > readonly onDidChangeConfiguration = this.onDidChangeConfigurationEmitter.event;
19 >
20 > constructor(configuration?: Record<string, unknown>) {
21 this.configuration = configuration || Object.create(null);
22 }
24 > private configurationByRoot: TernarySearchTree<string, Record<string, unknown>> = TernarySearchTree.forPaths<Record<string, unknown>>();
25 >
26 > public reloadConfiguration<T>(): Promise<T> {
27 return Promise.resolve(this.getValue() as T);
28 }
30 > public getValue<T>(arg1?: string | IConfigurationOverrides, arg2?: IConfigurationOverrides): T | undefined {
31 let configuration;
32 const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : undefined;
42 return configuration as T;
43 }
45 > public updateValue(key: string, value: unknown): Promise<void> {
46 return Promise.resolve(undefined);
47 }
49 > public setUserConfiguration(key: string, value: unknown, root?: URI): Promise<void> {
50 if (root) {
51 const configForRoot = this.configurationByRoot.get(root.fsPath) || Object.create(null);
58 return Promise.resolve(undefined);
59 }
61 > private overrideIdentifiers: Map<string, string[]> = new Map();
62 > public setOverrideIdentifiers(key: string, identifiers: string[]): void {
63 this.overrideIdentifiers.set(key, identifiers);
64 }
66 > public inspect<T>(key: string, overrides?: IConfigurationOverrides): IConfigurationValue<T> {
67 const value = this.getValue(key, overrides) as T;
68
75 };
76 }
78 > public keys() {
79 return {
80 default: Object.keys(Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties()),
src/vs/base/common/lazy.ts 39 covered LOC · 4 ranges

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- product.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 { env } from '../../../base/common/process.js';
7 > import { IProductConfiguration } from '../../../base/common/product.js';
8 > import { ISandboxConfiguration } from '../../../base/parts/sandbox/common/sandboxTypes.js';
9 >
10 > /**
11 > * @deprecated It is preferred that you use `IProductService` if you can. This
12 > * allows web embedders to override our defaults. But for things like `product.quality`,
13 > * the use is fine because that property is not overridable.
14 > */
15 > let product: IProductConfiguration;
16 >
17 > // Native sandbox environment
18 > const vscodeGlobal = (globalThis as { vscode?: { context?: { configuration(): ISandboxConfiguration | undefined } } }).vscode;
19 > if (typeof vscodeGlobal !== 'undefined' && typeof vscodeGlobal.context !== 'undefined') {
20 const configuration: ISandboxConfiguration | undefined = vscodeGlobal.context.configuration();
21 if (configuration) {
25 }
26 }
27 > // _VSCODE environment product.ts
28 > else if (globalThis._VSCODE_PRODUCT_JSON && globalThis._VSCODE_PACKAGE_JSON) {
29 > // Obtain values from product.json and package.json-data
30 > product = globalThis._VSCODE_PRODUCT_JSON as unknown as IProductConfiguration;
31 >
32 > // Running out of sources
33 > if (env['VSCODE_DEV']) {
34 Object.assign(product, {
35 nameShort: `${product.nameShort} Dev`,
39 });
40 }
41 > product.ts
42 > // Version is added during built time, but we still
43 > // want to have it running out of sources so we
44 > // read it from package.json only when we need it.
45 > if (!product.version) {
46 > const pkg = globalThis._VSCODE_PACKAGE_JSON as { version: string };
47 >
48 > Object.assign(product, {
49 > version: pkg.version
50 > });
51 > }
52 }
53
90 }
91 }
92 > product.ts
93 > export default product;
src/vs/base/common/observableInternal/observables/observableSignalFromEvent.ts 38 covered LOC · 8 ranges

Open complete file

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

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 { URI } from '../../../base/common/uri.js';
8 > import { ITextBufferFactory, ITextModel, ITextModelCreationOptions } from '../model.js';
9 > import { ILanguageSelection } from '../languages/language.js';
10 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
11 > import { DocumentSemanticTokensProvider, DocumentRangeSemanticTokensProvider } from '../languages.js';
12 > import { TextModelEditSource } from '../textModelEditSource.js';
13 >
14 > export const IModelService = createDecorator<IModelService>('modelService');
15 >
16 > export type DocumentTokensProvider = DocumentSemanticTokensProvider | DocumentRangeSemanticTokensProvider;
17 >
18 > export interface IModelService {
19 > readonly _serviceBrand: undefined;
20 >
21 > createModel(value: string | ITextBufferFactory, languageSelection: ILanguageSelection | null, resource?: URI, isForSimpleWidget?: boolean): ITextModel;
22 >
23 > updateModel(model: ITextModel, value: string | ITextBufferFactory, reason?: TextModelEditSource): void;
24 >
25 > destroyModel(resource: URI): void;
26 >
27 > getModels(): ITextModel[];
28 >
29 > getCreationOptions(language: string, resource: URI, isForSimpleWidget: boolean): ITextModelCreationOptions;
30 >
31 > getModel(resource: URI): ITextModel | null;
32 >
33 > readonly onModelAdded: Event<ITextModel>;
34 >
35 > readonly onModelRemoved: Event<ITextModel>;
36 >
37 > readonly onModelLanguageChanged: Event<{ readonly model: ITextModel; readonly oldLanguageId: string }>;
38 > }
src/vs/base/common/observableInternal/observables/observableSignal.ts 37 covered LOC · 6 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- onEnter.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 { onUnexpectedError } from '../../../../base/common/errors.js';
7 > import * as strings from '../../../../base/common/strings.js';
8 > import { CharacterPair, EnterAction, IndentAction, OnEnterRule } from '../languageConfiguration.js';
9 > import { EditorAutoIndentStrategy } from '../../config/editorOptions.js';
10 >
11 > export interface IOnEnterSupportOptions {
12 > brackets?: CharacterPair[];
13 > onEnterRules?: OnEnterRule[];
14 > }
15 >
16 > interface IProcessedBracketPair {
17 > open: string;
18 > close: string;
19 > openRegExp: RegExp;
20 > closeRegExp: RegExp;
21 > }
22 >
23 > export class OnEnterSupport {
24 >
25 > private readonly _brackets: IProcessedBracketPair[];
26 > private readonly _regExpRules: OnEnterRule[];
27 >
28 > constructor(opts: IOnEnterSupportOptions) {
29 opts = opts || {};
30 opts.brackets = opts.brackets || [
49 this._regExpRules = opts.onEnterRules || [];
50 }
51 > onEnter.ts
52 > public onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {
53 // (1): `regExpRules`
54 if (autoIndent >= EditorAutoIndentStrategy.Advanced) {
106 return null;
107 }
108 > onEnter.ts
109 > private static _createOpenBracketRegExp(bracket: string): RegExp | null {
110 let str = strings.escapeRegExpCharacters(bracket);
111 if (!/\B/.test(str.charAt(0))) {
115 return OnEnterSupport._safeRegExp(str);
116 }
117 > onEnter.ts
118 > private static _createCloseBracketRegExp(bracket: string): RegExp | null {
119 let str = strings.escapeRegExpCharacters(bracket);
120 if (!/\B/.test(str.charAt(str.length - 1))) {
124 return OnEnterSupport._safeRegExp(str);
125 }
126 > onEnter.ts
127 > private static _safeRegExp(def: string): RegExp | null {
128 try {
129 return new RegExp(def);
src/vs/base/common/observableInternal/changeTracker.ts 35 covered LOC · 2 ranges

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- extensions.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 { SyncDescriptor } from './descriptors.js';
7 > import { BrandedService, ServiceIdentifier } from './instantiation.js';
8 >
9 > const _registry: [ServiceIdentifier<any>, SyncDescriptor<any>][] = [];
10 >
11 > export const enum InstantiationType {
12 > /**
13 > * Instantiate this service as soon as a consumer depends on it. _Note_ that this
14 > * is more costly as some upfront work is done that is likely not needed
15 > */
16 > Eager = 0,
17 >
18 > /**
19 > * Instantiate this service as soon as a consumer uses it. This is the _better_
20 > * way of registering a service.
21 > */
22 > Delayed = 1
23 > }
24 >
25 > export function registerSingleton<T, Services extends BrandedService[]>(id: ServiceIdentifier<T>, ctor: new (...services: Services) => T, supportsDelayedInstantiation: InstantiationType): void;
26 > export function registerSingleton<T, Services extends BrandedService[]>(id: ServiceIdentifier<T>, descriptor: SyncDescriptor<any>): void;
27 > export function registerSingleton<T, Services extends BrandedService[]>(id: ServiceIdentifier<T>, ctorOrDescriptor: { new(...services: Services): T } | SyncDescriptor<any>, supportsDelayedInstantiation?: boolean | InstantiationType): void {
28 > if (!(ctorOrDescriptor instanceof SyncDescriptor)) {
29 > ctorOrDescriptor = new SyncDescriptor<T>(ctorOrDescriptor as new (...args: unknown[]) => T, [], Boolean(supportsDelayedInstantiation));
30 > }
31 >
32 > _registry.push([id, ctorOrDescriptor]);
33 > }
34 >
35 > export function getSingletonServiceDescriptors(): [ServiceIdentifier<any>, SyncDescriptor<any>][] {
36 return _registry;
37 }
src/vs/editor/common/languageSelector.ts 34 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageSelector.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 { IRelativePattern, match as matchGlobPattern } from '../../base/common/glob.js';
7 > import { URI } from '../../base/common/uri.js';
8 > import { normalize } from '../../base/common/path.js';
9 >
10 > export interface LanguageFilter {
11 > readonly language?: string;
12 > readonly scheme?: string;
13 > readonly pattern?: string | IRelativePattern;
14 > readonly notebookType?: string;
15 > /**
16 > * This provider is implemented in the UI thread.
17 > */
18 > readonly hasAccessToAllModels?: boolean;
19 > readonly exclusive?: boolean;
20 >
21 > /**
22 > * This provider comes from a builtin extension.
23 > */
24 > readonly isBuiltin?: boolean;
25 > }
26 >
27 > export type LanguageSelector = string | LanguageFilter | ReadonlyArray<string | LanguageFilter>;
28 >
29 > export function score(selector: LanguageSelector | undefined, candidateUri: URI, candidateLanguage: string, candidateIsSynchronized: boolean, candidateNotebookUri: URI | undefined, candidateNotebookType: string | undefined): number {
30
31 if (Array.isArray(selector)) {
132 }
133 }
135 >
136 > export function targetsNotebooks(selector: LanguageSelector): boolean {
137 if (typeof selector === 'string') {
138 return false;
143 }
144 }
146 > export function selectLanguageIds(selector: LanguageSelector, into: Set<string>): void {
147 if (typeof selector === 'string') {
148 into.add(selector);
src/vs/platform/notification/test/common/testNotificationService.ts 34 covered LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testNotificationService.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 { INotification, INotificationHandle, INotificationService, INotificationSource, INotificationSourceFilter, IPromptChoice, IPromptOptions, IStatusHandle, IStatusMessageOptions, NoOpNotification, NotificationsFilter, Severity } from '../../common/notification.js';
8 >
9 > export class TestNotificationService implements INotificationService {
10
11 readonly onDidChangeFilter: Event<void> = Event.None;
13 > declare readonly _serviceBrand: undefined;
14 >
15 > private static readonly NO_OP: INotificationHandle = new NoOpNotification();
16 >
17 > info(message: string): INotificationHandle {
18 return this.notify({ severity: Severity.Info, message });
19 }
21 > warn(message: string): INotificationHandle {
22 return this.notify({ severity: Severity.Warning, message });
23 }
25 > error(error: string | Error): INotificationHandle {
26 return this.notify({ severity: Severity.Error, message: error });
27 }
29 > notify(notification: INotification): INotificationHandle {
30 return TestNotificationService.NO_OP;
31 }
33 > prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
34 return TestNotificationService.NO_OP;
35 }
37 > status(message: string | Error, options?: IStatusMessageOptions): IStatusHandle {
38 return {
39 close: () => { }
40 };
41 }
43 > setFilter(): void { }
44 >
45 > getFilter(source?: INotificationSource | undefined): NotificationsFilter {
46 return NotificationsFilter.OFF;
47 }
49 > getFilters(): INotificationSourceFilter[] {
50 return [];
51 }
53 > removeFilter(sourceId: string): void { }
54 > }
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/platform/dialogs/test/common/testDialogService.ts 33 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testDialogService.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 Severity from '../../../../base/common/severity.js';
8 > import { IConfirmation, IConfirmationResult, IDialogService, IInputResult, IPrompt, IPromptBaseButton, IPromptResult, IPromptResultWithCancel, IPromptWithCustomCancel, IPromptWithDefaultCancel } from '../../common/dialogs.js';
9 >
10 > export class TestDialogService implements IDialogService {
11 >
12 > declare readonly _serviceBrand: undefined;
13 >
14 > readonly onWillShowDialog = Event.None;
15 > readonly onDidShowDialog = Event.None;
16 >
17 > constructor(
18 private defaultConfirmResult: IConfirmationResult | undefined = undefined,
19 private defaultPromptResult: IPromptResult<unknown> | undefined = undefined
21
22 private confirmResult: IConfirmationResult | undefined = undefined;
23 > setConfirmResult(result: IConfirmationResult) { testDialogService.ts
24 this.confirmResult = result;
25 }
27 > async confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
28 if (this.confirmResult) {
29 const confirmResult = this.confirmResult;
35 return this.defaultConfirmResult ?? { confirmed: false };
36 }
38 > prompt<T>(prompt: IPromptWithCustomCancel<T>): Promise<IPromptResultWithCancel<T>>;
39 > prompt<T>(prompt: IPromptWithDefaultCancel<T>): Promise<IPromptResult<T>>;
40 > prompt<T>(prompt: IPrompt<T>): Promise<IPromptResult<T>>;
41 > async prompt<T>(prompt: IPrompt<T> | IPromptWithCustomCancel<T>): Promise<IPromptResult<T> | IPromptResultWithCancel<T>> {
42 if (this.defaultPromptResult) {
43 return this.defaultPromptResult as IPromptResult<T>;
50 return { result: await promptButtons[0]?.run({ checkboxChecked: false }) };
51 }
52 > async info(message: string, detail?: string): Promise<void> { testDialogService.ts
53 await this.prompt({ type: Severity.Info, message, detail });
54 }
56 > async warn(message: string, detail?: string): Promise<void> {
57 await this.prompt({ type: Severity.Warning, message, detail });
58 }
60 > async error(message: string, detail?: string): Promise<void> {
61 await this.prompt({ type: Severity.Error, message, detail });
62 }
63 > async input(): Promise<IInputResult> { { return { confirmed: true, values: [] }; } } testDialogService.ts
64 > async about(): Promise<void> { }
65 > }
src/vs/base/common/observableInternal/set.ts 32 covered LOC · 13 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- severity.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 strings from './strings.js';
7 >
8 > enum Severity {
9 > Ignore = 0,
10 > Info = 1,
11 > Warning = 2,
12 > Error = 3
13 > }
14 >
15 > namespace Severity {
16 >
17 > const _error = 'error';
18 > const _warning = 'warning';
19 > const _warn = 'warn';
20 > const _info = 'info';
21 > const _ignore = 'ignore';
22 >
23 > /**
24 > * Parses 'error', 'warning', 'warn', 'info' in call casings
25 > * and falls back to ignore.
26 > */
27 > export function fromValue(value: string): Severity {
28 if (!value) {
29 return Severity.Ignore;
43 return Severity.Ignore;
44 }
46 > export function toString(severity: Severity): string {
47 switch (severity) {
48 case Severity.Error: return _error;
52 }
53 }
54 > } severity.ts
55 >
56 > export default Severity;
src/vs/editor/common/languages/supports/indentRules.ts 31 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- indentRules.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 { IndentationRule } from '../languageConfiguration.js';
7 >
8 > export const enum IndentConsts {
9 > INCREASE_MASK = 0b00000001,
10 > DECREASE_MASK = 0b00000010,
11 > INDENT_NEXTLINE_MASK = 0b00000100,
12 > UNINDENT_MASK = 0b00001000,
13 > }
14 >
15 function resetGlobalRegex(reg: RegExp) {
16 if (reg.global) {
20 return true;
21 }
23 > export class IndentRulesSupport {
24 >
25 > private readonly _indentationRules: IndentationRule;
26 >
27 > constructor(indentationRules: IndentationRule) {
28 this._indentationRules = indentationRules;
29 }
31 > public shouldIncrease(text: string): boolean {
32 if (this._indentationRules) {
33 if (this._indentationRules.increaseIndentPattern && resetGlobalRegex(this._indentationRules.increaseIndentPattern) && this._indentationRules.increaseIndentPattern.test(text)) {
40 return false;
41 }
43 > public shouldDecrease(text: string): boolean {
44 if (this._indentationRules && this._indentationRules.decreaseIndentPattern && resetGlobalRegex(this._indentationRules.decreaseIndentPattern) && this._indentationRules.decreaseIndentPattern.test(text)) {
45 return true;
47 return false;
48 }
50 > public shouldIndentNextLine(text: string): boolean {
51 if (this._indentationRules && this._indentationRules.indentNextLinePattern && resetGlobalRegex(this._indentationRules.indentNextLinePattern) && this._indentationRules.indentNextLinePattern.test(text)) {
52 return true;
55 return false;
56 }
58 > public shouldIgnore(text: string): boolean {
59 // the text matches `unIndentedLinePattern`
60 if (this._indentationRules && this._indentationRules.unIndentedLinePattern && resetGlobalRegex(this._indentationRules.unIndentedLinePattern) && this._indentationRules.unIndentedLinePattern.test(text)) {
64 return false;
65 }
67 > public getIndentMetadata(text: string): number {
68 let ret = 0;
69 if (this.shouldIncrease(text)) {
src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/nodeReader.ts 31 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- nodeReader.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 { AstNode } from './ast.js';
7 > import { lengthAdd, lengthZero, Length, lengthLessThan } from './length.js';
8 >
9 > /**
10 > * Allows to efficiently find a longest child at a given offset in a fixed node.
11 > * The requested offsets must increase monotonously.
12 > */
13 > export class NodeReader {
14 > private readonly nextNodes: AstNode[];
15 > private readonly offsets: Length[];
16 > private readonly idxs: number[];
17 > private lastOffset: Length = lengthZero;
18 >
19 > constructor(node: AstNode) {
20 this.nextNodes = [node];
21 this.offsets = [lengthZero];
22 this.idxs = [];
23 }
25 > /**
26 > * Returns the longest node at `offset` that satisfies the predicate.
27 > * @param offset must be greater than or equal to the last offset this method has been called with!
28 > */
29 > readLongestNodeAt(offset: Length, predicate: (node: AstNode) => boolean): AstNode | undefined {
30 if (lengthLessThan(offset, this.lastOffset)) {
31 throw new Error('Invalid offset');
88 }
89 }
91 > // Navigates to the longest node that continues after the current node.
92 > private nextNodeAfterCurrent(): void {
93 while (true) {
94 const currentOffset = lastOrUndefined(this.offsets);
118 }
119 }
120 > } nodeReader.ts
121 >
122 function getNextChildIdx(node: AstNode, curIdx: number = -1): number | -1 {
123 while (true) {
131 }
132 }
134 function lastOrUndefined<T>(arr: readonly T[]): T | undefined {
135 return arr.length > 0 ? arr[arr.length - 1] : undefined;
src/vs/base/common/errorMessage.ts 29 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- errorMessage.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as arrays from './arrays.js';
7 > import * as types from './types.js';
8 > import * as nls from '../../nls.js';
9 > import { IAction } from './actions.js';
10 >
11 function exceptionToErrorMessage(exception: any, verbose: boolean): string {
12 if (verbose && (exception.stack || exception.stacktrace)) {
16 return detectSystemErrorMessage(exception);
17 }
19 function stackToString(stack: string[] | string | undefined): string | undefined {
20 if (Array.isArray(stack)) {
24 return stack;
25 }
27 function detectSystemErrorMessage(exception: any): string {
28
39 return exception.message || nls.localize('error.defaultMessage', "An unknown error occurred. Please consult the log for more details.");
40 }
42 > /**
43 > * Tries to generate a human readable error message out of the error. If the verbose parameter
44 > * is set to true, the error message will include stacktrace details if provided.
45 > *
46 > * @returns A string containing the error message.
47 > */
48 > export function toErrorMessage(error: any = null, verbose: boolean = false): string {
49 if (!error) {
50 return nls.localize('error.defaultMessage', "An unknown error occurred. Please consult the log for more details.");
88 return nls.localize('error.defaultMessage', "An unknown error occurred. Please consult the log for more details.");
89 }
91 >
92 > export interface IErrorWithActions extends Error {
93 > actions: IAction[];
94 > }
95 >
96 > export function isErrorWithActions(obj: unknown): obj is IErrorWithActions {
97 const candidate = obj as IErrorWithActions | undefined;
98
99 return candidate instanceof Error && Array.isArray(candidate.actions);
100 }
102 > export function createErrorWithActions(messageOrError: string | Error, actions: IAction[]): IErrorWithActions {
103 let error: IErrorWithActions;
104 if (typeof messageOrError === 'string') {
src/vs/editor/common/languages/supports/electricCharacter.ts 29 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- electricCharacter.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 { distinct } from '../../../../base/common/arrays.js';
7 > import { ScopedLineTokens, ignoreBracketsInToken } from '../supports.js';
8 > import { BracketsUtils, RichEditBrackets } from './richEditBrackets.js';
9 >
10 > /**
11 > * Interface used to support electric characters
12 > * @internal
13 > */
14 > export interface IElectricAction {
15 > // The line will be indented at the same level of the line
16 > // which contains the matching given bracket type.
17 > matchOpenBracket: string;
18 > }
19 >
20 > export class BracketElectricCharacterSupport {
21 >
22 > private readonly _richEditBrackets: RichEditBrackets | null;
23 >
24 > constructor(richEditBrackets: RichEditBrackets | null) {
25 this._richEditBrackets = richEditBrackets;
26 }
28 > public getElectricCharacters(): string[] {
29 const result: string[] = [];
30
40 return distinct(result);
41 }
43 > public onElectricCharacter(character: string, context: ScopedLineTokens, column: number): IElectricAction | null {
44 if (!this._richEditBrackets || this._richEditBrackets.brackets.length === 0) {
45 return null;
src/vs/editor/common/model/indentationGuesser.ts 29 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- indentationGuesser.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 { ITextBuffer } from '../model.js';
8 >
9 class SpacesDiffResult {
10 public spacesDiff: number = 0;
11 public looksLikeAlignment: boolean = false;
13 >
14 > /**
15 > * Compute the diff in spaces between two line's indentation.
16 > */
17 function spacesDiff(a: string, aLength: number, b: string, bLength: number, result: SpacesDiffResult): void {
18
88 }
89 }
91 > /**
92 > * Result for a guessIndentation
93 > */
94 > export interface IGuessedIndentation {
95 > /**
96 > * If indentation is based on spaces (`insertSpaces` = true), then what is the number of spaces that make an indent?
97 > */
98 > tabSize: number;
99 > /**
100 > * Is indentation based on spaces?
101 > */
102 > insertSpaces: boolean;
103 > }
104 >
105 > export function guessIndentation(source: ITextBuffer, defaultTabSize: number, defaultInsertSpaces: boolean): IGuessedIndentation {
106 // Look at most at the first 10k lines
107 const linesCount = Math.min(source.getLineCount(), 10000);
src/vs/platform/theme/common/colors/searchColors.ts 29 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- searchColors.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 > // Import the effects we need
9 > import { registerColor, transparent } from '../colorUtils.js';
10 >
11 > // Import the colors we need
12 > import { foreground } from './baseColors.js';
13 > import { editorFindMatchHighlight, editorFindMatchHighlightBorder } from './editorColors.js';
14 >
15 >
16 > export const searchResultsInfoForeground = registerColor('search.resultsInfoForeground',
17 > { light: foreground, dark: transparent(foreground, 0.65), hcDark: foreground, hcLight: foreground },
18 > nls.localize('search.resultsInfoForeground', "Color of the text in the search viewlet's completion message."));
19 >
20 >
21 > // ----- search editor (Distinct from normal editor find match to allow for better differentiation)
22 >
23 > export const searchEditorFindMatch = registerColor('searchEditor.findMatchBackground',
24 > { light: transparent(editorFindMatchHighlight, 0.66), dark: transparent(editorFindMatchHighlight, 0.66), hcDark: editorFindMatchHighlight, hcLight: editorFindMatchHighlight },
25 > nls.localize('searchEditor.queryMatch', "Color of the Search Editor query matches."));
26 >
27 > export const searchEditorFindMatchBorder = registerColor('searchEditor.findMatchBorder',
28 > { light: transparent(editorFindMatchHighlightBorder, 0.66), dark: transparent(editorFindMatchHighlightBorder, 0.66), hcDark: editorFindMatchHighlightBorder, hcLight: editorFindMatchHighlightBorder },
29 > nls.localize('searchEditor.editorFindMatchBorder', "Border color of the Search Editor query matches."));
src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/concat23Trees.ts 28 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- concat23Trees.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 { AstNode, AstNodeKind, ListAstNode } from './ast.js';
7 >
8 > /**
9 > * Concatenates a list of (2,3) AstNode's into a single (2,3) AstNode.
10 > * This mutates the items of the input array!
11 > * If all items have the same height, this method has runtime O(items.length).
12 > * Otherwise, it has runtime O(items.length * max(log(items.length), items.max(i => i.height))).
13 > */
14 > export function concat23Trees(items: AstNode[]): AstNode | null {
15 if (items.length === 0) {
16 return null;
64 return result;
65 }
67 > export function concat23TreesOfSameHeight(items: AstNode[], createImmutableLists: boolean = false): AstNode | null {
68 if (items.length === 0) {
69 return null;
85 return ListAstNode.create23(items[0], items[1], length >= 3 ? items[2] : null, createImmutableLists);
86 }
88 function heightDiff(node1: AstNode, node2: AstNode): number {
89 return Math.abs(node1.listHeight - node2.listHeight);
90 }
92 function concat(node1: AstNode, node2: AstNode): AstNode {
93 if (node1.listHeight === node2.listHeight) {
101 }
102 }
104 > /**
105 > * Appends the given node to the end of this (2,3) tree.
106 > * Returns the new root.
107 > */
108 function append(list: ListAstNode, nodeToAppend: AstNode): AstNode {
109 list = list.toMutable();
150 }
151 }
153 > /**
154 > * Prepends the given node to the end of this (2,3) tree.
155 > * Returns the new root.
156 > */
157 function prepend(list: ListAstNode, nodeToAppend: AstNode): AstNode {
158 list = list.toMutable();
src/vs/editor/common/model/fixedArray.ts 27 covered LOC · 7 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- fixedArray.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 >
8 > /**
9 > * An array that avoids being sparse by always
10 > * filling up unused indices with a default value.
11 > */
12 > export class FixedArray<T> {
13 > private _store: T[] = [];
14 >
15 > constructor(
16 private readonly _default: T
17 ) { }
19 > public get(index: number): T {
20 if (index < this._store.length) {
21 return this._store[index];
23 return this._default;
24 }
26 > public set(index: number, value: T): void {
27 while (index >= this._store.length) {
28 this._store[this._store.length] = this._default;
30 this._store[index] = value;
31 }
33 > public replace(index: number, oldLength: number, newLength: number): void {
34 if (index >= this._store.length) {
35 return;
49 this._store = before.concat(insertArr, after);
50 }
52 > public delete(deleteIndex: number, deleteCount: number): void {
53 if (deleteCount === 0 || deleteIndex >= this._store.length) {
54 return;
56 this._store.splice(deleteIndex, deleteCount);
57 }
59 > public insert(insertIndex: number, insertCount: number): void {
60 if (insertCount === 0 || insertIndex >= this._store.length) {
61 return;
67 this._store = arrayInsert(this._store, insertIndex, arr);
68 }
69 > } fixedArray.ts
70 >
71 function arrayFill<T>(length: number, value: T): T[] {
72 const arr: T[] = [];
src/vs/base/common/observableInternal/experimental/utils.ts 26 covered LOC · 2 ranges

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- characterPair.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 { IAutoClosingPair, StandardAutoClosingPairConditional, LanguageConfiguration } from '../languageConfiguration.js';
7 >
8 > export class CharacterPairSupport {
9 >
10 > static readonly DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_QUOTES = ';:.,=}])> \n\t';
11 > static readonly DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_BRACKETS = '\'"`;:.,=}])> \n\t';
12 > static readonly DEFAULT_AUTOCLOSE_BEFORE_WHITESPACE = ' \n\t';
13 >
14 > private readonly _autoClosingPairs: StandardAutoClosingPairConditional[];
15 > private readonly _surroundingPairs: IAutoClosingPair[];
16 > private readonly _autoCloseBeforeForQuotes: string;
17 > private readonly _autoCloseBeforeForBrackets: string;
18 >
19 > constructor(config: LanguageConfiguration) {
20 if (config.autoClosingPairs) {
21 this._autoClosingPairs = config.autoClosingPairs.map(el => new StandardAutoClosingPairConditional(el));
37 this._surroundingPairs = config.surroundingPairs || this._autoClosingPairs;
38 }
40 > public getAutoClosingPairs(): StandardAutoClosingPairConditional[] {
41 return this._autoClosingPairs;
42 }
44 > public getAutoCloseBeforeSet(forQuotes: boolean): string {
45 return (forQuotes ? this._autoCloseBeforeForQuotes : this._autoCloseBeforeForBrackets);
46 }
48 > public getSurroundingPairs(): IAutoClosingPair[] {
49 return this._surroundingPairs;
50 }
src/vs/editor/common/tokens/contiguousMultilineTokensBuilder.ts 26 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- contiguousMultilineTokensBuilder.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 { readUInt32BE, writeUInt32BE } from '../../../base/common/buffer.js';
7 > import { ContiguousMultilineTokens } from './contiguousMultilineTokens.js';
8 >
9 > export class ContiguousMultilineTokensBuilder {
10 >
11 > public static deserialize(buff: Uint8Array): ContiguousMultilineTokens[] {
12 let offset = 0;
13 const count = readUInt32BE(buff, offset); offset += 4;
18 return result;
19 }
21 > private readonly _tokens: ContiguousMultilineTokens[];
22 >
23 > constructor() {
24 this._tokens = [];
25 }
27 > public add(lineNumber: number, lineTokens: Uint32Array): void {
28 if (this._tokens.length > 0) {
29 const last = this._tokens[this._tokens.length - 1];
36 this._tokens.push(new ContiguousMultilineTokens(lineNumber, [lineTokens]));
37 }
39 > public finalize(): ContiguousMultilineTokens[] {
40 return this._tokens;
41 }
43 > public serialize(): Uint8Array {
44 const size = this._serializeSize();
45 const result = new Uint8Array(size);
56 return result;
57 }
59 > private _serialize(destination: Uint8Array): void {
60 let offset = 0;
61 writeUInt32BE(destination, this._tokens.length, offset); offset += 4;
src/vs/editor/test/common/services/testTreeSitterLibraryService.ts 26 covered LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testTreeSitterLibraryService.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 { Parser, Language, Query } from '@vscode/tree-sitter-wasm';
7 > import { IReader } from '../../../../base/common/observable.js';
8 > import { ITreeSitterLibraryService } from '../../../../editor/common/services/treeSitter/treeSitterLibraryService.js';
9 >
10 > export class TestTreeSitterLibraryService implements ITreeSitterLibraryService {
11 > readonly _serviceBrand: undefined;
12 >
13 > getParserClass(): Promise<typeof Parser> {
14 throw new Error('not implemented in TestTreeSitterLibraryService');
15 }
17 > supportsLanguage(languageId: string, reader: IReader | undefined): boolean {
18 return false;
19 }
21 > getLanguage(languageId: string, ignoreSupportsCheck: boolean, reader: IReader | undefined): Language | undefined {
22 return undefined;
23 }
25 > async getLanguagePromise(languageId: string): Promise<Language | undefined> {
26 return undefined;
27 }
29 > getInjectionQueries(languageId: string, reader: IReader | undefined): Query | null | undefined {
30 return null;
31 }
33 > getHighlightingQueries(languageId: string, reader: IReader | undefined): Query | null | undefined {
34 return null;
35 }
37 > async createQuery(language: Language, querySource: string): Promise<Query> {
38 throw new Error('not implemented in TestTreeSitterLibraryService');
39 }
src/vs/platform/theme/common/theme.ts 26 covered LOC · 2 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- theme.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 > * Color scheme used by the OS and by color themes.
8 > */
9 > export enum ColorScheme {
10 > DARK = 'dark',
11 > LIGHT = 'light',
12 > HIGH_CONTRAST_DARK = 'hcDark',
13 > HIGH_CONTRAST_LIGHT = 'hcLight'
14 > }
15 >
16 > export enum ThemeTypeSelector {
17 > VS = 'vs',
18 > VS_DARK = 'vs-dark',
19 > HC_BLACK = 'hc-black',
20 > HC_LIGHT = 'hc-light'
21 > }
22 >
23 >
24 > export function isHighContrast(scheme: ColorScheme): boolean {
25 return scheme === ColorScheme.HIGH_CONTRAST_DARK || scheme === ColorScheme.HIGH_CONTRAST_LIGHT;
26 }
27 > theme.ts
28 > export function isDark(scheme: ColorScheme): boolean {
29 return scheme === ColorScheme.DARK || scheme === ColorScheme.HIGH_CONTRAST_DARK;
30 }
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/base/test/common/mock.ts 25 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mock.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 { SinonStub, stub } from 'sinon';
7 > import { DeepPartial } from '../../common/types.js';
8 >
9 > export interface Ctor<T> {
10 > new(): T;
11 > }
12 >
13 > export function mock<T>(): Ctor<T> {
14 // eslint-disable-next-line local/code-no-any-casts
15 return function () { } as any;
16 }
17 > mock.ts
18 > export type MockObject<T, ExceptProps = never> = { [K in keyof T]: K extends ExceptProps ? T[K] : SinonStub };
19 >
20 > // Creates an object object that returns sinon mocks for every property. Optionally
21 > // takes base properties.
22 > export const mockObject = <T extends object>() => <TP extends Partial<T> = {}>(properties?: TP): MockObject<T, keyof TP> => {
23 // eslint-disable-next-line local/code-no-any-casts
24 return new Proxy({ ...properties } as any, {
36 });
37 };
38 > mock.ts
39 > /**
40 > * Shortcut for type-safe partials in mocks. A shortcut for `obj as Partial<T> as T`.
41 > */
42 > export function upcastPartial<T>(partial: Partial<T>): T {
43 return partial as T;
44 }
45 > export function upcastDeepPartial<T>(partial: DeepPartial<T>): T { mock.ts
46 return partial as T;
47 }
src/vs/base/common/codiconsUtil.ts 24 covered LOC · 2 ranges

Open complete file

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

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- editorZoom.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 '../../../base/common/event.js';
7 >
8 > export interface IEditorZoom {
9 > readonly onDidChangeZoomLevel: Event<number>;
10 > getZoomLevel(): number;
11 > setZoomLevel(zoomLevel: number): void;
12 > }
13 >
14 > export const EditorZoom: IEditorZoom = new class implements IEditorZoom {
15 >
16 > private _zoomLevel: number = 0;
17 >
18 > private readonly _onDidChangeZoomLevel = new Emitter<number>();
19 > public readonly onDidChangeZoomLevel: Event<number> = this._onDidChangeZoomLevel.event;
20 >
21 > public getZoomLevel(): number {
22 return this._zoomLevel;
23 }
25 > public setZoomLevel(zoomLevel: number): void {
26 zoomLevel = Math.min(Math.max(-5, zoomLevel), 20);
27 if (this._zoomLevel === zoomLevel) {
32 this._onDidChangeZoomLevel.fire(this._zoomLevel);
33 }
34 > }; editorZoom.ts
src/vs/editor/common/tokens/contiguousTokensEditing.ts 23 covered LOC · 6 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- contiguousTokensEditing.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 { LineTokens } from './lineTokens.js';
7 >
8 > export const EMPTY_LINE_TOKENS = (new Uint32Array(0)).buffer;
9 >
10 > export class ContiguousTokensEditing {
11 >
12 > public static deleteBeginning(lineTokens: Uint32Array | ArrayBuffer | null, toChIndex: number): Uint32Array | ArrayBuffer | null {
13 if (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) {
14 return lineTokens;
16 return ContiguousTokensEditing.delete(lineTokens, 0, toChIndex);
17 }
19 > public static deleteEnding(lineTokens: Uint32Array | ArrayBuffer | null, fromChIndex: number): Uint32Array | ArrayBuffer | null {
20 if (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) {
21 return lineTokens;
26 return ContiguousTokensEditing.delete(lineTokens, fromChIndex, lineTextLength);
27 }
29 > public static delete(lineTokens: Uint32Array | ArrayBuffer | null, fromChIndex: number, toChIndex: number): Uint32Array | ArrayBuffer | null {
30 if (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS || fromChIndex === toChIndex) {
31 return lineTokens;
83 return tmp.buffer;
84 }
86 > public static append(lineTokens: Uint32Array | ArrayBuffer | null, _otherTokens: Uint32Array | ArrayBuffer | null): Uint32Array | ArrayBuffer | null {
87 if (_otherTokens === EMPTY_LINE_TOKENS) {
88 return lineTokens;
112 return result.buffer;
113 }
115 > public static insert(lineTokens: Uint32Array | ArrayBuffer | null, chIndex: number, textLength: number): Uint32Array | ArrayBuffer | null {
116 if (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) {
117 // nothing to do
134 return lineTokens;
135 }
137 >
138 > export function toUint32Array(arr: Uint32Array | ArrayBuffer): Uint32Array<ArrayBuffer> {
139 if (arr instanceof Uint32Array) {
140 return arr as Uint32Array<ArrayBuffer>;
src/vs/editor/test/common/modes/testLanguageConfigurationService.ts 23 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testLanguageConfigurationService.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 { Emitter } from '../../../../base/common/event.js';
6 > import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
7 > import { LanguageConfiguration } from '../../../common/languages/languageConfiguration.js';
8 > import { ILanguageConfigurationService, LanguageConfigurationRegistry, LanguageConfigurationServiceChangeEvent, ResolvedLanguageConfiguration } from '../../../common/languages/languageConfigurationRegistry.js';
9 >
10 > export class TestLanguageConfigurationService extends Disposable implements ILanguageConfigurationService {
11 > _serviceBrand: undefined;
12 >
13 > private readonly _registry = this._register(new LanguageConfigurationRegistry());
14 >
15 > private readonly _onDidChange = this._register(new Emitter<LanguageConfigurationServiceChangeEvent>());
16 > public readonly onDidChange = this._onDidChange.event;
17 >
18 > constructor() {
19 super();
20 this._register(this._registry.onDidChange((e) => this._onDidChange.fire(new LanguageConfigurationServiceChangeEvent(e.languageId))));
21 }
23 > register(languageId: string, configuration: LanguageConfiguration, priority?: number): IDisposable {
24 return this._registry.register(languageId, configuration, priority);
25 }
27 > getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration {
28 return this._registry.getLanguageConfiguration(languageId) ??
29 new ResolvedLanguageConfiguration('unknown', {});
30 }
src/vs/editor/common/model/textModelStringEdit.ts 22 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelStringEdit.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 { EditOperation } from '../core/editOperation.js';
7 > import { Range } from '../core/range.js';
8 > import { StringEdit, StringReplacement } from '../core/edits/stringEdit.js';
9 > import { OffsetRange } from '../core/ranges/offsetRange.js';
10 > import { DetailedLineRangeMapping } from '../diff/rangeMapping.js';
11 > import { ITextModel, IIdentifiedSingleEditOperation } from '../model.js';
12 > import { IModelContentChange } from './mirrorTextModel.js';
13 > import { LengthEdit } from '../core/edits/lengthEdit.js';
14 > import { countEOL } from '../core/misc/eolCounter.js';
15 >
16 > export function offsetEditToEditOperations(offsetEdit: StringEdit, doc: ITextModel): IIdentifiedSingleEditOperation[] {
17 const edits: IIdentifiedSingleEditOperation[] = [];
18 for (const singleEdit of offsetEdit.replacements) {
25 return edits;
26 }
28 > export function offsetEditFromContentChanges(contentChanges: readonly IModelContentChange[]) {
29 const editsArr = contentChanges.map(c => new StringReplacement(OffsetRange.ofStartAndLength(c.rangeOffset, c.rangeLength), c.text));
30 editsArr.reverse();
32 return edits;
33 }
35 > export function offsetEditFromLineRangeMapping(original: ITextModel, modified: ITextModel, changes: readonly DetailedLineRangeMapping[]): StringEdit {
36 const edits: StringReplacement[] = [];
37 for (const c of changes) {
49 return new StringEdit(edits);
50 }
52 > export function linesLengthEditFromModelContentChange(c: IModelContentChange[]): LengthEdit {
53 const contentChanges = c.slice().reverse();
54 const lengthEdits = contentChanges.map(c => LengthEdit.replace(
src/vs/editor/common/services/languageFeaturesService.ts 22 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageFeaturesService.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 '../../../base/common/uri.js';
7 > import { LanguageFeatureRegistry, NotebookInfo, NotebookInfoResolver } from '../languageFeatureRegistry.js';
8 > import { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DocumentPasteEditProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, MultiDocumentHighlightProvider, DocumentHighlightProvider, DocumentDropEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, EvaluatableExpressionProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, InlineValuesProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider, NewSymbolNamesProvider } from '../languages.js';
9 > import { ILanguageFeaturesService } from './languageFeatures.js';
10 > import { InstantiationType, registerSingleton } from '../../../platform/instantiation/common/extensions.js';
11 >
12 > export class LanguageFeaturesService implements ILanguageFeaturesService {
13
14 declare _serviceBrand: undefined;
45 readonly documentDropEditProvider = new LanguageFeatureRegistry<DocumentDropEditProvider>(this._score.bind(this));
46 readonly documentPasteEditProvider = new LanguageFeatureRegistry<DocumentPasteEditProvider>(this._score.bind(this));
48 > private _notebookTypeResolver?: NotebookInfoResolver;
49 >
50 > setNotebookTypeResolver(resolver: NotebookInfoResolver | undefined) {
51 this._notebookTypeResolver = resolver;
52 }
54 > private _score(uri: URI): NotebookInfo | undefined {
55 return this._notebookTypeResolver?.(uri);
56 }
58 > }
59 >
60 > registerSingleton(ILanguageFeaturesService, LanguageFeaturesService, InstantiationType.Delayed);
src/vs/platform/instantiation/common/descriptors.ts 21 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- descriptors.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 class SyncDescriptor<T> {
7 >
8 > readonly ctor: any;
9 > readonly staticArguments: unknown[];
10 > readonly supportsDelayedInstantiation: boolean;
11 >
12 > constructor(ctor: new (...args: any[]) => T, staticArguments: unknown[] = [], supportsDelayedInstantiation: boolean = false) {
13 > this.ctor = ctor; descriptors.ts
14 > this.staticArguments = staticArguments;
15 > this.supportsDelayedInstantiation = supportsDelayedInstantiation;
16 > }
18 >
19 > export interface SyncDescriptor0<T> {
20 > readonly ctor: new () => T;
21 > }
src/vs/platform/instantiation/common/serviceCollection.ts 20 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- serviceCollection.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 { ServiceIdentifier } from './instantiation.js';
7 > import { SyncDescriptor } from './descriptors.js';
8 >
9 > export class ServiceCollection {
10 >
11 > private _entries = new Map<ServiceIdentifier<any>, any>();
12 >
13 > constructor(...entries: [ServiceIdentifier<any>, any][]) {
14 for (const [id, service] of entries) {
15 this.set(id, service);
16 }
17 }
19 > set<T>(id: ServiceIdentifier<T>, instanceOrDescriptor: T | SyncDescriptor<T>): T | SyncDescriptor<T> {
20 const result = this._entries.get(id);
21 this._entries.set(id, instanceOrDescriptor);
22 return result;
23 }
25 > has(id: ServiceIdentifier<any>): boolean {
26 return this._entries.has(id);
27 }
29 > get<T>(id: ServiceIdentifier<T>): T | SyncDescriptor<T> {
30 return this._entries.get(id);
31 }
src/vs/base/common/observableInternal/utils/valueWithChangeEvent.ts 19 covered LOC · 4 ranges

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- combineTextEditInfos.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 { ArrayQueue } from '../../../../../base/common/arrays.js';
7 > import { TextEditInfo } from './beforeEditPositionMapper.js';
8 > import { Length, lengthAdd, lengthDiffNonNegative, lengthEquals, lengthIsZero, lengthToObj, lengthZero, sumLengths } from './length.js';
9 >
10 > export function combineTextEditInfos(textEditInfoFirst: TextEditInfo[], textEditInfoSecond: TextEditInfo[]): TextEditInfo[] {
11 if (textEditInfoFirst.length === 0) {
12 return textEditInfoSecond;
82 return result;
83 }
85 > class LengthMapping {
86 > constructor(
87 /**
88 * If false, length before and length after equal.
93 ) {
94 }
96 > splitAt(lengthAfter: Length): [LengthMapping, LengthMapping | undefined] {
97 const remainingLengthAfter = lengthDiffNonNegative(lengthAfter, this.lengthAfter);
98 if (lengthEquals(remainingLengthAfter, lengthZero)) {
110 }
111 }
113 > toString(): string {
114 return `${this.modified ? 'M' : 'U'}:${lengthToObj(this.lengthBefore)} -> ${lengthToObj(this.lengthAfter)}`;
115 }
117 >
118 function toLengthMapping(textEditInfos: TextEditInfo[]): LengthMapping[] {
119 const result: LengthMapping[] = [];
src/vs/editor/test/common/services/testTextResourcePropertiesService.ts 18 covered LOC · 3 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- testTextResourcePropertiesService.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 platform from '../../../../base/common/platform.js';
7 > import { URI } from '../../../../base/common/uri.js';
8 > import { ITextResourcePropertiesService } from '../../../common/services/textResourceConfiguration.js';
9 > import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
10 >
11 > export class TestTextResourcePropertiesService implements ITextResourcePropertiesService {
12 >
13 > declare readonly _serviceBrand: undefined;
14 >
15 > constructor(
16 @IConfigurationService private readonly configurationService: IConfigurationService,
17 ) {
18 }
20 > getEOL(resource: URI, language?: string): string {
21 const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource });
22 if (eol && typeof eol === 'string' && eol !== 'auto') {
src/vs/platform/theme/common/colorRegistry.ts 18 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- colorRegistry.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 * from './colorUtils.js';
7 >
8 > // Make sure all color files are exported
9 > export * from './colors/baseColors.js';
10 > export * from './colors/chartsColors.js';
11 > export * from './colors/editorColors.js';
12 > export * from './colors/inputColors.js';
13 > export * from './colors/listColors.js';
14 > export * from './colors/menuColors.js';
15 > export * from './colors/minimapColors.js';
16 > export * from './colors/miscColors.js';
17 > export * from './colors/quickpickColors.js';
18 > export * from './colors/searchColors.js';
src/vs/base/common/observableInternal/logging/debugger/debuggerRpc.ts 17 covered LOC · 2 ranges

Open complete file

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

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelDefaults.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 EDITOR_MODEL_DEFAULTS = {
7 > tabSize: 4,
8 > indentSize: 4,
9 > insertSpaces: true,
10 > detectIndentation: true,
11 > trimAutoWhitespace: true,
12 > largeFileOptimizations: true,
13 > bracketPairColorizationOptions: {
14 > enabled: true,
15 > independentColorPoolPerBracketType: false,
16 > },
17 > };
src/vs/editor/common/languages/nullTokenize.ts 16 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- nullTokenize.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 { Token, TokenizationResult, EncodedTokenizationResult, IState } from '../languages.js';
7 > import { LanguageId, FontStyle, ColorId, StandardTokenType, MetadataConsts } from '../encodedTokenAttributes.js';
8 >
9 > export const NullState: IState = new class implements IState {
10 > public clone(): IState {
11 return this;
12 }
13 > public equals(other: IState): boolean { nullTokenize.ts
14 return (this === other);
15 }
16 > }; nullTokenize.ts
17 >
18 > export function nullTokenize(languageId: string, state: IState): TokenizationResult {
19 return new TokenizationResult([new Token(0, '', languageId)], state);
20 }
22 > export function nullTokenizeEncoded(languageId: LanguageId, state: IState | null): EncodedTokenizationResult {
23 const tokens = new Uint32Array(2);
24 tokens[0] = 0;
src/vs/editor/common/services/treeSitter/treeSitterThemeService.ts 16 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- treeSitterThemeService.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 { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
7 > import { IObservable, IReader } from '../../../../base/common/observable.js';
8 >
9 > export const ITreeSitterThemeService = createDecorator<ITreeSitterThemeService>('treeSitterThemeService');
10 >
11 > export interface ITreeSitterThemeService {
12 > readonly _serviceBrand: undefined;
13 > readonly onChange: IObservable<void>;
14 >
15 > findMetadata(captureNames: string[], languageId: number, bracket: boolean, reader: IReader | undefined): number;
16 > }
src/vs/editor/common/core/misc/eolCounter.ts 15 covered LOC · 1 range

Open complete file

1 > /*--------------------------------------------------------------------------------------------- eolCounter.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 >
8 > export const enum StringEOL {
9 > Unknown = 0,
10 > Invalid = 3,
11 > LF = 1,
12 > CRLF = 2
13 > }
14 >
15 > export function countEOL(text: string): [number, number, number, StringEOL] {
16 let eolCount = 0;
17 let firstLineLength = 0;
src/vs/editor/common/model/tokens/treeSitter/cursorUtils.ts 15 covered LOC · 5 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- cursorUtils.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 type * as TreeSitter from '@vscode/tree-sitter-wasm';
6 >
7 > export function gotoNextSibling(newCursor: TreeSitter.TreeCursor, oldCursor: TreeSitter.TreeCursor) {
8 const n = newCursor.gotoNextSibling();
9 const o = oldCursor.gotoNextSibling();
13 return n && o;
14 }
16 > export function gotoParent(newCursor: TreeSitter.TreeCursor, oldCursor: TreeSitter.TreeCursor) {
17 const n = newCursor.gotoParent();
18 const o = oldCursor.gotoParent();
22 return n && o;
23 }
25 > export function gotoNthChild(newCursor: TreeSitter.TreeCursor, oldCursor: TreeSitter.TreeCursor, index: number) {
26 const n = newCursor.gotoFirstChild();
27 const o = oldCursor.gotoFirstChild();
44 return n && o;
45 }
47 > export function nextSiblingOrParentSibling(newCursor: TreeSitter.TreeCursor, oldCursor: TreeSitter.TreeCursor) {
48 do {
49 if (newCursor.currentNode.nextSibling) {
56 return false;
57 }
59 > export function getClosestPreviousNodes(cursor: TreeSitter.TreeCursor, tree: TreeSitter.Tree): TreeSitter.Node | undefined {
60 // Go up parents until the end of the parent is before the start of the current.
61 const findPrev = tree.walk();
src/vs/base/common/observableInternal/observables/observableValueOpts.ts 13 covered LOC · 1 range

Open complete file

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

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 >
8 > /**
9 > * Returns:
10 > * - -1 => the line consists of whitespace
11 > * - otherwise => the indent level is returned value
12 > */
13 > export function computeIndentLevel(line: string, tabSize: number): number {
14 let indent = 0;
15 let i = 0;
src/vs/editor/common/model/textModelPart.ts 12 covered LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- textModelPart.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 { Disposable } from '../../../base/common/lifecycle.js';
7 >
8 > export class TextModelPart extends Disposable {
9 private _isDisposed = false;
11 > public override dispose(): void {
12 super.dispose();
13 this._isDisposed = true;
14 }
15 > protected assertNotDisposed(): void { textModelPart.ts
16 if (this._isDisposed) {
17 throw new Error('TextModelPart is disposed!');
18 }
19 }
src/vs/base/common/observableInternal/commonFacade/deps.ts 10 covered LOC · 1 range

Open complete file

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

Open complete file

1 > /*--------------------------------------------------------------------------------------------- indentation.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 strings from '../../../../base/common/strings.js';
7 > import { CursorColumns } from '../cursorColumns.js';
8 >
9 function _normalizeIndentationFromWhitespace(str: string, indentSize: number, insertSpaces: boolean): string {
10 let spacesCnt = 0;
32 return result;
33 }
35 > export function normalizeIndentation(str: string, indentSize: number, insertSpaces: boolean): string {
36 let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(str);
37 if (firstNonWhitespaceIndex === -1) {
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');
src/vs/base/common/observable.ts 8 covered LOC · 1 range

Open complete file

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

Open complete file

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